1 /* 2 * JSON Parser 3 * 4 * Copyright IBM, Corp. 2009 5 * 6 * Authors: 7 * Anthony Liguori <aliguori@us.ibm.com> 8 * 9 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. 10 * See the COPYING.LIB file in the top-level directory. 11 * 12 */ 13 14 #include "qemu/osdep.h" 15 #include "qemu/cutils.h" 16 #include "qapi/error.h" 17 #include "qemu-common.h" 18 #include "qapi/qmp/types.h" 19 #include "qapi/qmp/json-parser.h" 20 #include "qapi/qmp/json-lexer.h" 21 #include "qapi/qmp/json-streamer.h" 22 23 typedef struct JSONParserContext 24 { 25 Error *err; 26 JSONToken *current; 27 GQueue *buf; 28 } JSONParserContext; 29 30 #define BUG_ON(cond) assert(!(cond)) 31 32 /** 33 * TODO 34 * 35 * 0) make errors meaningful again 36 * 1) add geometry information to tokens 37 * 3) should we return a parsed size? 38 * 4) deal with premature EOI 39 */ 40 41 static QObject *parse_value(JSONParserContext *ctxt, va_list *ap); 42 43 /** 44 * Error handler 45 */ 46 static void GCC_FMT_ATTR(3, 4) parse_error(JSONParserContext *ctxt, 47 JSONToken *token, const char *msg, ...) 48 { 49 va_list ap; 50 char message[1024]; 51 va_start(ap, msg); 52 vsnprintf(message, sizeof(message), msg, ap); 53 va_end(ap); 54 if (ctxt->err) { 55 error_free(ctxt->err); 56 ctxt->err = NULL; 57 } 58 error_setg(&ctxt->err, "JSON parse error, %s", message); 59 } 60 61 /** 62 * String helpers 63 * 64 * These helpers are used to unescape strings. 65 */ 66 static void wchar_to_utf8(uint16_t wchar, char *buffer, size_t buffer_length) 67 { 68 if (wchar <= 0x007F) { 69 BUG_ON(buffer_length < 2); 70 71 buffer[0] = wchar & 0x7F; 72 buffer[1] = 0; 73 } else if (wchar <= 0x07FF) { 74 BUG_ON(buffer_length < 3); 75 76 buffer[0] = 0xC0 | ((wchar >> 6) & 0x1F); 77 buffer[1] = 0x80 | (wchar & 0x3F); 78 buffer[2] = 0; 79 } else { 80 BUG_ON(buffer_length < 4); 81 82 buffer[0] = 0xE0 | ((wchar >> 12) & 0x0F); 83 buffer[1] = 0x80 | ((wchar >> 6) & 0x3F); 84 buffer[2] = 0x80 | (wchar & 0x3F); 85 buffer[3] = 0; 86 } 87 } 88 89 static int hex2decimal(char ch) 90 { 91 if (ch >= '0' && ch <= '9') { 92 return (ch - '0'); 93 } else if (ch >= 'a' && ch <= 'f') { 94 return 10 + (ch - 'a'); 95 } else if (ch >= 'A' && ch <= 'F') { 96 return 10 + (ch - 'A'); 97 } 98 99 return -1; 100 } 101 102 /** 103 * parse_string(): Parse a json string and return a QObject 104 * 105 * string 106 * "" 107 * " chars " 108 * chars 109 * char 110 * char chars 111 * char 112 * any-Unicode-character- 113 * except-"-or-\-or- 114 * control-character 115 * \" 116 * \\ 117 * \/ 118 * \b 119 * \f 120 * \n 121 * \r 122 * \t 123 * \u four-hex-digits 124 */ 125 static QString *qstring_from_escaped_str(JSONParserContext *ctxt, 126 JSONToken *token) 127 { 128 const char *ptr = token->str; 129 QString *str; 130 int double_quote = 1; 131 132 if (*ptr == '"') { 133 double_quote = 1; 134 } else { 135 double_quote = 0; 136 } 137 ptr++; 138 139 str = qstring_new(); 140 while (*ptr && 141 ((double_quote && *ptr != '"') || (!double_quote && *ptr != '\''))) { 142 if (*ptr == '\\') { 143 ptr++; 144 145 switch (*ptr) { 146 case '"': 147 qstring_append(str, "\""); 148 ptr++; 149 break; 150 case '\'': 151 qstring_append(str, "'"); 152 ptr++; 153 break; 154 case '\\': 155 qstring_append(str, "\\"); 156 ptr++; 157 break; 158 case '/': 159 qstring_append(str, "/"); 160 ptr++; 161 break; 162 case 'b': 163 qstring_append(str, "\b"); 164 ptr++; 165 break; 166 case 'f': 167 qstring_append(str, "\f"); 168 ptr++; 169 break; 170 case 'n': 171 qstring_append(str, "\n"); 172 ptr++; 173 break; 174 case 'r': 175 qstring_append(str, "\r"); 176 ptr++; 177 break; 178 case 't': 179 qstring_append(str, "\t"); 180 ptr++; 181 break; 182 case 'u': { 183 uint16_t unicode_char = 0; 184 char utf8_char[4]; 185 int i = 0; 186 187 ptr++; 188 189 for (i = 0; i < 4; i++) { 190 if (qemu_isxdigit(*ptr)) { 191 unicode_char |= hex2decimal(*ptr) << ((3 - i) * 4); 192 } else { 193 parse_error(ctxt, token, 194 "invalid hex escape sequence in string"); 195 goto out; 196 } 197 ptr++; 198 } 199 200 wchar_to_utf8(unicode_char, utf8_char, sizeof(utf8_char)); 201 qstring_append(str, utf8_char); 202 } break; 203 default: 204 parse_error(ctxt, token, "invalid escape sequence in string"); 205 goto out; 206 } 207 } else { 208 char dummy[2]; 209 210 dummy[0] = *ptr++; 211 dummy[1] = 0; 212 213 qstring_append(str, dummy); 214 } 215 } 216 217 return str; 218 219 out: 220 QDECREF(str); 221 return NULL; 222 } 223 224 /* Note: the token object returned by parser_context_peek_token or 225 * parser_context_pop_token is deleted as soon as parser_context_pop_token 226 * is called again. 227 */ 228 static JSONToken *parser_context_pop_token(JSONParserContext *ctxt) 229 { 230 g_free(ctxt->current); 231 assert(!g_queue_is_empty(ctxt->buf)); 232 ctxt->current = g_queue_pop_head(ctxt->buf); 233 return ctxt->current; 234 } 235 236 static JSONToken *parser_context_peek_token(JSONParserContext *ctxt) 237 { 238 assert(!g_queue_is_empty(ctxt->buf)); 239 return g_queue_peek_head(ctxt->buf); 240 } 241 242 static JSONParserContext *parser_context_new(GQueue *tokens) 243 { 244 JSONParserContext *ctxt; 245 246 if (!tokens) { 247 return NULL; 248 } 249 250 ctxt = g_malloc0(sizeof(JSONParserContext)); 251 ctxt->buf = tokens; 252 253 return ctxt; 254 } 255 256 /* to support error propagation, ctxt->err must be freed separately */ 257 static void parser_context_free(JSONParserContext *ctxt) 258 { 259 if (ctxt) { 260 while (!g_queue_is_empty(ctxt->buf)) { 261 parser_context_pop_token(ctxt); 262 } 263 g_free(ctxt->current); 264 g_queue_free(ctxt->buf); 265 g_free(ctxt); 266 } 267 } 268 269 /** 270 * Parsing rules 271 */ 272 static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap) 273 { 274 QObject *key = NULL, *value; 275 JSONToken *peek, *token; 276 277 peek = parser_context_peek_token(ctxt); 278 if (peek == NULL) { 279 parse_error(ctxt, NULL, "premature EOI"); 280 goto out; 281 } 282 283 key = parse_value(ctxt, ap); 284 if (!key || qobject_type(key) != QTYPE_QSTRING) { 285 parse_error(ctxt, peek, "key is not a string in object"); 286 goto out; 287 } 288 289 token = parser_context_pop_token(ctxt); 290 if (token == NULL) { 291 parse_error(ctxt, NULL, "premature EOI"); 292 goto out; 293 } 294 295 if (token->type != JSON_COLON) { 296 parse_error(ctxt, token, "missing : in object pair"); 297 goto out; 298 } 299 300 value = parse_value(ctxt, ap); 301 if (value == NULL) { 302 parse_error(ctxt, token, "Missing value in dict"); 303 goto out; 304 } 305 306 qdict_put_obj(dict, qstring_get_str(qobject_to_qstring(key)), value); 307 308 qobject_decref(key); 309 310 return 0; 311 312 out: 313 qobject_decref(key); 314 315 return -1; 316 } 317 318 static QObject *parse_object(JSONParserContext *ctxt, va_list *ap) 319 { 320 QDict *dict = NULL; 321 JSONToken *token, *peek; 322 323 token = parser_context_pop_token(ctxt); 324 assert(token && token->type == JSON_LCURLY); 325 326 dict = qdict_new(); 327 328 peek = parser_context_peek_token(ctxt); 329 if (peek == NULL) { 330 parse_error(ctxt, NULL, "premature EOI"); 331 goto out; 332 } 333 334 if (peek->type != JSON_RCURLY) { 335 if (parse_pair(ctxt, dict, ap) == -1) { 336 goto out; 337 } 338 339 token = parser_context_pop_token(ctxt); 340 if (token == NULL) { 341 parse_error(ctxt, NULL, "premature EOI"); 342 goto out; 343 } 344 345 while (token->type != JSON_RCURLY) { 346 if (token->type != JSON_COMMA) { 347 parse_error(ctxt, token, "expected separator in dict"); 348 goto out; 349 } 350 351 if (parse_pair(ctxt, dict, ap) == -1) { 352 goto out; 353 } 354 355 token = parser_context_pop_token(ctxt); 356 if (token == NULL) { 357 parse_error(ctxt, NULL, "premature EOI"); 358 goto out; 359 } 360 } 361 } else { 362 (void)parser_context_pop_token(ctxt); 363 } 364 365 return QOBJECT(dict); 366 367 out: 368 QDECREF(dict); 369 return NULL; 370 } 371 372 static QObject *parse_array(JSONParserContext *ctxt, va_list *ap) 373 { 374 QList *list = NULL; 375 JSONToken *token, *peek; 376 377 token = parser_context_pop_token(ctxt); 378 assert(token && token->type == JSON_LSQUARE); 379 380 list = qlist_new(); 381 382 peek = parser_context_peek_token(ctxt); 383 if (peek == NULL) { 384 parse_error(ctxt, NULL, "premature EOI"); 385 goto out; 386 } 387 388 if (peek->type != JSON_RSQUARE) { 389 QObject *obj; 390 391 obj = parse_value(ctxt, ap); 392 if (obj == NULL) { 393 parse_error(ctxt, token, "expecting value"); 394 goto out; 395 } 396 397 qlist_append_obj(list, obj); 398 399 token = parser_context_pop_token(ctxt); 400 if (token == NULL) { 401 parse_error(ctxt, NULL, "premature EOI"); 402 goto out; 403 } 404 405 while (token->type != JSON_RSQUARE) { 406 if (token->type != JSON_COMMA) { 407 parse_error(ctxt, token, "expected separator in list"); 408 goto out; 409 } 410 411 obj = parse_value(ctxt, ap); 412 if (obj == NULL) { 413 parse_error(ctxt, token, "expecting value"); 414 goto out; 415 } 416 417 qlist_append_obj(list, obj); 418 419 token = parser_context_pop_token(ctxt); 420 if (token == NULL) { 421 parse_error(ctxt, NULL, "premature EOI"); 422 goto out; 423 } 424 } 425 } else { 426 (void)parser_context_pop_token(ctxt); 427 } 428 429 return QOBJECT(list); 430 431 out: 432 QDECREF(list); 433 return NULL; 434 } 435 436 static QObject *parse_keyword(JSONParserContext *ctxt) 437 { 438 JSONToken *token; 439 440 token = parser_context_pop_token(ctxt); 441 assert(token && token->type == JSON_KEYWORD); 442 443 if (!strcmp(token->str, "true")) { 444 return QOBJECT(qbool_from_bool(true)); 445 } else if (!strcmp(token->str, "false")) { 446 return QOBJECT(qbool_from_bool(false)); 447 } else if (!strcmp(token->str, "null")) { 448 return qnull(); 449 } 450 parse_error(ctxt, token, "invalid keyword '%s'", token->str); 451 return NULL; 452 } 453 454 static QObject *parse_escape(JSONParserContext *ctxt, va_list *ap) 455 { 456 JSONToken *token; 457 458 if (ap == NULL) { 459 return NULL; 460 } 461 462 token = parser_context_pop_token(ctxt); 463 assert(token && token->type == JSON_ESCAPE); 464 465 if (!strcmp(token->str, "%p")) { 466 return va_arg(*ap, QObject *); 467 } else if (!strcmp(token->str, "%i")) { 468 return QOBJECT(qbool_from_bool(va_arg(*ap, int))); 469 } else if (!strcmp(token->str, "%d")) { 470 return QOBJECT(qnum_from_int(va_arg(*ap, int))); 471 } else if (!strcmp(token->str, "%ld")) { 472 return QOBJECT(qnum_from_int(va_arg(*ap, long))); 473 } else if (!strcmp(token->str, "%lld") || 474 !strcmp(token->str, "%I64d")) { 475 return QOBJECT(qnum_from_int(va_arg(*ap, long long))); 476 } else if (!strcmp(token->str, "%u")) { 477 return QOBJECT(qnum_from_uint(va_arg(*ap, unsigned int))); 478 } else if (!strcmp(token->str, "%lu")) { 479 return QOBJECT(qnum_from_uint(va_arg(*ap, unsigned long))); 480 } else if (!strcmp(token->str, "%llu") || 481 !strcmp(token->str, "%I64u")) { 482 return QOBJECT(qnum_from_uint(va_arg(*ap, unsigned long long))); 483 } else if (!strcmp(token->str, "%s")) { 484 return QOBJECT(qstring_from_str(va_arg(*ap, const char *))); 485 } else if (!strcmp(token->str, "%f")) { 486 return QOBJECT(qnum_from_double(va_arg(*ap, double))); 487 } 488 return NULL; 489 } 490 491 static QObject *parse_literal(JSONParserContext *ctxt) 492 { 493 JSONToken *token; 494 495 token = parser_context_pop_token(ctxt); 496 assert(token); 497 498 switch (token->type) { 499 case JSON_STRING: 500 return QOBJECT(qstring_from_escaped_str(ctxt, token)); 501 case JSON_INTEGER: { 502 /* 503 * Represent JSON_INTEGER as QNUM_I64 if possible, else as 504 * QNUM_U64, else as QNUM_DOUBLE. Note that qemu_strtoi64() 505 * and qemu_strtou64() fail with ERANGE when it's not 506 * possible. 507 * 508 * qnum_get_int() will then work for any signed 64-bit 509 * JSON_INTEGER, qnum_get_uint() for any unsigned 64-bit 510 * integer, and qnum_get_double() both for any JSON_INTEGER 511 * and any JSON_FLOAT (with precision loss for integers beyond 512 * 53 bits) 513 */ 514 int ret; 515 int64_t value; 516 uint64_t uvalue; 517 518 ret = qemu_strtoi64(token->str, NULL, 10, &value); 519 if (!ret) { 520 return QOBJECT(qnum_from_int(value)); 521 } 522 assert(ret == -ERANGE); 523 524 if (token->str[0] != '-') { 525 ret = qemu_strtou64(token->str, NULL, 10, &uvalue); 526 if (!ret) { 527 return QOBJECT(qnum_from_uint(uvalue)); 528 } 529 assert(ret == -ERANGE); 530 } 531 /* fall through to JSON_FLOAT */ 532 } 533 case JSON_FLOAT: 534 /* FIXME dependent on locale; a pervasive issue in QEMU */ 535 /* FIXME our lexer matches RFC 7159 in forbidding Inf or NaN, 536 * but those might be useful extensions beyond JSON */ 537 return QOBJECT(qnum_from_double(strtod(token->str, NULL))); 538 default: 539 abort(); 540 } 541 } 542 543 static QObject *parse_value(JSONParserContext *ctxt, va_list *ap) 544 { 545 JSONToken *token; 546 547 token = parser_context_peek_token(ctxt); 548 if (token == NULL) { 549 parse_error(ctxt, NULL, "premature EOI"); 550 return NULL; 551 } 552 553 switch (token->type) { 554 case JSON_LCURLY: 555 return parse_object(ctxt, ap); 556 case JSON_LSQUARE: 557 return parse_array(ctxt, ap); 558 case JSON_ESCAPE: 559 return parse_escape(ctxt, ap); 560 case JSON_INTEGER: 561 case JSON_FLOAT: 562 case JSON_STRING: 563 return parse_literal(ctxt); 564 case JSON_KEYWORD: 565 return parse_keyword(ctxt); 566 default: 567 parse_error(ctxt, token, "expecting value"); 568 return NULL; 569 } 570 } 571 572 QObject *json_parser_parse(GQueue *tokens, va_list *ap) 573 { 574 return json_parser_parse_err(tokens, ap, NULL); 575 } 576 577 QObject *json_parser_parse_err(GQueue *tokens, va_list *ap, Error **errp) 578 { 579 JSONParserContext *ctxt = parser_context_new(tokens); 580 QObject *result; 581 582 if (!ctxt) { 583 return NULL; 584 } 585 586 result = parse_value(ctxt, ap); 587 588 error_propagate(errp, ctxt->err); 589 590 parser_context_free(ctxt); 591 592 return result; 593 } 594