4 * Copyright IBM, Corp. 2009
7 * Anthony Liguori <aliguori@us.ibm.com>
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.
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"
23 typedef struct JSONParserContext
30 #define BUG_ON(cond) assert(!(cond))
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
41 static QObject
*parse_value(JSONParserContext
*ctxt
, va_list *ap
);
46 static void GCC_FMT_ATTR(3, 4) parse_error(JSONParserContext
*ctxt
,
47 JSONToken
*token
, const char *msg
, ...)
52 vsnprintf(message
, sizeof(message
), msg
, ap
);
55 error_free(ctxt
->err
);
58 error_setg(&ctxt
->err
, "JSON parse error, %s", message
);
64 * These helpers are used to unescape strings.
66 static void wchar_to_utf8(uint16_t wchar
, char *buffer
, size_t buffer_length
)
68 if (wchar
<= 0x007F) {
69 BUG_ON(buffer_length
< 2);
71 buffer
[0] = wchar
& 0x7F;
73 } else if (wchar
<= 0x07FF) {
74 BUG_ON(buffer_length
< 3);
76 buffer
[0] = 0xC0 | ((wchar
>> 6) & 0x1F);
77 buffer
[1] = 0x80 | (wchar
& 0x3F);
80 BUG_ON(buffer_length
< 4);
82 buffer
[0] = 0xE0 | ((wchar
>> 12) & 0x0F);
83 buffer
[1] = 0x80 | ((wchar
>> 6) & 0x3F);
84 buffer
[2] = 0x80 | (wchar
& 0x3F);
89 static int hex2decimal(char ch
)
91 if (ch
>= '0' && ch
<= '9') {
93 } else if (ch
>= 'a' && ch
<= 'f') {
94 return 10 + (ch
- 'a');
95 } else if (ch
>= 'A' && ch
<= 'F') {
96 return 10 + (ch
- 'A');
103 * parse_string(): Parse a json string and return a QObject
112 * any-Unicode-character-
125 static QString
*qstring_from_escaped_str(JSONParserContext
*ctxt
,
128 const char *ptr
= token
->str
;
130 int double_quote
= 1;
141 ((double_quote
&& *ptr
!= '"') || (!double_quote
&& *ptr
!= '\''))) {
147 qstring_append(str
, "\"");
151 qstring_append(str
, "'");
155 qstring_append(str
, "\\");
159 qstring_append(str
, "/");
163 qstring_append(str
, "\b");
167 qstring_append(str
, "\f");
171 qstring_append(str
, "\n");
175 qstring_append(str
, "\r");
179 qstring_append(str
, "\t");
183 uint16_t unicode_char
= 0;
189 for (i
= 0; i
< 4; i
++) {
190 if (qemu_isxdigit(*ptr
)) {
191 unicode_char
|= hex2decimal(*ptr
) << ((3 - i
) * 4);
193 parse_error(ctxt
, token
,
194 "invalid hex escape sequence in string");
200 wchar_to_utf8(unicode_char
, utf8_char
, sizeof(utf8_char
));
201 qstring_append(str
, utf8_char
);
204 parse_error(ctxt
, token
, "invalid escape sequence in string");
213 qstring_append(str
, dummy
);
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
228 static JSONToken
*parser_context_pop_token(JSONParserContext
*ctxt
)
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
;
236 static JSONToken
*parser_context_peek_token(JSONParserContext
*ctxt
)
238 assert(!g_queue_is_empty(ctxt
->buf
));
239 return g_queue_peek_head(ctxt
->buf
);
242 static JSONParserContext
*parser_context_new(GQueue
*tokens
)
244 JSONParserContext
*ctxt
;
250 ctxt
= g_malloc0(sizeof(JSONParserContext
));
256 /* to support error propagation, ctxt->err must be freed separately */
257 static void parser_context_free(JSONParserContext
*ctxt
)
260 while (!g_queue_is_empty(ctxt
->buf
)) {
261 parser_context_pop_token(ctxt
);
263 g_free(ctxt
->current
);
264 g_queue_free(ctxt
->buf
);
272 static int parse_pair(JSONParserContext
*ctxt
, QDict
*dict
, va_list *ap
)
274 QObject
*key
= NULL
, *value
;
275 JSONToken
*peek
, *token
;
277 peek
= parser_context_peek_token(ctxt
);
279 parse_error(ctxt
, NULL
, "premature EOI");
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");
289 token
= parser_context_pop_token(ctxt
);
291 parse_error(ctxt
, NULL
, "premature EOI");
295 if (token
->type
!= JSON_COLON
) {
296 parse_error(ctxt
, token
, "missing : in object pair");
300 value
= parse_value(ctxt
, ap
);
302 parse_error(ctxt
, token
, "Missing value in dict");
306 qdict_put_obj(dict
, qstring_get_str(qobject_to_qstring(key
)), value
);
318 static QObject
*parse_object(JSONParserContext
*ctxt
, va_list *ap
)
321 JSONToken
*token
, *peek
;
323 token
= parser_context_pop_token(ctxt
);
324 assert(token
&& token
->type
== JSON_LCURLY
);
328 peek
= parser_context_peek_token(ctxt
);
330 parse_error(ctxt
, NULL
, "premature EOI");
334 if (peek
->type
!= JSON_RCURLY
) {
335 if (parse_pair(ctxt
, dict
, ap
) == -1) {
339 token
= parser_context_pop_token(ctxt
);
341 parse_error(ctxt
, NULL
, "premature EOI");
345 while (token
->type
!= JSON_RCURLY
) {
346 if (token
->type
!= JSON_COMMA
) {
347 parse_error(ctxt
, token
, "expected separator in dict");
351 if (parse_pair(ctxt
, dict
, ap
) == -1) {
355 token
= parser_context_pop_token(ctxt
);
357 parse_error(ctxt
, NULL
, "premature EOI");
362 (void)parser_context_pop_token(ctxt
);
365 return QOBJECT(dict
);
372 static QObject
*parse_array(JSONParserContext
*ctxt
, va_list *ap
)
375 JSONToken
*token
, *peek
;
377 token
= parser_context_pop_token(ctxt
);
378 assert(token
&& token
->type
== JSON_LSQUARE
);
382 peek
= parser_context_peek_token(ctxt
);
384 parse_error(ctxt
, NULL
, "premature EOI");
388 if (peek
->type
!= JSON_RSQUARE
) {
391 obj
= parse_value(ctxt
, ap
);
393 parse_error(ctxt
, token
, "expecting value");
397 qlist_append_obj(list
, obj
);
399 token
= parser_context_pop_token(ctxt
);
401 parse_error(ctxt
, NULL
, "premature EOI");
405 while (token
->type
!= JSON_RSQUARE
) {
406 if (token
->type
!= JSON_COMMA
) {
407 parse_error(ctxt
, token
, "expected separator in list");
411 obj
= parse_value(ctxt
, ap
);
413 parse_error(ctxt
, token
, "expecting value");
417 qlist_append_obj(list
, obj
);
419 token
= parser_context_pop_token(ctxt
);
421 parse_error(ctxt
, NULL
, "premature EOI");
426 (void)parser_context_pop_token(ctxt
);
429 return QOBJECT(list
);
436 static QObject
*parse_keyword(JSONParserContext
*ctxt
)
440 token
= parser_context_pop_token(ctxt
);
441 assert(token
&& token
->type
== JSON_KEYWORD
);
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 QOBJECT(qnull());
450 parse_error(ctxt
, token
, "invalid keyword '%s'", token
->str
);
454 static QObject
*parse_escape(JSONParserContext
*ctxt
, va_list *ap
)
462 token
= parser_context_pop_token(ctxt
);
463 assert(token
&& token
->type
== JSON_ESCAPE
);
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)));
491 static QObject
*parse_literal(JSONParserContext
*ctxt
)
495 token
= parser_context_pop_token(ctxt
);
498 switch (token
->type
) {
500 return QOBJECT(qstring_from_escaped_str(ctxt
, token
));
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
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
518 ret
= qemu_strtoi64(token
->str
, NULL
, 10, &value
);
520 return QOBJECT(qnum_from_int(value
));
522 assert(ret
== -ERANGE
);
524 if (token
->str
[0] != '-') {
525 ret
= qemu_strtou64(token
->str
, NULL
, 10, &uvalue
);
527 return QOBJECT(qnum_from_uint(uvalue
));
529 assert(ret
== -ERANGE
);
531 /* fall through to 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
)));
543 static QObject
*parse_value(JSONParserContext
*ctxt
, va_list *ap
)
547 token
= parser_context_peek_token(ctxt
);
549 parse_error(ctxt
, NULL
, "premature EOI");
553 switch (token
->type
) {
555 return parse_object(ctxt
, ap
);
557 return parse_array(ctxt
, ap
);
559 return parse_escape(ctxt
, ap
);
563 return parse_literal(ctxt
);
565 return parse_keyword(ctxt
);
567 parse_error(ctxt
, token
, "expecting value");
572 QObject
*json_parser_parse(GQueue
*tokens
, va_list *ap
)
574 return json_parser_parse_err(tokens
, ap
, NULL
);
577 QObject
*json_parser_parse_err(GQueue
*tokens
, va_list *ap
, Error
**errp
)
579 JSONParserContext
*ctxt
= parser_context_new(tokens
);
586 result
= parse_value(ctxt
, ap
);
588 error_propagate(errp
, ctxt
->err
);
590 parser_context_free(ctxt
);