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