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