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
36 #define BUG_ON(cond) assert(!(cond))
41 * 0) make errors meaningful again
42 * 1) add geometry information to tokens
43 * 3) should we return a parsed size?
44 * 4) deal with premature EOI
47 static QObject
*parse_value(JSONParserContext
*ctxt
, va_list *ap
);
52 * tokens are dictionaries that contain a type, a string value, and geometry information
53 * about a token identified by the lexer. These are routines that make working with
54 * these objects a bit easier.
56 static const char *token_get_value(QObject
*obj
)
58 return qdict_get_str(qobject_to_qdict(obj
), "token");
61 static JSONTokenType
token_get_type(QObject
*obj
)
63 return qdict_get_int(qobject_to_qdict(obj
), "type");
66 static int token_is_escape(QObject
*obj
, const char *value
)
68 if (token_get_type(obj
) != JSON_ESCAPE
) {
72 return (strcmp(token_get_value(obj
), value
) == 0);
78 static void GCC_FMT_ATTR(3, 4) parse_error(JSONParserContext
*ctxt
,
79 QObject
*token
, const char *msg
, ...)
84 vsnprintf(message
, sizeof(message
), msg
, ap
);
87 error_free(ctxt
->err
);
90 error_setg(&ctxt
->err
, "JSON parse error, %s", message
);
96 * These helpers are used to unescape strings.
98 static void wchar_to_utf8(uint16_t wchar
, char *buffer
, size_t buffer_length
)
100 if (wchar
<= 0x007F) {
101 BUG_ON(buffer_length
< 2);
103 buffer
[0] = wchar
& 0x7F;
105 } else if (wchar
<= 0x07FF) {
106 BUG_ON(buffer_length
< 3);
108 buffer
[0] = 0xC0 | ((wchar
>> 6) & 0x1F);
109 buffer
[1] = 0x80 | (wchar
& 0x3F);
112 BUG_ON(buffer_length
< 4);
114 buffer
[0] = 0xE0 | ((wchar
>> 12) & 0x0F);
115 buffer
[1] = 0x80 | ((wchar
>> 6) & 0x3F);
116 buffer
[2] = 0x80 | (wchar
& 0x3F);
121 static int hex2decimal(char ch
)
123 if (ch
>= '0' && ch
<= '9') {
125 } else if (ch
>= 'a' && ch
<= 'f') {
126 return 10 + (ch
- 'a');
127 } else if (ch
>= 'A' && ch
<= 'F') {
128 return 10 + (ch
- 'A');
135 * parse_string(): Parse a json string and return a QObject
144 * any-Unicode-character-
157 static QString
*qstring_from_escaped_str(JSONParserContext
*ctxt
, QObject
*token
)
159 const char *ptr
= token_get_value(token
);
161 int double_quote
= 1;
172 ((double_quote
&& *ptr
!= '"') || (!double_quote
&& *ptr
!= '\''))) {
178 qstring_append(str
, "\"");
182 qstring_append(str
, "'");
186 qstring_append(str
, "\\");
190 qstring_append(str
, "/");
194 qstring_append(str
, "\b");
198 qstring_append(str
, "\f");
202 qstring_append(str
, "\n");
206 qstring_append(str
, "\r");
210 qstring_append(str
, "\t");
214 uint16_t unicode_char
= 0;
220 for (i
= 0; i
< 4; i
++) {
221 if (qemu_isxdigit(*ptr
)) {
222 unicode_char
|= hex2decimal(*ptr
) << ((3 - i
) * 4);
224 parse_error(ctxt
, token
,
225 "invalid hex escape sequence in string");
231 wchar_to_utf8(unicode_char
, utf8_char
, sizeof(utf8_char
));
232 qstring_append(str
, utf8_char
);
235 parse_error(ctxt
, token
, "invalid escape sequence in string");
244 qstring_append(str
, dummy
);
255 static QObject
*parser_context_pop_token(JSONParserContext
*ctxt
)
258 g_assert(ctxt
->tokens
.pos
< ctxt
->tokens
.count
);
259 token
= ctxt
->tokens
.buf
[ctxt
->tokens
.pos
];
264 /* Note: parser_context_{peek|pop}_token do not increment the
265 * token object's refcount. In both cases the references will continue
266 * to be tracked and cleaned up in parser_context_free(), so do not
267 * attempt to free the token object.
269 static QObject
*parser_context_peek_token(JSONParserContext
*ctxt
)
272 g_assert(ctxt
->tokens
.pos
< ctxt
->tokens
.count
);
273 token
= ctxt
->tokens
.buf
[ctxt
->tokens
.pos
];
277 static JSONParserContext
parser_context_save(JSONParserContext
*ctxt
)
279 JSONParserContext saved_ctxt
= {0};
280 saved_ctxt
.tokens
.pos
= ctxt
->tokens
.pos
;
281 saved_ctxt
.tokens
.count
= ctxt
->tokens
.count
;
282 saved_ctxt
.tokens
.buf
= ctxt
->tokens
.buf
;
286 static void parser_context_restore(JSONParserContext
*ctxt
,
287 JSONParserContext saved_ctxt
)
289 ctxt
->tokens
.pos
= saved_ctxt
.tokens
.pos
;
290 ctxt
->tokens
.count
= saved_ctxt
.tokens
.count
;
291 ctxt
->tokens
.buf
= saved_ctxt
.tokens
.buf
;
294 static void tokens_append_from_iter(QObject
*obj
, void *opaque
)
296 JSONParserContext
*ctxt
= opaque
;
297 g_assert(ctxt
->tokens
.pos
< ctxt
->tokens
.count
);
298 ctxt
->tokens
.buf
[ctxt
->tokens
.pos
++] = obj
;
302 static JSONParserContext
*parser_context_new(QList
*tokens
)
304 JSONParserContext
*ctxt
;
311 count
= qlist_size(tokens
);
316 ctxt
= g_malloc0(sizeof(JSONParserContext
));
317 ctxt
->tokens
.pos
= 0;
318 ctxt
->tokens
.count
= count
;
319 ctxt
->tokens
.buf
= g_malloc(count
* sizeof(QObject
*));
320 qlist_iter(tokens
, tokens_append_from_iter
, ctxt
);
321 ctxt
->tokens
.pos
= 0;
326 /* to support error propagation, ctxt->err must be freed separately */
327 static void parser_context_free(JSONParserContext
*ctxt
)
331 for (i
= 0; i
< ctxt
->tokens
.count
; i
++) {
332 qobject_decref(ctxt
->tokens
.buf
[i
]);
334 g_free(ctxt
->tokens
.buf
);
342 static int parse_pair(JSONParserContext
*ctxt
, QDict
*dict
, va_list *ap
)
344 QObject
*key
= NULL
, *token
= NULL
, *value
, *peek
;
345 JSONParserContext saved_ctxt
= parser_context_save(ctxt
);
347 peek
= parser_context_peek_token(ctxt
);
349 parse_error(ctxt
, NULL
, "premature EOI");
353 key
= parse_value(ctxt
, ap
);
354 if (!key
|| qobject_type(key
) != QTYPE_QSTRING
) {
355 parse_error(ctxt
, peek
, "key is not a string in object");
359 token
= parser_context_pop_token(ctxt
);
361 parse_error(ctxt
, NULL
, "premature EOI");
365 if (token_get_type(token
) != JSON_COLON
) {
366 parse_error(ctxt
, token
, "missing : in object pair");
370 value
= parse_value(ctxt
, ap
);
372 parse_error(ctxt
, token
, "Missing value in dict");
376 qdict_put_obj(dict
, qstring_get_str(qobject_to_qstring(key
)), value
);
383 parser_context_restore(ctxt
, saved_ctxt
);
389 static QObject
*parse_object(JSONParserContext
*ctxt
, va_list *ap
)
392 QObject
*token
, *peek
;
393 JSONParserContext saved_ctxt
= parser_context_save(ctxt
);
395 token
= parser_context_pop_token(ctxt
);
400 if (token_get_type(token
) != JSON_LCURLY
) {
406 peek
= parser_context_peek_token(ctxt
);
408 parse_error(ctxt
, NULL
, "premature EOI");
412 if (token_get_type(peek
) != JSON_RCURLY
) {
413 if (parse_pair(ctxt
, dict
, ap
) == -1) {
417 token
= parser_context_pop_token(ctxt
);
419 parse_error(ctxt
, NULL
, "premature EOI");
423 while (token_get_type(token
) != JSON_RCURLY
) {
424 if (token_get_type(token
) != JSON_COMMA
) {
425 parse_error(ctxt
, token
, "expected separator in dict");
429 if (parse_pair(ctxt
, dict
, ap
) == -1) {
433 token
= parser_context_pop_token(ctxt
);
435 parse_error(ctxt
, NULL
, "premature EOI");
440 (void)parser_context_pop_token(ctxt
);
443 return QOBJECT(dict
);
446 parser_context_restore(ctxt
, saved_ctxt
);
451 static QObject
*parse_array(JSONParserContext
*ctxt
, va_list *ap
)
454 QObject
*token
, *peek
;
455 JSONParserContext saved_ctxt
= parser_context_save(ctxt
);
457 token
= parser_context_pop_token(ctxt
);
462 if (token_get_type(token
) != JSON_LSQUARE
) {
468 peek
= parser_context_peek_token(ctxt
);
470 parse_error(ctxt
, NULL
, "premature EOI");
474 if (token_get_type(peek
) != JSON_RSQUARE
) {
477 obj
= parse_value(ctxt
, ap
);
479 parse_error(ctxt
, token
, "expecting value");
483 qlist_append_obj(list
, obj
);
485 token
= parser_context_pop_token(ctxt
);
487 parse_error(ctxt
, NULL
, "premature EOI");
491 while (token_get_type(token
) != JSON_RSQUARE
) {
492 if (token_get_type(token
) != JSON_COMMA
) {
493 parse_error(ctxt
, token
, "expected separator in list");
497 obj
= parse_value(ctxt
, ap
);
499 parse_error(ctxt
, token
, "expecting value");
503 qlist_append_obj(list
, obj
);
505 token
= parser_context_pop_token(ctxt
);
507 parse_error(ctxt
, NULL
, "premature EOI");
512 (void)parser_context_pop_token(ctxt
);
515 return QOBJECT(list
);
518 parser_context_restore(ctxt
, saved_ctxt
);
523 static QObject
*parse_keyword(JSONParserContext
*ctxt
)
525 QObject
*token
, *ret
;
526 JSONParserContext saved_ctxt
= parser_context_save(ctxt
);
529 token
= parser_context_pop_token(ctxt
);
534 if (token_get_type(token
) != JSON_KEYWORD
) {
538 val
= token_get_value(token
);
540 if (!strcmp(val
, "true")) {
541 ret
= QOBJECT(qbool_from_bool(true));
542 } else if (!strcmp(val
, "false")) {
543 ret
= QOBJECT(qbool_from_bool(false));
544 } else if (!strcmp(val
, "null")) {
547 parse_error(ctxt
, token
, "invalid keyword '%s'", val
);
554 parser_context_restore(ctxt
, saved_ctxt
);
559 static QObject
*parse_escape(JSONParserContext
*ctxt
, va_list *ap
)
561 QObject
*token
= NULL
, *obj
;
562 JSONParserContext saved_ctxt
= parser_context_save(ctxt
);
568 token
= parser_context_pop_token(ctxt
);
573 if (token_is_escape(token
, "%p")) {
574 obj
= va_arg(*ap
, QObject
*);
575 } else if (token_is_escape(token
, "%i")) {
576 obj
= QOBJECT(qbool_from_bool(va_arg(*ap
, int)));
577 } else if (token_is_escape(token
, "%d")) {
578 obj
= QOBJECT(qint_from_int(va_arg(*ap
, int)));
579 } else if (token_is_escape(token
, "%ld")) {
580 obj
= QOBJECT(qint_from_int(va_arg(*ap
, long)));
581 } else if (token_is_escape(token
, "%lld") ||
582 token_is_escape(token
, "%I64d")) {
583 obj
= QOBJECT(qint_from_int(va_arg(*ap
, long long)));
584 } else if (token_is_escape(token
, "%s")) {
585 obj
= QOBJECT(qstring_from_str(va_arg(*ap
, const char *)));
586 } else if (token_is_escape(token
, "%f")) {
587 obj
= QOBJECT(qfloat_from_double(va_arg(*ap
, double)));
595 parser_context_restore(ctxt
, saved_ctxt
);
600 static QObject
*parse_literal(JSONParserContext
*ctxt
)
602 QObject
*token
, *obj
;
603 JSONParserContext saved_ctxt
= parser_context_save(ctxt
);
605 token
= parser_context_pop_token(ctxt
);
610 switch (token_get_type(token
)) {
612 obj
= QOBJECT(qstring_from_escaped_str(ctxt
, token
));
615 /* A possibility exists that this is a whole-valued float where the
616 * fractional part was left out due to being 0 (.0). It's not a big
617 * deal to treat these as ints in the parser, so long as users of the
618 * resulting QObject know to expect a QInt in place of a QFloat in
621 * However, in some cases these values will overflow/underflow a
622 * QInt/int64 container, thus we should assume these are to be handled
623 * as QFloats/doubles rather than silently changing their values.
625 * strtoll() indicates these instances by setting errno to ERANGE
629 errno
= 0; /* strtoll doesn't set errno on success */
630 value
= strtoll(token_get_value(token
), NULL
, 10);
631 if (errno
!= ERANGE
) {
632 obj
= QOBJECT(qint_from_int(value
));
635 /* fall through to JSON_FLOAT */
638 /* FIXME dependent on locale */
639 obj
= QOBJECT(qfloat_from_double(strtod(token_get_value(token
), NULL
)));
648 parser_context_restore(ctxt
, saved_ctxt
);
653 static QObject
*parse_value(JSONParserContext
*ctxt
, va_list *ap
)
657 obj
= parse_object(ctxt
, ap
);
659 obj
= parse_array(ctxt
, ap
);
662 obj
= parse_escape(ctxt
, ap
);
665 obj
= parse_keyword(ctxt
);
668 obj
= parse_literal(ctxt
);
674 QObject
*json_parser_parse(QList
*tokens
, va_list *ap
)
676 return json_parser_parse_err(tokens
, ap
, NULL
);
679 QObject
*json_parser_parse_err(QList
*tokens
, va_list *ap
, Error
**errp
)
681 JSONParserContext
*ctxt
= parser_context_new(tokens
);
688 result
= parse_value(ctxt
, ap
);
690 error_propagate(errp
, ctxt
->err
);
692 parser_context_free(ctxt
);