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 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 }; 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), LIBXL__LOG_DEBUG, 63 "response:\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 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 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 466 int libxl__json_object_append_to(libxl__gc *gc, libxl__json_object *obj, 467 libxl__yajl_ctx *ctx) 468 { 469 libxl__json_object *dst = ctx->current; 470 471 if (dst) { 472 switch (dst->type) { 473 case JSON_MAP: { 474 libxl__json_map_node *last; 475 476 if (dst->u.map->count == 0) { 477 LIBXL__LOG(libxl__gc_owner(gc), LIBXL__LOG_ERROR, 478 "Try to add a value to an empty map (with no key)"); 479 return ERROR_FAIL; 480 } 481 flexarray_get(dst->u.map, dst->u.map->count - 1, (void**)&last); 482 last->obj = obj; 483 break; 484 } 485 case JSON_ARRAY: 486 flexarray_append(dst->u.array, obj); 487 break; 488 default: 489 LIBXL__LOG(libxl__gc_owner(gc), LIBXL__LOG_ERROR, 490 "Try append an object is not a map/array (%i)", 491 dst->type); 492 return ERROR_FAIL; 493 } 494 } 495 496 obj->parent = dst; 497 498 if (libxl__json_object_is_map(obj) || libxl__json_object_is_array(obj)) 499 ctx->current = obj; 500 if (ctx->head == NULL) 501 ctx->head = obj; 502 503 return 0; 504 } 505 506 void libxl__json_object_free(libxl__gc *gc, libxl__json_object *obj) 507 { 508 int idx = 0; 509 510 if (obj == NULL) 511 return; 512 switch (obj->type) { 513 case JSON_STRING: 514 case JSON_NUMBER: 515 free(obj->u.string); 516 break; 517 case JSON_MAP: { 518 libxl__json_map_node *node = NULL; 519 520 for (idx = 0; idx < obj->u.map->count; idx++) { 521 if (flexarray_get(obj->u.map, idx, (void**)&node) != 0) 522 break; 523 libxl__json_object_free(gc, node->obj); 524 free(node->map_key); 525 free(node); 526 node = NULL; 527 } 528 flexarray_free(obj->u.map); 529 break; 530 } 531 case JSON_ARRAY: { 532 libxl__json_object *node = NULL; 533 534 for (idx = 0; idx < obj->u.array->count; idx++) { 535 if (flexarray_get(obj->u.array, idx, (void**)&node) != 0) 536 break; 537 libxl__json_object_free(gc, node); 538 node = NULL; 539 } 540 flexarray_free(obj->u.array); 541 break; 542 } 543 default: 544 break; 545 } 546 free(obj); 547 } 548 549 libxl__json_object *libxl__json_array_get(const libxl__json_object *o, int i) 550 { 551 flexarray_t *array = NULL; 552 libxl__json_object *obj = NULL; 553 554 if ((array = libxl__json_object_get_array(o)) == NULL) { 555 return NULL; 556 } 557 558 if (i >= array->count) 559 return NULL; 560 561 if (flexarray_get(array, i, (void**)&obj) != 0) 562 return NULL; 563 564 return obj; 565 } 566 567 libxl__json_map_node *libxl__json_map_node_get(const libxl__json_object *o, 568 int i) 569 { 570 flexarray_t *array = NULL; 571 libxl__json_map_node *obj = NULL; 572 573 if ((array = libxl__json_object_get_map(o)) == NULL) { 574 return NULL; 575 } 576 577 if (i >= array->count) 578 return NULL; 579 580 if (flexarray_get(array, i, (void**)&obj) != 0) 581 return NULL; 582 583 return obj; 584 } 585 586 const libxl__json_object *libxl__json_map_get(const char *key, 587 const libxl__json_object *o, 588 libxl__json_node_type expected_type) 589 { 590 flexarray_t *maps = NULL; 591 int idx = 0; 592 593 if (libxl__json_object_is_map(o)) { 594 libxl__json_map_node *node = NULL; 595 596 maps = o->u.map; 597 for (idx = 0; idx < maps->count; idx++) { 598 if (flexarray_get(maps, idx, (void**)&node) != 0) 599 return NULL; 600 if (strcmp(key, node->map_key) == 0) { 601 if (expected_type == JSON_ANY 602 || (node->obj && (node->obj->type & expected_type))) { 603 return node->obj; 604 } else { 605 return NULL; 606 } 607 } 608 } 609 } 610 return NULL; 611 } 612 613 yajl_status libxl__json_object_to_yajl_gen(libxl__gc *gc, 614 yajl_gen hand, 615 libxl__json_object *obj) 616 { 617 int idx = 0; 618 yajl_status rc; 619 620 #define CONVERT_YAJL_GEN_TO_STATUS(gen) \ 621 ((gen) == yajl_gen_status_ok ? yajl_status_ok : yajl_status_error) 622 623 switch (obj->type) { 624 case JSON_NULL: 625 return CONVERT_YAJL_GEN_TO_STATUS(yajl_gen_null(hand)); 626 case JSON_BOOL: 627 return CONVERT_YAJL_GEN_TO_STATUS(yajl_gen_bool(hand, obj->u.b)); 628 case JSON_INTEGER: 629 return CONVERT_YAJL_GEN_TO_STATUS(yajl_gen_integer(hand, obj->u.i)); 630 case JSON_DOUBLE: 631 return CONVERT_YAJL_GEN_TO_STATUS(yajl_gen_double(hand, obj->u.d)); 632 case JSON_NUMBER: 633 return CONVERT_YAJL_GEN_TO_STATUS( 634 yajl_gen_number(hand, obj->u.string, strlen(obj->u.string))); 635 case JSON_STRING: 636 return CONVERT_YAJL_GEN_TO_STATUS( 637 libxl__yajl_gen_asciiz(hand, obj->u.string)); 638 case JSON_MAP: { 639 libxl__json_map_node *node = NULL; 640 641 rc = CONVERT_YAJL_GEN_TO_STATUS(yajl_gen_map_open(hand)); 642 if (rc != yajl_status_ok) 643 return rc; 644 for (idx = 0; idx < obj->u.map->count; idx++) { 645 if (flexarray_get(obj->u.map, idx, (void**)&node) != 0) 646 break; 647 648 rc = CONVERT_YAJL_GEN_TO_STATUS( 649 libxl__yajl_gen_asciiz(hand, node->map_key)); 650 if (rc != yajl_status_ok) 651 return rc; 652 rc = libxl__json_object_to_yajl_gen(gc, hand, node->obj); 653 if (rc != yajl_status_ok) 654 return rc; 655 } 656 return CONVERT_YAJL_GEN_TO_STATUS(yajl_gen_map_close(hand)); 657 } 658 case JSON_ARRAY: { 659 libxl__json_object *node = NULL; 660 661 rc = CONVERT_YAJL_GEN_TO_STATUS(yajl_gen_array_open(hand)); 662 if (rc != yajl_status_ok) 663 return rc; 664 for (idx = 0; idx < obj->u.array->count; idx++) { 665 if (flexarray_get(obj->u.array, idx, (void**)&node) != 0) 666 break; 667 rc = libxl__json_object_to_yajl_gen(gc, hand, node); 668 if (rc != yajl_status_ok) 669 return rc; 670 } 671 return CONVERT_YAJL_GEN_TO_STATUS(yajl_gen_array_close(hand)); 672 } 673 case JSON_ANY: 674 /* JSON_ANY is not a valid value for obj->type. */ 675 ; 676 } 677 abort(); 678 #undef CONVERT_YAJL_GEN_TO_STATUS 679 } 680 681 682 /* 683 * JSON callbacks 684 */ 685 686 static int json_callback_null(void *opaque) 687 { 688 libxl__yajl_ctx *ctx = opaque; 689 libxl__json_object *obj; 690 691 DEBUG_GEN(ctx, null); 692 693 obj = libxl__json_object_alloc(ctx->gc, JSON_NULL); 694 695 if (libxl__json_object_append_to(ctx->gc, obj, ctx)) 696 return 0; 697 698 return 1; 699 } 700 701 static int json_callback_boolean(void *opaque, int boolean) 702 { 703 libxl__yajl_ctx *ctx = opaque; 704 libxl__json_object *obj; 705 706 DEBUG_GEN_VALUE(ctx, bool, boolean); 707 708 obj = libxl__json_object_alloc(ctx->gc, JSON_BOOL); 709 obj->u.b = boolean; 710 711 if (libxl__json_object_append_to(ctx->gc, obj, ctx)) 712 return 0; 713 714 return 1; 715 } 716 717 static bool is_decimal(const char *s, unsigned len) 718 { 719 const char *end = s + len; 720 for (; s < end; s++) { 721 if (*s == '.') 722 return true; 723 } 724 return false; 725 } 726 727 static int json_callback_number(void *opaque, const char *s, libxl_yajl_length len) 728 { 729 libxl__yajl_ctx *ctx = opaque; 730 libxl__json_object *obj = NULL; 731 char *t = NULL; 732 733 DEBUG_GEN_NUMBER(ctx, s, len); 734 735 if (is_decimal(s, len)) { 736 double d = strtod(s, NULL); 737 738 if ((d == HUGE_VALF || d == HUGE_VALL) && errno == ERANGE) { 739 goto error; 740 } 741 742 obj = libxl__json_object_alloc(ctx->gc, JSON_DOUBLE); 743 obj->u.d = d; 744 } else { 745 long long i = strtoll(s, NULL, 10); 746 747 if ((i == LLONG_MIN || i == LLONG_MAX) && errno == ERANGE) { 748 goto error; 749 } 750 751 obj = libxl__json_object_alloc(ctx->gc, JSON_INTEGER); 752 obj->u.i = i; 753 } 754 goto out; 755 756 error: 757 /* If the conversion fail, we just store the original string. */ 758 obj = libxl__json_object_alloc(ctx->gc, JSON_NUMBER); 759 760 t = libxl__zalloc(ctx->gc, len + 1); 761 strncpy(t, s, len); 762 t[len] = 0; 763 764 obj->u.string = t; 765 766 out: 767 if (libxl__json_object_append_to(ctx->gc, obj, ctx)) 768 return 0; 769 770 return 1; 771 } 772 773 static int json_callback_string(void *opaque, const unsigned char *str, 774 libxl_yajl_length len) 775 { 776 libxl__yajl_ctx *ctx = opaque; 777 char *t = NULL; 778 libxl__json_object *obj = NULL; 779 780 t = libxl__zalloc(ctx->gc, len + 1); 781 782 DEBUG_GEN_STRING(ctx, str, len); 783 784 strncpy(t, (const char *) str, len); 785 t[len] = 0; 786 787 obj = libxl__json_object_alloc(ctx->gc, JSON_STRING); 788 obj->u.string = t; 789 790 if (libxl__json_object_append_to(ctx->gc, obj, ctx)) 791 return 0; 792 793 return 1; 794 } 795 796 static int json_callback_map_key(void *opaque, const unsigned char *str, 797 libxl_yajl_length len) 798 { 799 libxl__yajl_ctx *ctx = opaque; 800 char *t = NULL; 801 libxl__json_object *obj = ctx->current; 802 libxl__gc *gc = ctx->gc; 803 804 t = libxl__zalloc(gc, len + 1); 805 806 DEBUG_GEN_STRING(ctx, str, len); 807 808 strncpy(t, (const char *) str, len); 809 t[len] = 0; 810 811 if (libxl__json_object_is_map(obj)) { 812 libxl__json_map_node *node; 813 814 GCNEW(node); 815 node->map_key = t; 816 node->obj = NULL; 817 818 flexarray_append(obj->u.map, node); 819 } else { 820 LIBXL__LOG(libxl__gc_owner(ctx->gc), LIBXL__LOG_ERROR, 821 "Current json object is not a map"); 822 return 0; 823 } 824 825 return 1; 826 } 827 828 static int json_callback_start_map(void *opaque) 829 { 830 libxl__yajl_ctx *ctx = opaque; 831 libxl__json_object *obj = NULL; 832 833 DEBUG_GEN(ctx, map_open); 834 835 obj = libxl__json_object_alloc(ctx->gc, JSON_MAP); 836 837 if (libxl__json_object_append_to(ctx->gc, obj, ctx)) 838 return 0; 839 840 return 1; 841 } 842 843 static int json_callback_end_map(void *opaque) 844 { 845 libxl__yajl_ctx *ctx = opaque; 846 847 DEBUG_GEN(ctx, map_close); 848 849 if (ctx->current) { 850 ctx->current = ctx->current->parent; 851 } else { 852 LIBXL__LOG(libxl__gc_owner(ctx->gc), LIBXL__LOG_ERROR, 853 "No current libxl__json_object, cannot use his parent."); 854 return 0; 855 } 856 857 return 1; 858 } 859 860 static int json_callback_start_array(void *opaque) 861 { 862 libxl__yajl_ctx *ctx = opaque; 863 libxl__json_object *obj = NULL; 864 865 DEBUG_GEN(ctx, array_open); 866 867 obj = libxl__json_object_alloc(ctx->gc, JSON_ARRAY); 868 869 if (libxl__json_object_append_to(ctx->gc, obj, ctx)) 870 return 0; 871 872 return 1; 873 } 874 875 static int json_callback_end_array(void *opaque) 876 { 877 libxl__yajl_ctx *ctx = opaque; 878 879 DEBUG_GEN(ctx, array_close); 880 881 if (ctx->current) { 882 ctx->current = ctx->current->parent; 883 } else { 884 LIBXL__LOG(libxl__gc_owner(ctx->gc), LIBXL__LOG_ERROR, 885 "No current libxl__json_object, cannot use his parent."); 886 return 0; 887 } 888 889 return 1; 890 } 891 892 static yajl_callbacks callbacks = { 893 json_callback_null, 894 json_callback_boolean, 895 NULL, 896 NULL, 897 json_callback_number, 898 json_callback_string, 899 json_callback_start_map, 900 json_callback_map_key, 901 json_callback_end_map, 902 json_callback_start_array, 903 json_callback_end_array 904 }; 905 906 static void yajl_ctx_free(libxl__yajl_ctx *yajl_ctx) 907 { 908 if (yajl_ctx->hand) { 909 yajl_free(yajl_ctx->hand); 910 yajl_ctx->hand = NULL; 911 } 912 DEBUG_GEN_FREE(yajl_ctx); 913 } 914 915 libxl__json_object *libxl__json_parse(libxl__gc *gc, const char *s) 916 { 917 yajl_status status; 918 libxl__yajl_ctx yajl_ctx; 919 libxl__json_object *o = NULL; 920 unsigned char *str = NULL; 921 922 memset(&yajl_ctx, 0, sizeof (yajl_ctx)); 923 yajl_ctx.gc = gc; 924 925 DEBUG_GEN_ALLOC(&yajl_ctx); 926 927 if (yajl_ctx.hand == NULL) { 928 yajl_ctx.hand = libxl__yajl_alloc(&callbacks, NULL, &yajl_ctx); 929 } 930 status = yajl_parse(yajl_ctx.hand, (const unsigned char *)s, strlen(s)); 931 if (status != yajl_status_ok) 932 goto out; 933 934 status = yajl_complete_parse(yajl_ctx.hand); 935 if (status != yajl_status_ok) 936 goto out; 937 938 o = yajl_ctx.head; 939 940 DEBUG_GEN_REPORT(&yajl_ctx); 941 942 yajl_ctx.head = NULL; 943 944 yajl_ctx_free(&yajl_ctx); 945 return o; 946 947 out: 948 str = yajl_get_error(yajl_ctx.hand, 1, (const unsigned char*)s, strlen(s)); 949 950 LIBXL__LOG(libxl__gc_owner(gc), LIBXL__LOG_ERROR, "yajl error: %s", str); 951 yajl_free_error(yajl_ctx.hand, str); 952 yajl_ctx_free(&yajl_ctx); 953 return NULL; 954 } 955 956 static const char *yajl_gen_status_to_string(yajl_gen_status s) 957 { 958 switch (s) { 959 case yajl_gen_status_ok: abort(); 960 case yajl_gen_keys_must_be_strings: 961 return "keys must be strings"; 962 case yajl_max_depth_exceeded: 963 return "max depth exceeded"; 964 case yajl_gen_in_error_state: 965 return "in error state"; 966 case yajl_gen_generation_complete: 967 return "generation complete"; 968 case yajl_gen_invalid_number: 969 return "invalid number"; 970 #if 0 /* This is in the docs but not implemented in the version I am running. */ 971 case yajl_gen_no_buf: 972 return "no buffer"; 973 case yajl_gen_invalid_string: 974 return "invalid string"; 975 #endif 976 default: 977 return "unknown error"; 978 } 979 } 980 981 char *libxl__object_to_json(libxl_ctx *ctx, const char *type, 982 libxl__gen_json_callback gen, void *p) 983 { 984 const unsigned char *buf; 985 char *ret = NULL; 986 libxl_yajl_length len = 0; 987 yajl_gen_status s; 988 yajl_gen hand; 989 990 hand = libxl_yajl_gen_alloc(NULL); 991 if (!hand) 992 return NULL; 993 994 s = gen(hand, p); 995 if (s != yajl_gen_status_ok) 996 goto out; 997 998 s = yajl_gen_get_buf(hand, &buf, &len); 999 if (s != yajl_gen_status_ok) 1000 goto out; 1001 ret = strdup((const char *)buf); 1002 1003 out: 1004 yajl_gen_free(hand); 1005 1006 if (s != yajl_gen_status_ok) { 1007 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, 1008 "unable to convert %s to JSON representation. " 1009 "YAJL error code %d: %s", type, 1010 s, yajl_gen_status_to_string(s)); 1011 } else if (!ret) { 1012 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, 1013 "unable to allocate space for to JSON representation of %s", 1014 type); 1015 } 1016 1017 return ret; 1018 } 1019 1020 yajl_gen_status libxl__uint64_gen_json(yajl_gen hand, uint64_t val) 1021 { 1022 char *num; 1023 int len; 1024 yajl_gen_status s; 1025 1026 1027 len = asprintf(&num, "%"PRIu64, val); 1028 if (len == -1) { 1029 s = yajl_gen_in_error_state; 1030 goto out; 1031 } 1032 1033 s = yajl_gen_number(hand, num, len); 1034 1035 free(num); 1036 1037 out: 1038 return s; 1039 } 1040 1041 int libxl__object_from_json(libxl_ctx *ctx, const char *type, 1042 libxl__json_parse_callback parse, 1043 void *p, const char *s) 1044 { 1045 GC_INIT(ctx); 1046 libxl__json_object *o; 1047 int rc; 1048 1049 o = libxl__json_parse(gc, s); 1050 if (!o) { 1051 LOG(ERROR, 1052 "unable to generate libxl__json_object from JSON representation of %s.", 1053 type); 1054 rc = ERROR_FAIL; 1055 goto out; 1056 } 1057 1058 rc = parse(gc, o, p); 1059 if (rc) { 1060 LOG(ERROR, "unable to convert libxl__json_object to %s. (rc=%d)", type, rc); 1061 rc = ERROR_FAIL; 1062 goto out; 1063 } 1064 1065 rc = 0; 1066 out: 1067 GC_FREE; 1068 return rc; 1069 } 1070 1071 int libxl__int_parse_json(libxl__gc *gc, const libxl__json_object *o, 1072 void *p) 1073 { 1074 long long i; 1075 1076 if (!libxl__json_object_is_integer(o)) 1077 return ERROR_FAIL; 1078 1079 i = libxl__json_object_get_integer(o); 1080 1081 if (i > INT_MAX || i < INT_MIN) 1082 return ERROR_FAIL; 1083 1084 *((int *)p) = i; 1085 1086 return 0; 1087 } 1088 1089 /* Macro to generate: 1090 * libxl__uint8_parse_json 1091 * libxl__uint16_parse_json 1092 * libxl__uint32_parse_json 1093 */ 1094 #define PARSE_UINT(width) \ 1095 int libxl__uint ## width ## _parse_json(libxl__gc *gc, \ 1096 const libxl__json_object *o,\ 1097 void *p) \ 1098 { \ 1099 long long i; \ 1100 \ 1101 if (!libxl__json_object_is_integer(o)) \ 1102 return ERROR_FAIL; \ 1103 \ 1104 i = libxl__json_object_get_integer(o); \ 1105 \ 1106 if (i < 0 || i > UINT ## width ## _MAX) \ 1107 return ERROR_FAIL; \ 1108 \ 1109 *((uint ## width ## _t *)p) = i; \ 1110 \ 1111 return 0; \ 1112 } 1113 1114 PARSE_UINT(8); 1115 PARSE_UINT(16); 1116 PARSE_UINT(32); 1117 1118 int libxl__uint64_parse_json(libxl__gc *gc, const libxl__json_object *o, 1119 void *p) 1120 { 1121 if (!libxl__json_object_is_integer(o) && 1122 !libxl__json_object_is_number(o)) 1123 return ERROR_FAIL; 1124 1125 if (libxl__json_object_is_integer(o)) { 1126 long long i = libxl__json_object_get_integer(o); 1127 1128 if (i < 0) 1129 return ERROR_FAIL; 1130 1131 *((uint64_t *)p) = i; 1132 } else { 1133 const char *s; 1134 unsigned long long i; 1135 int saved_errno = errno; 1136 1137 s = libxl__json_object_get_number(o); 1138 1139 errno = 0; 1140 i = strtoull(s, NULL, 10); 1141 1142 if (i == ULLONG_MAX && errno == ERANGE) 1143 return ERROR_FAIL; 1144 1145 errno = saved_errno; 1146 *((uint64_t *)p) = i; 1147 } 1148 1149 return 0; 1150 } 1151 1152 /* 1153 * Local variables: 1154 * mode: C 1155 * c-basic-offset: 4 1156 * indent-tabs-mode: nil 1157 * End: 1158 */ 1159