1 /*
2 * Copyright (C) 2011 Citrix Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published
6 * by the Free Software Foundation; version 2.1 only. with the special
7 * exception on linking described in file LICENSE.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 */
14
15 #include "libxl_osdeps.h" /* must come before any other headers */
16
17 #include <math.h>
18
19 #include <yajl/yajl_parse.h>
20 #include <yajl/yajl_gen.h>
21
22 #include "libxl_internal.h"
23
24 /* #define DEBUG_ANSWER */
25
26 typedef struct libxl__yajl_ctx {
27 libxl__gc *gc;
28 yajl_handle hand;
29 libxl__json_object *head;
30 libxl__json_object *current;
31 #ifdef DEBUG_ANSWER
32 yajl_gen g;
33 #endif
34 } libxl__yajl_ctx;
35
36 #ifdef DEBUG_ANSWER
37 #if YAJL_VERSION < 20000
38 # define DEBUG_GEN_ALLOC(ctx) \
39 if ((ctx)->g == NULL) { \
40 yajl_gen_config conf = { 1, " " }; \
41 (ctx)->g = yajl_gen_alloc(&conf, NULL); \
42 }
43 #else /* YAJL2 */
44 # define DEBUG_GEN_ALLOC(ctx) \
45 if ((ctx)->g == NULL) { \
46 (ctx)->g = yajl_gen_alloc(NULL); \
47 yajl_gen_config((ctx)->g, yajl_gen_beautify, 1); \
48 yajl_gen_config((ctx)->g, yajl_gen_indent_string, " "); \
49 }
50 #endif
51 # define DEBUG_GEN_FREE(ctx) \
52 if ((ctx)->g) yajl_gen_free((ctx)->g)
53 # define DEBUG_GEN(ctx, type) yajl_gen_##type(ctx->g)
54 # define DEBUG_GEN_VALUE(ctx, type, value) yajl_gen_##type(ctx->g, value)
55 # define DEBUG_GEN_STRING(ctx, str, n) yajl_gen_string(ctx->g, str, n)
56 # define DEBUG_GEN_NUMBER(ctx, str, n) yajl_gen_number(ctx->g, str, n)
57 # define DEBUG_GEN_REPORT(yajl_ctx) \
58 do { \
59 const unsigned char *buf = NULL; \
60 size_t len = 0; \
61 yajl_gen_get_buf((yajl_ctx)->g, &buf, &len); \
62 LIBXL__LOG(libxl__gc_owner((yajl_ctx)->gc), XTL_DEBUG, \
63 "response: %s\n", buf); \
64 yajl_gen_free((yajl_ctx)->g); \
65 (yajl_ctx)->g = NULL; \
66 } while (0)
67 #else
68 # define DEBUG_GEN_ALLOC(ctx) ((void)0)
69 # define DEBUG_GEN_FREE(ctx) ((void)0)
70 # define DEBUG_GEN(ctx, type) ((void)0)
71 # define DEBUG_GEN_VALUE(ctx, type, value) ((void)0)
72 # define DEBUG_GEN_STRING(ctx, value, length) ((void)0)
73 # define DEBUG_GEN_NUMBER(ctx, value, length) ((void)0)
74 # define DEBUG_GEN_REPORT(ctx) ((void)0)
75 #endif
76
77 /*
78 * YAJL Helper
79 */
80
libxl__yajl_gen_asciiz(yajl_gen hand,const char * str)81 yajl_gen_status libxl__yajl_gen_asciiz(yajl_gen hand, const char *str)
82 {
83 return yajl_gen_string(hand, (const unsigned char *)str, strlen(str));
84 }
85
libxl__yajl_gen_enum(yajl_gen hand,const char * str)86 yajl_gen_status libxl__yajl_gen_enum(yajl_gen hand, const char *str)
87 {
88 if (str)
89 return libxl__yajl_gen_asciiz(hand, str);
90 else
91 return yajl_gen_null(hand);
92 }
93
94 /*
95 * YAJL generators for builtin libxl types.
96 */
libxl_defbool_gen_json(yajl_gen hand,libxl_defbool * db)97 yajl_gen_status libxl_defbool_gen_json(yajl_gen hand,
98 libxl_defbool *db)
99 {
100 return libxl__yajl_gen_asciiz(hand, libxl_defbool_to_string(*db));
101 }
102
libxl__defbool_parse_json(libxl__gc * gc,const libxl__json_object * o,libxl_defbool * p)103 int libxl__defbool_parse_json(libxl__gc *gc, const libxl__json_object *o,
104 libxl_defbool *p)
105 {
106 const char *s;
107
108 if (!libxl__json_object_is_string(o))
109 return ERROR_FAIL;
110
111 s = libxl__json_object_get_string(o);
112
113 if (!strncmp(s, LIBXL__DEFBOOL_STR_DEFAULT,
114 strlen(LIBXL__DEFBOOL_STR_DEFAULT)))
115 p->val = LIBXL__DEFBOOL_DEFAULT;
116 else if (!strncmp(s, LIBXL__DEFBOOL_STR_TRUE,
117 strlen(LIBXL__DEFBOOL_STR_TRUE)))
118 p->val = LIBXL__DEFBOOL_TRUE;
119 else if (!strncmp(s, LIBXL__DEFBOOL_STR_FALSE,
120 strlen(LIBXL__DEFBOOL_STR_FALSE)))
121 p->val = LIBXL__DEFBOOL_FALSE;
122 else
123 return ERROR_FAIL;
124
125 return 0;
126 }
127
libxl__bool_parse_json(libxl__gc * gc,const libxl__json_object * o,bool * p)128 int libxl__bool_parse_json(libxl__gc *gc, const libxl__json_object *o,
129 bool *p)
130 {
131 if (!libxl__json_object_is_bool(o))
132 return ERROR_FAIL;
133
134 *p = libxl__json_object_get_bool(o);
135
136 return 0;
137 }
138
libxl_uuid_gen_json(yajl_gen hand,libxl_uuid * uuid)139 yajl_gen_status libxl_uuid_gen_json(yajl_gen hand,
140 libxl_uuid *uuid)
141 {
142 char buf[LIBXL_UUID_FMTLEN+1];
143 snprintf(buf, sizeof(buf), LIBXL_UUID_FMT, LIBXL_UUID_BYTES((*uuid)));
144 return yajl_gen_string(hand, (const unsigned char *)buf, LIBXL_UUID_FMTLEN);
145 }
146
libxl__uuid_parse_json(libxl__gc * gc,const libxl__json_object * o,libxl_uuid * p)147 int libxl__uuid_parse_json(libxl__gc *gc, const libxl__json_object *o,
148 libxl_uuid *p)
149 {
150 if (!libxl__json_object_is_string(o))
151 return ERROR_FAIL;
152
153 return libxl_uuid_from_string(p, o->u.string);
154 }
155
libxl_bitmap_gen_json(yajl_gen hand,libxl_bitmap * bitmap)156 yajl_gen_status libxl_bitmap_gen_json(yajl_gen hand,
157 libxl_bitmap *bitmap)
158 {
159 yajl_gen_status s;
160 int i;
161
162 s = yajl_gen_array_open(hand);
163 if (s != yajl_gen_status_ok) goto out;
164
165 libxl_for_each_bit(i, *bitmap) {
166 if (libxl_bitmap_test(bitmap, i)) {
167 s = yajl_gen_integer(hand, i);
168 if (s != yajl_gen_status_ok) goto out;
169 }
170 }
171 s = yajl_gen_array_close(hand);
172 out:
173 return s;
174 }
175
libxl__bitmap_parse_json(libxl__gc * gc,const libxl__json_object * o,libxl_bitmap * p)176 int libxl__bitmap_parse_json(libxl__gc *gc, const libxl__json_object *o,
177 libxl_bitmap *p)
178 {
179 int i;
180 int size;
181 const libxl__json_object *t;
182 flexarray_t *array;
183
184 if (!libxl__json_object_is_array(o))
185 return ERROR_FAIL;
186
187 array = libxl__json_object_get_array(o);
188 if (!array->count) {
189 libxl_bitmap_init(p);
190 return 0;
191 }
192
193 t = libxl__json_array_get(o, array->count - 1);
194 if (!libxl__json_object_is_integer(t))
195 return ERROR_FAIL;
196 size = libxl__json_object_get_integer(t) + 1;
197
198 libxl_bitmap_alloc(CTX, p, size);
199
200 for (i = 0; (t = libxl__json_array_get(o, i)); i++) {
201 if (!libxl__json_object_is_integer(t))
202 return ERROR_FAIL;
203
204 libxl_bitmap_set(p, libxl__json_object_get_integer(t));
205 }
206
207 return 0;
208 }
209
libxl_key_value_list_gen_json(yajl_gen hand,libxl_key_value_list * pkvl)210 yajl_gen_status libxl_key_value_list_gen_json(yajl_gen hand,
211 libxl_key_value_list *pkvl)
212 {
213 libxl_key_value_list kvl = *pkvl;
214 yajl_gen_status s;
215 int i;
216
217 s = yajl_gen_map_open(hand);
218 if (s != yajl_gen_status_ok) goto out;
219
220 if (!kvl) goto empty;
221
222 for (i = 0; kvl[i] != NULL; i += 2) {
223 s = libxl__yajl_gen_asciiz(hand, kvl[i]);
224 if (s != yajl_gen_status_ok) goto out;
225 if (kvl[i + 1])
226 s = libxl__yajl_gen_asciiz(hand, kvl[i+1]);
227 else
228 s = yajl_gen_null(hand);
229 if (s != yajl_gen_status_ok) goto out;
230 }
231 empty:
232 s = yajl_gen_map_close(hand);
233 out:
234 return s;
235 }
236
libxl__key_value_list_parse_json(libxl__gc * gc,const libxl__json_object * o,libxl_key_value_list * p)237 int libxl__key_value_list_parse_json(libxl__gc *gc, const libxl__json_object *o,
238 libxl_key_value_list *p)
239 {
240 libxl__json_map_node *node = NULL;
241 flexarray_t *maps = NULL;
242 int i, size;
243 libxl_key_value_list kvl;
244
245 if (!libxl__json_object_is_map(o))
246 return ERROR_FAIL;
247
248 maps = libxl__json_object_get_map(o);
249 size = maps->count * 2;
250 kvl = *p = libxl__calloc(NOGC, size+1, sizeof(char *));
251
252 for (i = 0; i < maps->count; i++) {
253 int idx = i * 2;
254 if (flexarray_get(maps, i, (void**)&node) != 0)
255 return ERROR_FAIL;
256
257 if (!libxl__json_object_is_string(node->obj) &&
258 !libxl__json_object_is_null(node->obj))
259 return ERROR_FAIL;
260
261 kvl[idx] = libxl__strdup(NOGC, node->map_key);
262 if (libxl__json_object_is_string(node->obj))
263 kvl[idx+1] =
264 libxl__strdup(NOGC, libxl__json_object_get_string(node->obj));
265 else
266 kvl[idx+1] = NULL;
267 }
268
269 return 0;
270 }
271
libxl_string_list_gen_json(yajl_gen hand,libxl_string_list * pl)272 yajl_gen_status libxl_string_list_gen_json(yajl_gen hand, libxl_string_list *pl)
273 {
274 libxl_string_list l = *pl;
275 yajl_gen_status s;
276 int i;
277
278 s = yajl_gen_array_open(hand);
279 if (s != yajl_gen_status_ok) goto out;
280
281 if (!l) goto empty;
282
283 for (i = 0; l[i] != NULL; i++) {
284 s = libxl__yajl_gen_asciiz(hand, l[i]);
285 if (s != yajl_gen_status_ok) goto out;
286 }
287 empty:
288 s = yajl_gen_array_close(hand);
289 out:
290 return s;
291 }
292
libxl__string_list_parse_json(libxl__gc * gc,const libxl__json_object * o,libxl_string_list * p)293 int libxl__string_list_parse_json(libxl__gc *gc, const libxl__json_object *o,
294 libxl_string_list *p)
295 {
296 const libxl__json_object *t;
297 libxl_string_list l;
298 flexarray_t *array = NULL;
299 int i, size;
300
301 if (!libxl__json_object_is_array(o))
302 return ERROR_FAIL;
303
304 array = libxl__json_object_get_array(o);
305 size = array->count;
306
307 if (size == 0) {
308 *p = NULL;
309 return 0;
310 }
311
312 /* need one extra slot as sentinel */
313 l = *p = libxl__calloc(NOGC, size + 1, sizeof(char *));
314
315 for (i = 0; (t = libxl__json_array_get(o, i)); i++) {
316 if (!libxl__json_object_is_string(t))
317 return ERROR_FAIL;
318
319 l[i] = libxl__strdup(NOGC, libxl__json_object_get_string(t));
320 }
321
322 return 0;
323 }
324
libxl_mac_gen_json(yajl_gen hand,libxl_mac * mac)325 yajl_gen_status libxl_mac_gen_json(yajl_gen hand, libxl_mac *mac)
326 {
327 char buf[LIBXL_MAC_FMTLEN+1];
328 snprintf(buf, sizeof(buf), LIBXL_MAC_FMT, LIBXL_MAC_BYTES((*mac)));
329 return yajl_gen_string(hand, (const unsigned char *)buf, LIBXL_MAC_FMTLEN);
330 }
331
libxl__mac_parse_json(libxl__gc * gc,const libxl__json_object * o,libxl_mac * p)332 int libxl__mac_parse_json(libxl__gc *gc, const libxl__json_object *o,
333 libxl_mac *p)
334 {
335 if (!libxl__json_object_is_string(o))
336 return ERROR_FAIL;
337
338 return libxl__parse_mac(libxl__json_object_get_string(o), *p);
339 }
340
libxl_hwcap_gen_json(yajl_gen hand,libxl_hwcap * p)341 yajl_gen_status libxl_hwcap_gen_json(yajl_gen hand,
342 libxl_hwcap *p)
343 {
344 yajl_gen_status s;
345 int i;
346
347 s = yajl_gen_array_open(hand);
348 if (s != yajl_gen_status_ok) goto out;
349
350 for(i=0; i<4; i++) {
351 s = yajl_gen_integer(hand, (*p)[i]);
352 if (s != yajl_gen_status_ok) goto out;
353 }
354 s = yajl_gen_array_close(hand);
355 out:
356 return s;
357 }
358
libxl__hwcap_parse_json(libxl__gc * gc,const libxl__json_object * o,libxl_hwcap * p)359 int libxl__hwcap_parse_json(libxl__gc *gc, const libxl__json_object *o,
360 libxl_hwcap *p)
361 {
362 int i;
363
364 if (!libxl__json_object_is_array(o))
365 return ERROR_FAIL;
366
367 for (i = 0; i<4; i++) {
368 const libxl__json_object *t;
369
370 t = libxl__json_array_get(o, i);
371 if (!t || !libxl__json_object_is_integer(t))
372 return ERROR_FAIL;
373
374 (*p)[i] = libxl__json_object_get_integer(t);
375 }
376
377 return 0;
378 }
379
libxl_ms_vm_genid_gen_json(yajl_gen hand,libxl_ms_vm_genid * p)380 yajl_gen_status libxl_ms_vm_genid_gen_json(yajl_gen hand, libxl_ms_vm_genid *p)
381 {
382 yajl_gen_status s;
383 int i;
384
385 s = yajl_gen_array_open(hand);
386 if (s != yajl_gen_status_ok)
387 return s;
388
389 for (i = 0; i < LIBXL_MS_VM_GENID_LEN; i++) {
390 s = yajl_gen_integer(hand, p->bytes[i]);
391 if (s != yajl_gen_status_ok)
392 return s;
393 }
394
395 return yajl_gen_array_close(hand);
396 }
397
libxl__ms_vm_genid_parse_json(libxl__gc * gc,const libxl__json_object * o,libxl_ms_vm_genid * p)398 int libxl__ms_vm_genid_parse_json(libxl__gc *gc, const libxl__json_object *o,
399 libxl_ms_vm_genid *p)
400 {
401 unsigned int i;
402
403 if (!libxl__json_object_is_array(o))
404 return ERROR_FAIL;
405
406 for (i = 0; i < LIBXL_MS_VM_GENID_LEN; i++) {
407 const libxl__json_object *t;
408
409 t = libxl__json_array_get(o, i);
410 if (!t || !libxl__json_object_is_integer(t))
411 return ERROR_FAIL;
412
413 p->bytes[i] = libxl__json_object_get_integer(t);
414 }
415
416 return 0;
417 }
418
libxl__string_gen_json(yajl_gen hand,const char * p)419 yajl_gen_status libxl__string_gen_json(yajl_gen hand,
420 const char *p)
421 {
422 if (p)
423 return libxl__yajl_gen_asciiz(hand, p);
424 else
425 return yajl_gen_null(hand);
426 }
427
libxl__string_parse_json(libxl__gc * gc,const libxl__json_object * o,char ** p)428 int libxl__string_parse_json(libxl__gc *gc, const libxl__json_object *o,
429 char **p)
430 {
431 if (!libxl__json_object_is_string(o) && !libxl__json_object_is_null(o))
432 return ERROR_FAIL;
433
434 if (libxl__json_object_is_null(o))
435 *p = NULL;
436 else
437 *p = libxl__strdup(NOGC, libxl__json_object_get_string(o));
438
439 return 0;
440 }
441
442 /*
443 * libxl__json_object helper functions
444 */
445
libxl__json_object_alloc(libxl__gc * gc,libxl__json_node_type type)446 libxl__json_object *libxl__json_object_alloc(libxl__gc *gc,
447 libxl__json_node_type type)
448 {
449 libxl__json_object *obj;
450
451 obj = libxl__zalloc(gc, sizeof(*obj));
452
453 obj->type = type;
454
455 if (type == JSON_MAP || type == JSON_ARRAY) {
456 flexarray_t *array = flexarray_make(gc, 1, 1);
457 if (type == JSON_MAP)
458 obj->u.map = array;
459 else
460 obj->u.array = array;
461 }
462
463 return obj;
464 }
465
libxl__json_object_append_to(libxl__gc * gc,libxl__json_object * obj,libxl__yajl_ctx * ctx)466 static int libxl__json_object_append_to(libxl__gc *gc,
467 libxl__json_object *obj,
468 libxl__yajl_ctx *ctx)
469 {
470 libxl__json_object *dst = ctx->current;
471
472 if (dst) {
473 switch (dst->type) {
474 case JSON_MAP: {
475 libxl__json_map_node *last;
476
477 if (dst->u.map->count == 0) {
478 LIBXL__LOG(libxl__gc_owner(gc), LIBXL__LOG_ERROR,
479 "Try to add a value to an empty map (with no key)");
480 return ERROR_FAIL;
481 }
482 flexarray_get(dst->u.map, dst->u.map->count - 1, (void**)&last);
483 last->obj = obj;
484 break;
485 }
486 case JSON_ARRAY:
487 flexarray_append(dst->u.array, obj);
488 break;
489 default:
490 LIBXL__LOG(libxl__gc_owner(gc), LIBXL__LOG_ERROR,
491 "Try append an object is not a map/array (%i)",
492 dst->type);
493 return ERROR_FAIL;
494 }
495 }
496
497 obj->parent = dst;
498
499 if (libxl__json_object_is_map(obj) || libxl__json_object_is_array(obj))
500 ctx->current = obj;
501 if (ctx->head == NULL)
502 ctx->head = obj;
503
504 return 0;
505 }
506
libxl__json_object_free(libxl__gc * gc,libxl__json_object * obj)507 void libxl__json_object_free(libxl__gc *gc, libxl__json_object *obj)
508 {
509 int idx = 0;
510
511 if (obj == NULL)
512 return;
513 switch (obj->type) {
514 case JSON_STRING:
515 case JSON_NUMBER:
516 free(obj->u.string);
517 break;
518 case JSON_MAP: {
519 libxl__json_map_node *node = NULL;
520
521 for (idx = 0; idx < obj->u.map->count; idx++) {
522 if (flexarray_get(obj->u.map, idx, (void**)&node) != 0)
523 break;
524 libxl__json_object_free(gc, node->obj);
525 free(node->map_key);
526 free(node);
527 node = NULL;
528 }
529 flexarray_free(obj->u.map);
530 break;
531 }
532 case JSON_ARRAY: {
533 libxl__json_object *node = NULL;
534
535 for (idx = 0; idx < obj->u.array->count; idx++) {
536 if (flexarray_get(obj->u.array, idx, (void**)&node) != 0)
537 break;
538 libxl__json_object_free(gc, node);
539 node = NULL;
540 }
541 flexarray_free(obj->u.array);
542 break;
543 }
544 default:
545 break;
546 }
547 free(obj);
548 }
549
libxl__json_array_get(const libxl__json_object * o,int i)550 libxl__json_object *libxl__json_array_get(const libxl__json_object *o, int i)
551 {
552 flexarray_t *array = NULL;
553 libxl__json_object *obj = NULL;
554
555 if ((array = libxl__json_object_get_array(o)) == NULL) {
556 return NULL;
557 }
558
559 if (i >= array->count)
560 return NULL;
561
562 if (flexarray_get(array, i, (void**)&obj) != 0)
563 return NULL;
564
565 return obj;
566 }
567
libxl__json_map_node_get(const libxl__json_object * o,int i)568 libxl__json_map_node *libxl__json_map_node_get(const libxl__json_object *o,
569 int i)
570 {
571 flexarray_t *array = NULL;
572 libxl__json_map_node *obj = NULL;
573
574 if ((array = libxl__json_object_get_map(o)) == NULL) {
575 return NULL;
576 }
577
578 if (i >= array->count)
579 return NULL;
580
581 if (flexarray_get(array, i, (void**)&obj) != 0)
582 return NULL;
583
584 return obj;
585 }
586
libxl__json_map_get(const char * key,const libxl__json_object * o,libxl__json_node_type expected_type)587 const libxl__json_object *libxl__json_map_get(const char *key,
588 const libxl__json_object *o,
589 libxl__json_node_type expected_type)
590 {
591 flexarray_t *maps = NULL;
592 int idx = 0;
593
594 if (libxl__json_object_is_map(o)) {
595 libxl__json_map_node *node = NULL;
596
597 maps = o->u.map;
598 for (idx = 0; idx < maps->count; idx++) {
599 if (flexarray_get(maps, idx, (void**)&node) != 0)
600 return NULL;
601 if (strcmp(key, node->map_key) == 0) {
602 if (expected_type == JSON_ANY
603 || (node->obj && (node->obj->type & expected_type))) {
604 return node->obj;
605 } else {
606 return NULL;
607 }
608 }
609 }
610 }
611 return NULL;
612 }
613
libxl__json_object_to_yajl_gen(libxl__gc * gc,yajl_gen hand,const libxl__json_object * obj)614 yajl_status libxl__json_object_to_yajl_gen(libxl__gc *gc,
615 yajl_gen hand,
616 const libxl__json_object *obj)
617 {
618 int idx = 0;
619 yajl_status rc;
620
621 #define CONVERT_YAJL_GEN_TO_STATUS(gen) \
622 ((gen) == yajl_gen_status_ok ? yajl_status_ok : yajl_status_error)
623
624 switch (obj->type) {
625 case JSON_NULL:
626 return CONVERT_YAJL_GEN_TO_STATUS(yajl_gen_null(hand));
627 case JSON_BOOL:
628 return CONVERT_YAJL_GEN_TO_STATUS(yajl_gen_bool(hand, obj->u.b));
629 case JSON_INTEGER:
630 return CONVERT_YAJL_GEN_TO_STATUS(yajl_gen_integer(hand, obj->u.i));
631 case JSON_DOUBLE:
632 return CONVERT_YAJL_GEN_TO_STATUS(yajl_gen_double(hand, obj->u.d));
633 case JSON_NUMBER:
634 return CONVERT_YAJL_GEN_TO_STATUS(
635 yajl_gen_number(hand, obj->u.string, strlen(obj->u.string)));
636 case JSON_STRING:
637 return CONVERT_YAJL_GEN_TO_STATUS(
638 libxl__yajl_gen_asciiz(hand, obj->u.string));
639 case JSON_MAP: {
640 libxl__json_map_node *node = NULL;
641
642 rc = CONVERT_YAJL_GEN_TO_STATUS(yajl_gen_map_open(hand));
643 if (rc != yajl_status_ok)
644 return rc;
645 for (idx = 0; idx < obj->u.map->count; idx++) {
646 if (flexarray_get(obj->u.map, idx, (void**)&node) != 0)
647 break;
648
649 rc = CONVERT_YAJL_GEN_TO_STATUS(
650 libxl__yajl_gen_asciiz(hand, node->map_key));
651 if (rc != yajl_status_ok)
652 return rc;
653 rc = libxl__json_object_to_yajl_gen(gc, hand, node->obj);
654 if (rc != yajl_status_ok)
655 return rc;
656 }
657 return CONVERT_YAJL_GEN_TO_STATUS(yajl_gen_map_close(hand));
658 }
659 case JSON_ARRAY: {
660 libxl__json_object *node = NULL;
661
662 rc = CONVERT_YAJL_GEN_TO_STATUS(yajl_gen_array_open(hand));
663 if (rc != yajl_status_ok)
664 return rc;
665 for (idx = 0; idx < obj->u.array->count; idx++) {
666 if (flexarray_get(obj->u.array, idx, (void**)&node) != 0)
667 break;
668 rc = libxl__json_object_to_yajl_gen(gc, hand, node);
669 if (rc != yajl_status_ok)
670 return rc;
671 }
672 return CONVERT_YAJL_GEN_TO_STATUS(yajl_gen_array_close(hand));
673 }
674 case JSON_ANY:
675 /* JSON_ANY is not a valid value for obj->type. */
676 ;
677 }
678 abort();
679 #undef CONVERT_YAJL_GEN_TO_STATUS
680 }
681
682
683 /*
684 * JSON callbacks
685 */
686
json_callback_null(void * opaque)687 static int json_callback_null(void *opaque)
688 {
689 libxl__yajl_ctx *ctx = opaque;
690 libxl__json_object *obj;
691
692 DEBUG_GEN(ctx, null);
693
694 obj = libxl__json_object_alloc(ctx->gc, JSON_NULL);
695
696 if (libxl__json_object_append_to(ctx->gc, obj, ctx))
697 return 0;
698
699 return 1;
700 }
701
json_callback_boolean(void * opaque,int boolean)702 static int json_callback_boolean(void *opaque, int boolean)
703 {
704 libxl__yajl_ctx *ctx = opaque;
705 libxl__json_object *obj;
706
707 DEBUG_GEN_VALUE(ctx, bool, boolean);
708
709 obj = libxl__json_object_alloc(ctx->gc, JSON_BOOL);
710 obj->u.b = boolean;
711
712 if (libxl__json_object_append_to(ctx->gc, obj, ctx))
713 return 0;
714
715 return 1;
716 }
717
is_decimal(const char * s,unsigned len)718 static bool is_decimal(const char *s, unsigned len)
719 {
720 const char *end = s + len;
721 for (; s < end; s++) {
722 if (*s == '.')
723 return true;
724 }
725 return false;
726 }
727
json_callback_number(void * opaque,const char * s,libxl_yajl_length len)728 static int json_callback_number(void *opaque, const char *s, libxl_yajl_length len)
729 {
730 libxl__yajl_ctx *ctx = opaque;
731 libxl__json_object *obj = NULL;
732 char *t = NULL;
733
734 DEBUG_GEN_NUMBER(ctx, s, len);
735
736 if (is_decimal(s, len)) {
737 double d = strtod(s, NULL);
738
739 if ((d == HUGE_VALF || d == HUGE_VALL) && errno == ERANGE) {
740 goto error;
741 }
742
743 obj = libxl__json_object_alloc(ctx->gc, JSON_DOUBLE);
744 obj->u.d = d;
745 } else {
746 long long i = strtoll(s, NULL, 10);
747
748 if ((i == LLONG_MIN || i == LLONG_MAX) && errno == ERANGE) {
749 goto error;
750 }
751
752 obj = libxl__json_object_alloc(ctx->gc, JSON_INTEGER);
753 obj->u.i = i;
754 }
755 goto out;
756
757 error:
758 /* If the conversion fail, we just store the original string. */
759 obj = libxl__json_object_alloc(ctx->gc, JSON_NUMBER);
760
761 t = libxl__zalloc(ctx->gc, len + 1);
762 strncpy(t, s, len);
763 t[len] = 0;
764
765 obj->u.string = t;
766
767 out:
768 if (libxl__json_object_append_to(ctx->gc, obj, ctx))
769 return 0;
770
771 return 1;
772 }
773
json_callback_string(void * opaque,const unsigned char * str,libxl_yajl_length len)774 static int json_callback_string(void *opaque, const unsigned char *str,
775 libxl_yajl_length len)
776 {
777 libxl__yajl_ctx *ctx = opaque;
778 char *t = NULL;
779 libxl__json_object *obj = NULL;
780
781 t = libxl__zalloc(ctx->gc, len + 1);
782
783 DEBUG_GEN_STRING(ctx, str, len);
784
785 strncpy(t, (const char *) str, len);
786 t[len] = 0;
787
788 obj = libxl__json_object_alloc(ctx->gc, JSON_STRING);
789 obj->u.string = t;
790
791 if (libxl__json_object_append_to(ctx->gc, obj, ctx))
792 return 0;
793
794 return 1;
795 }
796
json_callback_map_key(void * opaque,const unsigned char * str,libxl_yajl_length len)797 static int json_callback_map_key(void *opaque, const unsigned char *str,
798 libxl_yajl_length len)
799 {
800 libxl__yajl_ctx *ctx = opaque;
801 char *t = NULL;
802 libxl__json_object *obj = ctx->current;
803 libxl__gc *gc = ctx->gc;
804
805 t = libxl__zalloc(gc, len + 1);
806
807 DEBUG_GEN_STRING(ctx, str, len);
808
809 strncpy(t, (const char *) str, len);
810 t[len] = 0;
811
812 if (libxl__json_object_is_map(obj)) {
813 libxl__json_map_node *node;
814
815 GCNEW(node);
816 node->map_key = t;
817 node->obj = NULL;
818
819 flexarray_append(obj->u.map, node);
820 } else {
821 LIBXL__LOG(libxl__gc_owner(ctx->gc), LIBXL__LOG_ERROR,
822 "Current json object is not a map");
823 return 0;
824 }
825
826 return 1;
827 }
828
json_callback_start_map(void * opaque)829 static int json_callback_start_map(void *opaque)
830 {
831 libxl__yajl_ctx *ctx = opaque;
832 libxl__json_object *obj = NULL;
833
834 DEBUG_GEN(ctx, map_open);
835
836 obj = libxl__json_object_alloc(ctx->gc, JSON_MAP);
837
838 if (libxl__json_object_append_to(ctx->gc, obj, ctx))
839 return 0;
840
841 return 1;
842 }
843
json_callback_end_map(void * opaque)844 static int json_callback_end_map(void *opaque)
845 {
846 libxl__yajl_ctx *ctx = opaque;
847
848 DEBUG_GEN(ctx, map_close);
849
850 if (ctx->current) {
851 ctx->current = ctx->current->parent;
852 } else {
853 LIBXL__LOG(libxl__gc_owner(ctx->gc), LIBXL__LOG_ERROR,
854 "No current libxl__json_object, cannot use his parent.");
855 return 0;
856 }
857
858 return 1;
859 }
860
json_callback_start_array(void * opaque)861 static int json_callback_start_array(void *opaque)
862 {
863 libxl__yajl_ctx *ctx = opaque;
864 libxl__json_object *obj = NULL;
865
866 DEBUG_GEN(ctx, array_open);
867
868 obj = libxl__json_object_alloc(ctx->gc, JSON_ARRAY);
869
870 if (libxl__json_object_append_to(ctx->gc, obj, ctx))
871 return 0;
872
873 return 1;
874 }
875
json_callback_end_array(void * opaque)876 static int json_callback_end_array(void *opaque)
877 {
878 libxl__yajl_ctx *ctx = opaque;
879
880 DEBUG_GEN(ctx, array_close);
881
882 if (ctx->current) {
883 ctx->current = ctx->current->parent;
884 } else {
885 LIBXL__LOG(libxl__gc_owner(ctx->gc), LIBXL__LOG_ERROR,
886 "No current libxl__json_object, cannot use his parent.");
887 return 0;
888 }
889
890 return 1;
891 }
892
893 static yajl_callbacks callbacks = {
894 json_callback_null,
895 json_callback_boolean,
896 NULL,
897 NULL,
898 json_callback_number,
899 json_callback_string,
900 json_callback_start_map,
901 json_callback_map_key,
902 json_callback_end_map,
903 json_callback_start_array,
904 json_callback_end_array
905 };
906
yajl_ctx_free(libxl__yajl_ctx * yajl_ctx)907 static void yajl_ctx_free(libxl__yajl_ctx *yajl_ctx)
908 {
909 if (yajl_ctx->hand) {
910 yajl_free(yajl_ctx->hand);
911 yajl_ctx->hand = NULL;
912 }
913 DEBUG_GEN_FREE(yajl_ctx);
914 }
915
libxl__json_parse(libxl__gc * gc,const char * s)916 libxl__json_object *libxl__json_parse(libxl__gc *gc, const char *s)
917 {
918 yajl_status status;
919 libxl__yajl_ctx yajl_ctx;
920 libxl__json_object *o = NULL;
921 unsigned char *str = NULL;
922
923 memset(&yajl_ctx, 0, sizeof (yajl_ctx));
924 yajl_ctx.gc = gc;
925
926 DEBUG_GEN_ALLOC(&yajl_ctx);
927
928 if (yajl_ctx.hand == NULL) {
929 yajl_ctx.hand = libxl__yajl_alloc(&callbacks, NULL, &yajl_ctx);
930 }
931 status = yajl_parse(yajl_ctx.hand, (const unsigned char *)s, strlen(s));
932 if (status != yajl_status_ok)
933 goto out;
934
935 status = yajl_complete_parse(yajl_ctx.hand);
936 if (status != yajl_status_ok)
937 goto out;
938
939 o = yajl_ctx.head;
940
941 DEBUG_GEN_REPORT(&yajl_ctx);
942
943 yajl_ctx.head = NULL;
944
945 yajl_ctx_free(&yajl_ctx);
946 return o;
947
948 out:
949 str = yajl_get_error(yajl_ctx.hand, 1, (const unsigned char*)s, strlen(s));
950
951 LIBXL__LOG(libxl__gc_owner(gc), LIBXL__LOG_ERROR, "yajl error: %s", str);
952 yajl_free_error(yajl_ctx.hand, str);
953 yajl_ctx_free(&yajl_ctx);
954 return NULL;
955 }
956
yajl_gen_status_to_string(yajl_gen_status s)957 static const char *yajl_gen_status_to_string(yajl_gen_status s)
958 {
959 switch (s) {
960 case yajl_gen_status_ok: abort();
961 case yajl_gen_keys_must_be_strings:
962 return "keys must be strings";
963 case yajl_max_depth_exceeded:
964 return "max depth exceeded";
965 case yajl_gen_in_error_state:
966 return "in error state";
967 case yajl_gen_generation_complete:
968 return "generation complete";
969 case yajl_gen_invalid_number:
970 return "invalid number";
971 #if 0 /* This is in the docs but not implemented in the version I am running. */
972 case yajl_gen_no_buf:
973 return "no buffer";
974 case yajl_gen_invalid_string:
975 return "invalid string";
976 #endif
977 default:
978 return "unknown error";
979 }
980 }
981
libxl__object_to_json(libxl_ctx * ctx,const char * type,libxl__gen_json_callback gen,void * p)982 char *libxl__object_to_json(libxl_ctx *ctx, const char *type,
983 libxl__gen_json_callback gen, void *p)
984 {
985 const unsigned char *buf;
986 char *ret = NULL;
987 libxl_yajl_length len = 0;
988 yajl_gen_status s;
989 yajl_gen hand;
990
991 hand = libxl_yajl_gen_alloc(NULL);
992 if (!hand)
993 return NULL;
994
995 s = gen(hand, p);
996 if (s != yajl_gen_status_ok)
997 goto out;
998
999 s = yajl_gen_get_buf(hand, &buf, &len);
1000 if (s != yajl_gen_status_ok)
1001 goto out;
1002 ret = strdup((const char *)buf);
1003
1004 out:
1005 yajl_gen_free(hand);
1006
1007 if (s != yajl_gen_status_ok) {
1008 LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
1009 "unable to convert %s to JSON representation. "
1010 "YAJL error code %d: %s", type,
1011 s, yajl_gen_status_to_string(s));
1012 } else if (!ret) {
1013 LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
1014 "unable to allocate space for to JSON representation of %s",
1015 type);
1016 }
1017
1018 return ret;
1019 }
1020
libxl__json_object_to_json(libxl__gc * gc,const libxl__json_object * args)1021 char *libxl__json_object_to_json(libxl__gc *gc,
1022 const libxl__json_object *args)
1023 {
1024 const unsigned char *buf;
1025 libxl_yajl_length len;
1026 yajl_gen_status s;
1027 yajl_gen hand;
1028 char *ret = NULL;
1029 int rc;
1030
1031 if (!args)
1032 return NULL;
1033
1034 hand = libxl_yajl_gen_alloc(NULL);
1035 if (!hand)
1036 return NULL;
1037
1038 rc = libxl__json_object_to_yajl_gen(gc, hand, args);
1039 if (rc)
1040 goto out;
1041
1042 s = yajl_gen_get_buf(hand, &buf, &len);
1043 if (s)
1044 goto out;
1045
1046 ret = libxl__strndup(gc, (const char *)buf, len);
1047
1048 out:
1049 yajl_gen_free(hand);
1050 return ret;
1051 }
1052
libxl__uint64_gen_json(yajl_gen hand,uint64_t val)1053 yajl_gen_status libxl__uint64_gen_json(yajl_gen hand, uint64_t val)
1054 {
1055 char *num;
1056 int len;
1057 yajl_gen_status s;
1058
1059
1060 len = asprintf(&num, "%"PRIu64, val);
1061 if (len == -1) {
1062 s = yajl_gen_in_error_state;
1063 goto out;
1064 }
1065
1066 s = yajl_gen_number(hand, num, len);
1067
1068 free(num);
1069
1070 out:
1071 return s;
1072 }
1073
libxl__object_from_json(libxl_ctx * ctx,const char * type,libxl__json_parse_callback parse,void * p,const char * s)1074 int libxl__object_from_json(libxl_ctx *ctx, const char *type,
1075 libxl__json_parse_callback parse,
1076 void *p, const char *s)
1077 {
1078 GC_INIT(ctx);
1079 libxl__json_object *o;
1080 int rc;
1081
1082 o = libxl__json_parse(gc, s);
1083 if (!o) {
1084 LOG(ERROR,
1085 "unable to generate libxl__json_object from JSON representation of %s.",
1086 type);
1087 rc = ERROR_FAIL;
1088 goto out;
1089 }
1090
1091 rc = parse(gc, o, p);
1092 if (rc) {
1093 LOG(ERROR, "unable to convert libxl__json_object to %s. (rc=%d)", type, rc);
1094 rc = ERROR_FAIL;
1095 goto out;
1096 }
1097
1098 rc = 0;
1099 out:
1100 GC_FREE;
1101 return rc;
1102 }
1103
libxl__int_parse_json(libxl__gc * gc,const libxl__json_object * o,void * p)1104 int libxl__int_parse_json(libxl__gc *gc, const libxl__json_object *o,
1105 void *p)
1106 {
1107 long long i;
1108
1109 if (!libxl__json_object_is_integer(o))
1110 return ERROR_FAIL;
1111
1112 i = libxl__json_object_get_integer(o);
1113
1114 if (i > INT_MAX || i < INT_MIN)
1115 return ERROR_FAIL;
1116
1117 *((int *)p) = i;
1118
1119 return 0;
1120 }
1121
1122 /* Macro to generate:
1123 * libxl__uint8_parse_json
1124 * libxl__uint16_parse_json
1125 * libxl__uint32_parse_json
1126 */
1127 #define PARSE_UINT(width) \
1128 int libxl__uint ## width ## _parse_json(libxl__gc *gc, \
1129 const libxl__json_object *o,\
1130 void *p) \
1131 { \
1132 long long i; \
1133 \
1134 if (!libxl__json_object_is_integer(o)) \
1135 return ERROR_FAIL; \
1136 \
1137 i = libxl__json_object_get_integer(o); \
1138 \
1139 if (i < 0 || i > UINT ## width ## _MAX) \
1140 return ERROR_FAIL; \
1141 \
1142 *((uint ## width ## _t *)p) = i; \
1143 \
1144 return 0; \
1145 }
1146
1147 PARSE_UINT(8);
1148 PARSE_UINT(16);
1149 PARSE_UINT(32);
1150
libxl__uint64_parse_json(libxl__gc * gc,const libxl__json_object * o,void * p)1151 int libxl__uint64_parse_json(libxl__gc *gc, const libxl__json_object *o,
1152 void *p)
1153 {
1154 if (!libxl__json_object_is_integer(o) &&
1155 !libxl__json_object_is_number(o))
1156 return ERROR_FAIL;
1157
1158 if (libxl__json_object_is_integer(o)) {
1159 long long i = libxl__json_object_get_integer(o);
1160
1161 if (i < 0)
1162 return ERROR_FAIL;
1163
1164 *((uint64_t *)p) = i;
1165 } else {
1166 const char *s;
1167 unsigned long long i;
1168 int saved_errno = errno;
1169
1170 s = libxl__json_object_get_number(o);
1171
1172 errno = 0;
1173 i = strtoull(s, NULL, 10);
1174
1175 if (i == ULLONG_MAX && errno == ERANGE)
1176 return ERROR_FAIL;
1177
1178 errno = saved_errno;
1179 *((uint64_t *)p) = i;
1180 }
1181
1182 return 0;
1183 }
1184
1185 /*
1186 * Local variables:
1187 * mode: C
1188 * c-basic-offset: 4
1189 * indent-tabs-mode: nil
1190 * End:
1191 */
1192