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.
16 #include "qemu-common.h"
17 #include "qapi/qmp/qstring.h"
18 #include "qapi/qmp/qint.h"
19 #include "qapi/qmp/qdict.h"
20 #include "qapi/qmp/qlist.h"
21 #include "qapi/qmp/qfloat.h"
22 #include "qapi/qmp/qbool.h"
23 #include "qapi/qmp/json-parser.h"
24 #include "qapi/qmp/json-lexer.h"
26 typedef struct JSONParserContext
33 #define BUG_ON(cond) assert(!(cond))
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
44 static QObject
*parse_value(JSONParserContext
*ctxt
, va_list *ap
);
49 * tokens are dictionaries that contain a type, a string value, and geometry information
50 * about a token identified by the lexer. These are routines that make working with
51 * these objects a bit easier.
53 static const char *token_get_value(QObject
*obj
)
55 return qdict_get_str(qobject_to_qdict(obj
), "token");
58 static JSONTokenType
token_get_type(QObject
*obj
)
60 return qdict_get_int(qobject_to_qdict(obj
), "type");
66 static void GCC_FMT_ATTR(3, 4) parse_error(JSONParserContext
*ctxt
,
67 QObject
*token
, const char *msg
, ...)
72 vsnprintf(message
, sizeof(message
), msg
, ap
);
75 error_free(ctxt
->err
);
78 error_setg(&ctxt
->err
, "JSON parse error, %s", message
);
84 * These helpers are used to unescape strings.
86 static void wchar_to_utf8(uint16_t wchar
, char *buffer
, size_t buffer_length
)
88 if (wchar
<= 0x007F) {
89 BUG_ON(buffer_length
< 2);
91 buffer
[0] = wchar
& 0x7F;
93 } else if (wchar
<= 0x07FF) {
94 BUG_ON(buffer_length
< 3);
96 buffer
[0] = 0xC0 | ((wchar
>> 6) & 0x1F);
97 buffer
[1] = 0x80 | (wchar
& 0x3F);
100 BUG_ON(buffer_length
< 4);
102 buffer
[0] = 0xE0 | ((wchar
>> 12) & 0x0F);
103 buffer
[1] = 0x80 | ((wchar
>> 6) & 0x3F);
104 buffer
[2] = 0x80 | (wchar
& 0x3F);
109 static int hex2decimal(char ch
)
111 if (ch
>= '0' && ch
<= '9') {
113 } else if (ch
>= 'a' && ch
<= 'f') {
114 return 10 + (ch
- 'a');
115 } else if (ch
>= 'A' && ch
<= 'F') {
116 return 10 + (ch
- 'A');
123 * parse_string(): Parse a json string and return a QObject
132 * any-Unicode-character-
145 static QString
*qstring_from_escaped_str(JSONParserContext
*ctxt
, QObject
*token
)
147 const char *ptr
= token_get_value(token
);
149 int double_quote
= 1;
160 ((double_quote
&& *ptr
!= '"') || (!double_quote
&& *ptr
!= '\''))) {
166 qstring_append(str
, "\"");
170 qstring_append(str
, "'");
174 qstring_append(str
, "\\");
178 qstring_append(str
, "/");
182 qstring_append(str
, "\b");
186 qstring_append(str
, "\f");
190 qstring_append(str
, "\n");
194 qstring_append(str
, "\r");
198 qstring_append(str
, "\t");
202 uint16_t unicode_char
= 0;
208 for (i
= 0; i
< 4; i
++) {
209 if (qemu_isxdigit(*ptr
)) {
210 unicode_char
|= hex2decimal(*ptr
) << ((3 - i
) * 4);
212 parse_error(ctxt
, token
,
213 "invalid hex escape sequence in string");
219 wchar_to_utf8(unicode_char
, utf8_char
, sizeof(utf8_char
));
220 qstring_append(str
, utf8_char
);
223 parse_error(ctxt
, token
, "invalid escape sequence in string");
232 qstring_append(str
, dummy
);
243 /* Note: unless the token object returned by parser_context_peek_token
244 * or parser_context_pop_token is explicitly incref'd, it will be
245 * deleted as soon as parser_context_pop_token is called again.
247 static QObject
*parser_context_pop_token(JSONParserContext
*ctxt
)
249 qobject_decref(ctxt
->current
);
250 assert(!g_queue_is_empty(ctxt
->buf
));
251 ctxt
->current
= g_queue_pop_head(ctxt
->buf
);
252 return ctxt
->current
;
255 static QObject
*parser_context_peek_token(JSONParserContext
*ctxt
)
257 assert(!g_queue_is_empty(ctxt
->buf
));
258 return g_queue_peek_head(ctxt
->buf
);
261 static JSONParserContext
*parser_context_new(GQueue
*tokens
)
263 JSONParserContext
*ctxt
;
269 ctxt
= g_malloc0(sizeof(JSONParserContext
));
275 /* to support error propagation, ctxt->err must be freed separately */
276 static void parser_context_free(JSONParserContext
*ctxt
)
279 while (!g_queue_is_empty(ctxt
->buf
)) {
280 parser_context_pop_token(ctxt
);
282 qobject_decref(ctxt
->current
);
283 g_queue_free(ctxt
->buf
);
291 static int parse_pair(JSONParserContext
*ctxt
, QDict
*dict
, va_list *ap
)
293 QObject
*key
= NULL
, *token
= NULL
, *value
, *peek
;
295 peek
= parser_context_peek_token(ctxt
);
297 parse_error(ctxt
, NULL
, "premature EOI");
301 key
= parse_value(ctxt
, ap
);
302 if (!key
|| qobject_type(key
) != QTYPE_QSTRING
) {
303 parse_error(ctxt
, peek
, "key is not a string in object");
307 token
= parser_context_pop_token(ctxt
);
309 parse_error(ctxt
, NULL
, "premature EOI");
313 if (token_get_type(token
) != JSON_COLON
) {
314 parse_error(ctxt
, token
, "missing : in object pair");
318 value
= parse_value(ctxt
, ap
);
320 parse_error(ctxt
, token
, "Missing value in dict");
324 qdict_put_obj(dict
, qstring_get_str(qobject_to_qstring(key
)), value
);
336 static QObject
*parse_object(JSONParserContext
*ctxt
, va_list *ap
)
339 QObject
*token
, *peek
;
341 token
= parser_context_pop_token(ctxt
);
342 assert(token
&& token_get_type(token
) == JSON_LCURLY
);
346 peek
= parser_context_peek_token(ctxt
);
348 parse_error(ctxt
, NULL
, "premature EOI");
352 if (token_get_type(peek
) != JSON_RCURLY
) {
353 if (parse_pair(ctxt
, dict
, ap
) == -1) {
357 token
= parser_context_pop_token(ctxt
);
359 parse_error(ctxt
, NULL
, "premature EOI");
363 while (token_get_type(token
) != JSON_RCURLY
) {
364 if (token_get_type(token
) != JSON_COMMA
) {
365 parse_error(ctxt
, token
, "expected separator in dict");
369 if (parse_pair(ctxt
, dict
, ap
) == -1) {
373 token
= parser_context_pop_token(ctxt
);
375 parse_error(ctxt
, NULL
, "premature EOI");
380 (void)parser_context_pop_token(ctxt
);
383 return QOBJECT(dict
);
390 static QObject
*parse_array(JSONParserContext
*ctxt
, va_list *ap
)
393 QObject
*token
, *peek
;
395 token
= parser_context_pop_token(ctxt
);
396 assert(token
&& token_get_type(token
) == JSON_LSQUARE
);
400 peek
= parser_context_peek_token(ctxt
);
402 parse_error(ctxt
, NULL
, "premature EOI");
406 if (token_get_type(peek
) != JSON_RSQUARE
) {
409 obj
= parse_value(ctxt
, ap
);
411 parse_error(ctxt
, token
, "expecting value");
415 qlist_append_obj(list
, obj
);
417 token
= parser_context_pop_token(ctxt
);
419 parse_error(ctxt
, NULL
, "premature EOI");
423 while (token_get_type(token
) != JSON_RSQUARE
) {
424 if (token_get_type(token
) != JSON_COMMA
) {
425 parse_error(ctxt
, token
, "expected separator in list");
429 obj
= parse_value(ctxt
, ap
);
431 parse_error(ctxt
, token
, "expecting value");
435 qlist_append_obj(list
, obj
);
437 token
= parser_context_pop_token(ctxt
);
439 parse_error(ctxt
, NULL
, "premature EOI");
444 (void)parser_context_pop_token(ctxt
);
447 return QOBJECT(list
);
454 static QObject
*parse_keyword(JSONParserContext
*ctxt
)
459 token
= parser_context_pop_token(ctxt
);
460 assert(token
&& token_get_type(token
) == JSON_KEYWORD
);
461 val
= token_get_value(token
);
463 if (!strcmp(val
, "true")) {
464 return QOBJECT(qbool_from_bool(true));
465 } else if (!strcmp(val
, "false")) {
466 return QOBJECT(qbool_from_bool(false));
467 } else if (!strcmp(val
, "null")) {
470 parse_error(ctxt
, token
, "invalid keyword '%s'", val
);
474 static QObject
*parse_escape(JSONParserContext
*ctxt
, va_list *ap
)
483 token
= parser_context_pop_token(ctxt
);
484 assert(token
&& token_get_type(token
) == JSON_ESCAPE
);
485 val
= token_get_value(token
);
487 if (!strcmp(val
, "%p")) {
488 return va_arg(*ap
, QObject
*);
489 } else if (!strcmp(val
, "%i")) {
490 return QOBJECT(qbool_from_bool(va_arg(*ap
, int)));
491 } else if (!strcmp(val
, "%d")) {
492 return QOBJECT(qint_from_int(va_arg(*ap
, int)));
493 } else if (!strcmp(val
, "%ld")) {
494 return QOBJECT(qint_from_int(va_arg(*ap
, long)));
495 } else if (!strcmp(val
, "%lld") ||
496 !strcmp(val
, "%I64d")) {
497 return QOBJECT(qint_from_int(va_arg(*ap
, long long)));
498 } else if (!strcmp(val
, "%s")) {
499 return QOBJECT(qstring_from_str(va_arg(*ap
, const char *)));
500 } else if (!strcmp(val
, "%f")) {
501 return QOBJECT(qfloat_from_double(va_arg(*ap
, double)));
506 static QObject
*parse_literal(JSONParserContext
*ctxt
)
510 token
= parser_context_pop_token(ctxt
);
513 switch (token_get_type(token
)) {
515 return QOBJECT(qstring_from_escaped_str(ctxt
, token
));
517 /* A possibility exists that this is a whole-valued float where the
518 * fractional part was left out due to being 0 (.0). It's not a big
519 * deal to treat these as ints in the parser, so long as users of the
520 * resulting QObject know to expect a QInt in place of a QFloat in
523 * However, in some cases these values will overflow/underflow a
524 * QInt/int64 container, thus we should assume these are to be handled
525 * as QFloats/doubles rather than silently changing their values.
527 * strtoll() indicates these instances by setting errno to ERANGE
531 errno
= 0; /* strtoll doesn't set errno on success */
532 value
= strtoll(token_get_value(token
), NULL
, 10);
533 if (errno
!= ERANGE
) {
534 return QOBJECT(qint_from_int(value
));
536 /* fall through to JSON_FLOAT */
539 /* FIXME dependent on locale */
540 return QOBJECT(qfloat_from_double(strtod(token_get_value(token
),
547 static QObject
*parse_value(JSONParserContext
*ctxt
, va_list *ap
)
551 token
= parser_context_peek_token(ctxt
);
553 parse_error(ctxt
, NULL
, "premature EOI");
557 switch (token_get_type(token
)) {
559 return parse_object(ctxt
, ap
);
561 return parse_array(ctxt
, ap
);
563 return parse_escape(ctxt
, ap
);
567 return parse_literal(ctxt
);
569 return parse_keyword(ctxt
);
571 parse_error(ctxt
, token
, "expecting value");
576 QObject
*json_parser_parse(GQueue
*tokens
, va_list *ap
)
578 return json_parser_parse_err(tokens
, ap
, NULL
);
581 QObject
*json_parser_parse_err(GQueue
*tokens
, va_list *ap
, Error
**errp
)
583 JSONParserContext
*ctxt
= parser_context_new(tokens
);
590 result
= parse_value(ctxt
, ap
);
592 error_propagate(errp
, ctxt
->err
);
594 parser_context_free(ctxt
);