blob: a9b227f56cb08b6a470982197ea3023c732e28fb [file] [log] [blame]
Anthony Liguori4a5fcab2009-11-11 10:39:23 -06001/*
Eric Blake6e8e5cb2016-01-29 06:48:37 -07002 * JSON Parser
Anthony Liguori4a5fcab2009-11-11 10:39:23 -06003 *
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
Peter Maydellf2ad72b2016-01-29 17:50:01 +000014#include "qemu/osdep.h"
Marc-André Lureau2bc7cfe2017-06-07 20:36:02 +040015#include "qemu/cutils.h"
Markus Armbrustere59f39d2018-08-23 18:39:49 +020016#include "qemu/unicode.h"
Markus Armbrusterda34e652016-03-14 09:01:28 +010017#include "qapi/error.h"
Anthony Liguori4a5fcab2009-11-11 10:39:23 -060018#include "qemu-common.h"
Markus Armbruster6b673952018-02-01 12:18:35 +010019#include "qapi/qmp/qbool.h"
Markus Armbruster452fcdb2018-02-01 12:18:39 +010020#include "qapi/qmp/qdict.h"
Markus Armbruster47e6b292018-02-01 12:18:38 +010021#include "qapi/qmp/qlist.h"
Markus Armbruster15280c32018-02-01 12:18:36 +010022#include "qapi/qmp/qnull.h"
23#include "qapi/qmp/qnum.h"
Markus Armbruster6b673952018-02-01 12:18:35 +010024#include "qapi/qmp/qstring.h"
Paolo Bonzini7b1b5d12012-12-17 18:19:43 +010025#include "qapi/qmp/json-parser.h"
26#include "qapi/qmp/json-lexer.h"
Paolo Bonzini9bada892015-11-25 22:23:32 +010027#include "qapi/qmp/json-streamer.h"
Anthony Liguori4a5fcab2009-11-11 10:39:23 -060028
29typedef struct JSONParserContext
30{
Anthony Liguorief749d02011-06-01 12:14:50 -050031 Error *err;
Paolo Bonzini9bada892015-11-25 22:23:32 +010032 JSONToken *current;
Paolo Bonzini95385fe2015-11-25 22:23:31 +010033 GQueue *buf;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -060034} JSONParserContext;
35
36#define BUG_ON(cond) assert(!(cond))
37
38/**
39 * TODO
40 *
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
45 */
46
Michael Roth65c0f1e2012-08-15 13:45:43 -050047static QObject *parse_value(JSONParserContext *ctxt, va_list *ap);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -060048
49/**
Anthony Liguori4a5fcab2009-11-11 10:39:23 -060050 * Error handler
51 */
Stefan Weil8b7968f2010-09-23 21:28:05 +020052static void GCC_FMT_ATTR(3, 4) parse_error(JSONParserContext *ctxt,
Paolo Bonzini9bada892015-11-25 22:23:32 +010053 JSONToken *token, const char *msg, ...)
Anthony Liguori4a5fcab2009-11-11 10:39:23 -060054{
Amos Kongc96c84a2010-03-24 23:12:05 +080055 va_list ap;
Anthony Liguorief749d02011-06-01 12:14:50 -050056 char message[1024];
Markus Armbruster574bf162018-08-23 18:39:50 +020057
58 if (ctxt->err) {
59 return;
60 }
Amos Kongc96c84a2010-03-24 23:12:05 +080061 va_start(ap, msg);
Anthony Liguorief749d02011-06-01 12:14:50 -050062 vsnprintf(message, sizeof(message), msg, ap);
Amos Kongc96c84a2010-03-24 23:12:05 +080063 va_end(ap);
Cole Robinsonf231b882014-03-21 19:42:26 -040064 error_setg(&ctxt->err, "JSON parse error, %s", message);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -060065}
66
67/**
68 * String helpers
69 *
70 * These helpers are used to unescape strings.
71 */
72static void wchar_to_utf8(uint16_t wchar, char *buffer, size_t buffer_length)
73{
74 if (wchar <= 0x007F) {
75 BUG_ON(buffer_length < 2);
76
77 buffer[0] = wchar & 0x7F;
78 buffer[1] = 0;
79 } else if (wchar <= 0x07FF) {
80 BUG_ON(buffer_length < 3);
81
82 buffer[0] = 0xC0 | ((wchar >> 6) & 0x1F);
83 buffer[1] = 0x80 | (wchar & 0x3F);
84 buffer[2] = 0;
85 } else {
86 BUG_ON(buffer_length < 4);
87
88 buffer[0] = 0xE0 | ((wchar >> 12) & 0x0F);
89 buffer[1] = 0x80 | ((wchar >> 6) & 0x3F);
90 buffer[2] = 0x80 | (wchar & 0x3F);
91 buffer[3] = 0;
92 }
93}
94
95static int hex2decimal(char ch)
96{
97 if (ch >= '0' && ch <= '9') {
98 return (ch - '0');
99 } else if (ch >= 'a' && ch <= 'f') {
100 return 10 + (ch - 'a');
101 } else if (ch >= 'A' && ch <= 'F') {
102 return 10 + (ch - 'A');
103 }
104
105 return -1;
106}
107
108/**
109 * parse_string(): Parse a json string and return a QObject
110 *
111 * string
112 * ""
113 * " chars "
114 * chars
115 * char
116 * char chars
117 * char
118 * any-Unicode-character-
119 * except-"-or-\-or-
120 * control-character
121 * \"
122 * \\
123 * \/
124 * \b
125 * \f
126 * \n
127 * \r
128 * \t
129 * \u four-hex-digits
130 */
Paolo Bonzini9bada892015-11-25 22:23:32 +0100131static QString *qstring_from_escaped_str(JSONParserContext *ctxt,
132 JSONToken *token)
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600133{
Paolo Bonzini9bada892015-11-25 22:23:32 +0100134 const char *ptr = token->str;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600135 QString *str;
Markus Armbruster00ea57f2018-08-23 18:39:47 +0200136 char quote;
Markus Armbrustere59f39d2018-08-23 18:39:49 +0200137 int cp;
138 char *end;
139 ssize_t len;
140 char utf8_buf[5];
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600141
Markus Armbruster00ea57f2018-08-23 18:39:47 +0200142 assert(*ptr == '"' || *ptr == '\'');
143 quote = *ptr++;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600144 str = qstring_new();
Markus Armbruster00ea57f2018-08-23 18:39:47 +0200145
146 while (*ptr != quote) {
147 assert(*ptr);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600148 if (*ptr == '\\') {
149 ptr++;
Markus Armbruster00ea57f2018-08-23 18:39:47 +0200150 switch (*ptr++) {
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600151 case '"':
152 qstring_append(str, "\"");
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600153 break;
154 case '\'':
155 qstring_append(str, "'");
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600156 break;
157 case '\\':
158 qstring_append(str, "\\");
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600159 break;
160 case '/':
161 qstring_append(str, "/");
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600162 break;
163 case 'b':
164 qstring_append(str, "\b");
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600165 break;
Luiz Capitulinobd032692010-05-19 17:06:15 -0300166 case 'f':
167 qstring_append(str, "\f");
Luiz Capitulinobd032692010-05-19 17:06:15 -0300168 break;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600169 case 'n':
170 qstring_append(str, "\n");
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600171 break;
172 case 'r':
173 qstring_append(str, "\r");
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600174 break;
175 case 't':
176 qstring_append(str, "\t");
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600177 break;
178 case 'u': {
179 uint16_t unicode_char = 0;
180 char utf8_char[4];
181 int i = 0;
182
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600183 for (i = 0; i < 4; i++) {
184 if (qemu_isxdigit(*ptr)) {
185 unicode_char |= hex2decimal(*ptr) << ((3 - i) * 4);
186 } else {
187 parse_error(ctxt, token,
188 "invalid hex escape sequence in string");
189 goto out;
190 }
191 ptr++;
192 }
193
194 wchar_to_utf8(unicode_char, utf8_char, sizeof(utf8_char));
195 qstring_append(str, utf8_char);
196 } break;
197 default:
198 parse_error(ctxt, token, "invalid escape sequence in string");
199 goto out;
200 }
201 } else {
Markus Armbrustere59f39d2018-08-23 18:39:49 +0200202 cp = mod_utf8_codepoint(ptr, 6, &end);
Markus Armbruster4b1c0cd2018-08-23 18:39:52 +0200203 if (cp < 0) {
Markus Armbrustere59f39d2018-08-23 18:39:49 +0200204 parse_error(ctxt, token, "invalid UTF-8 sequence in string");
205 goto out;
206 }
207 ptr = end;
208 len = mod_utf8_encode(utf8_buf, sizeof(utf8_buf), cp);
209 assert(len >= 0);
210 qstring_append(str, utf8_buf);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600211 }
212 }
213
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600214 return str;
215
216out:
Marc-André Lureaucb3e7f02018-04-19 17:01:43 +0200217 qobject_unref(str);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600218 return NULL;
219}
220
Paolo Bonzini9bada892015-11-25 22:23:32 +0100221/* Note: the token object returned by parser_context_peek_token or
222 * parser_context_pop_token is deleted as soon as parser_context_pop_token
223 * is called again.
Paolo Bonzini95385fe2015-11-25 22:23:31 +0100224 */
Paolo Bonzini9bada892015-11-25 22:23:32 +0100225static JSONToken *parser_context_pop_token(JSONParserContext *ctxt)
Michael Roth65c0f1e2012-08-15 13:45:43 -0500226{
Paolo Bonzini9bada892015-11-25 22:23:32 +0100227 g_free(ctxt->current);
Paolo Bonzini95385fe2015-11-25 22:23:31 +0100228 assert(!g_queue_is_empty(ctxt->buf));
229 ctxt->current = g_queue_pop_head(ctxt->buf);
230 return ctxt->current;
Michael Roth65c0f1e2012-08-15 13:45:43 -0500231}
232
Paolo Bonzini9bada892015-11-25 22:23:32 +0100233static JSONToken *parser_context_peek_token(JSONParserContext *ctxt)
Michael Roth65c0f1e2012-08-15 13:45:43 -0500234{
Paolo Bonzini95385fe2015-11-25 22:23:31 +0100235 assert(!g_queue_is_empty(ctxt->buf));
236 return g_queue_peek_head(ctxt->buf);
Michael Roth65c0f1e2012-08-15 13:45:43 -0500237}
238
Paolo Bonzini95385fe2015-11-25 22:23:31 +0100239static JSONParserContext *parser_context_new(GQueue *tokens)
Michael Roth65c0f1e2012-08-15 13:45:43 -0500240{
241 JSONParserContext *ctxt;
Michael Roth65c0f1e2012-08-15 13:45:43 -0500242
243 if (!tokens) {
244 return NULL;
245 }
246
Michael Roth65c0f1e2012-08-15 13:45:43 -0500247 ctxt = g_malloc0(sizeof(JSONParserContext));
Paolo Bonzini95385fe2015-11-25 22:23:31 +0100248 ctxt->buf = tokens;
Michael Roth65c0f1e2012-08-15 13:45:43 -0500249
250 return ctxt;
251}
252
253/* to support error propagation, ctxt->err must be freed separately */
254static void parser_context_free(JSONParserContext *ctxt)
255{
Michael Roth65c0f1e2012-08-15 13:45:43 -0500256 if (ctxt) {
Paolo Bonzini95385fe2015-11-25 22:23:31 +0100257 while (!g_queue_is_empty(ctxt->buf)) {
258 parser_context_pop_token(ctxt);
Michael Roth65c0f1e2012-08-15 13:45:43 -0500259 }
Paolo Bonzini9bada892015-11-25 22:23:32 +0100260 g_free(ctxt->current);
Paolo Bonzini95385fe2015-11-25 22:23:31 +0100261 g_queue_free(ctxt->buf);
Michael Roth65c0f1e2012-08-15 13:45:43 -0500262 g_free(ctxt);
263 }
264}
265
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600266/**
267 * Parsing rules
268 */
Michael Roth65c0f1e2012-08-15 13:45:43 -0500269static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap)
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600270{
Max Reitz532fb532018-03-10 16:14:36 -0600271 QObject *value;
272 QString *key = NULL;
Paolo Bonzini9bada892015-11-25 22:23:32 +0100273 JSONToken *peek, *token;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600274
Michael Roth65c0f1e2012-08-15 13:45:43 -0500275 peek = parser_context_peek_token(ctxt);
Anthony Liguori11e8a462011-06-01 12:14:55 -0500276 if (peek == NULL) {
277 parse_error(ctxt, NULL, "premature EOI");
278 goto out;
279 }
280
Max Reitz532fb532018-03-10 16:14:36 -0600281 key = qobject_to(QString, parse_value(ctxt, ap));
282 if (!key) {
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600283 parse_error(ctxt, peek, "key is not a string in object");
284 goto out;
285 }
286
Michael Roth65c0f1e2012-08-15 13:45:43 -0500287 token = parser_context_pop_token(ctxt);
Anthony Liguori11e8a462011-06-01 12:14:55 -0500288 if (token == NULL) {
289 parse_error(ctxt, NULL, "premature EOI");
290 goto out;
291 }
292
Paolo Bonzini9bada892015-11-25 22:23:32 +0100293 if (token->type != JSON_COLON) {
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600294 parse_error(ctxt, token, "missing : in object pair");
295 goto out;
296 }
297
Michael Roth65c0f1e2012-08-15 13:45:43 -0500298 value = parse_value(ctxt, ap);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600299 if (value == NULL) {
300 parse_error(ctxt, token, "Missing value in dict");
301 goto out;
302 }
303
Max Reitz532fb532018-03-10 16:14:36 -0600304 qdict_put_obj(dict, qstring_get_str(key), value);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600305
Marc-André Lureaucb3e7f02018-04-19 17:01:43 +0200306 qobject_unref(key);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600307
308 return 0;
309
310out:
Marc-André Lureaucb3e7f02018-04-19 17:01:43 +0200311 qobject_unref(key);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600312
313 return -1;
314}
315
Michael Roth65c0f1e2012-08-15 13:45:43 -0500316static QObject *parse_object(JSONParserContext *ctxt, va_list *ap)
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600317{
318 QDict *dict = NULL;
Paolo Bonzini9bada892015-11-25 22:23:32 +0100319 JSONToken *token, *peek;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600320
Michael Roth65c0f1e2012-08-15 13:45:43 -0500321 token = parser_context_pop_token(ctxt);
Paolo Bonzini9bada892015-11-25 22:23:32 +0100322 assert(token && token->type == JSON_LCURLY);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600323
324 dict = qdict_new();
325
Michael Roth65c0f1e2012-08-15 13:45:43 -0500326 peek = parser_context_peek_token(ctxt);
Anthony Liguori11e8a462011-06-01 12:14:55 -0500327 if (peek == NULL) {
328 parse_error(ctxt, NULL, "premature EOI");
329 goto out;
330 }
331
Paolo Bonzini9bada892015-11-25 22:23:32 +0100332 if (peek->type != JSON_RCURLY) {
Michael Roth65c0f1e2012-08-15 13:45:43 -0500333 if (parse_pair(ctxt, dict, ap) == -1) {
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600334 goto out;
335 }
336
Michael Roth65c0f1e2012-08-15 13:45:43 -0500337 token = parser_context_pop_token(ctxt);
Anthony Liguori11e8a462011-06-01 12:14:55 -0500338 if (token == NULL) {
339 parse_error(ctxt, NULL, "premature EOI");
340 goto out;
341 }
342
Paolo Bonzini9bada892015-11-25 22:23:32 +0100343 while (token->type != JSON_RCURLY) {
344 if (token->type != JSON_COMMA) {
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600345 parse_error(ctxt, token, "expected separator in dict");
346 goto out;
347 }
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600348
Michael Roth65c0f1e2012-08-15 13:45:43 -0500349 if (parse_pair(ctxt, dict, ap) == -1) {
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600350 goto out;
351 }
352
Michael Roth65c0f1e2012-08-15 13:45:43 -0500353 token = parser_context_pop_token(ctxt);
Anthony Liguori11e8a462011-06-01 12:14:55 -0500354 if (token == NULL) {
355 parse_error(ctxt, NULL, "premature EOI");
356 goto out;
357 }
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600358 }
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600359 } else {
Gongleia491af42014-06-10 17:20:24 +0800360 (void)parser_context_pop_token(ctxt);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600361 }
362
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600363 return QOBJECT(dict);
364
365out:
Marc-André Lureaucb3e7f02018-04-19 17:01:43 +0200366 qobject_unref(dict);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600367 return NULL;
368}
369
Michael Roth65c0f1e2012-08-15 13:45:43 -0500370static QObject *parse_array(JSONParserContext *ctxt, va_list *ap)
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600371{
372 QList *list = NULL;
Paolo Bonzini9bada892015-11-25 22:23:32 +0100373 JSONToken *token, *peek;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600374
Michael Roth65c0f1e2012-08-15 13:45:43 -0500375 token = parser_context_pop_token(ctxt);
Paolo Bonzini9bada892015-11-25 22:23:32 +0100376 assert(token && token->type == JSON_LSQUARE);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600377
378 list = qlist_new();
379
Michael Roth65c0f1e2012-08-15 13:45:43 -0500380 peek = parser_context_peek_token(ctxt);
Anthony Liguori11e8a462011-06-01 12:14:55 -0500381 if (peek == NULL) {
382 parse_error(ctxt, NULL, "premature EOI");
383 goto out;
384 }
385
Paolo Bonzini9bada892015-11-25 22:23:32 +0100386 if (peek->type != JSON_RSQUARE) {
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600387 QObject *obj;
388
Michael Roth65c0f1e2012-08-15 13:45:43 -0500389 obj = parse_value(ctxt, ap);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600390 if (obj == NULL) {
391 parse_error(ctxt, token, "expecting value");
392 goto out;
393 }
394
395 qlist_append_obj(list, obj);
396
Michael Roth65c0f1e2012-08-15 13:45:43 -0500397 token = parser_context_pop_token(ctxt);
Anthony Liguori11e8a462011-06-01 12:14:55 -0500398 if (token == NULL) {
399 parse_error(ctxt, NULL, "premature EOI");
400 goto out;
401 }
402
Paolo Bonzini9bada892015-11-25 22:23:32 +0100403 while (token->type != JSON_RSQUARE) {
404 if (token->type != JSON_COMMA) {
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600405 parse_error(ctxt, token, "expected separator in list");
406 goto out;
407 }
408
Michael Roth65c0f1e2012-08-15 13:45:43 -0500409 obj = parse_value(ctxt, ap);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600410 if (obj == NULL) {
411 parse_error(ctxt, token, "expecting value");
412 goto out;
413 }
414
415 qlist_append_obj(list, obj);
416
Michael Roth65c0f1e2012-08-15 13:45:43 -0500417 token = parser_context_pop_token(ctxt);
Anthony Liguori11e8a462011-06-01 12:14:55 -0500418 if (token == NULL) {
419 parse_error(ctxt, NULL, "premature EOI");
420 goto out;
421 }
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600422 }
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600423 } else {
Gongleia491af42014-06-10 17:20:24 +0800424 (void)parser_context_pop_token(ctxt);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600425 }
426
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600427 return QOBJECT(list);
428
429out:
Marc-André Lureaucb3e7f02018-04-19 17:01:43 +0200430 qobject_unref(list);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600431 return NULL;
432}
433
Michael Roth65c0f1e2012-08-15 13:45:43 -0500434static QObject *parse_keyword(JSONParserContext *ctxt)
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600435{
Paolo Bonzini9bada892015-11-25 22:23:32 +0100436 JSONToken *token;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600437
Michael Roth65c0f1e2012-08-15 13:45:43 -0500438 token = parser_context_pop_token(ctxt);
Paolo Bonzini9bada892015-11-25 22:23:32 +0100439 assert(token && token->type == JSON_KEYWORD);
Markus Armbruster50e2a462015-11-25 22:23:27 +0100440
Paolo Bonzini9bada892015-11-25 22:23:32 +0100441 if (!strcmp(token->str, "true")) {
Markus Armbrusterd538b252015-11-25 22:23:30 +0100442 return QOBJECT(qbool_from_bool(true));
Paolo Bonzini9bada892015-11-25 22:23:32 +0100443 } else if (!strcmp(token->str, "false")) {
Markus Armbrusterd538b252015-11-25 22:23:30 +0100444 return QOBJECT(qbool_from_bool(false));
Paolo Bonzini9bada892015-11-25 22:23:32 +0100445 } else if (!strcmp(token->str, "null")) {
Markus Armbruster006ca092017-06-26 13:52:24 +0200446 return QOBJECT(qnull());
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600447 }
Paolo Bonzini9bada892015-11-25 22:23:32 +0100448 parse_error(ctxt, token, "invalid keyword '%s'", token->str);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600449 return NULL;
450}
451
Michael Roth65c0f1e2012-08-15 13:45:43 -0500452static QObject *parse_escape(JSONParserContext *ctxt, va_list *ap)
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600453{
Paolo Bonzini9bada892015-11-25 22:23:32 +0100454 JSONToken *token;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600455
456 if (ap == NULL) {
Markus Armbrusterd538b252015-11-25 22:23:30 +0100457 return NULL;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600458 }
459
Michael Roth65c0f1e2012-08-15 13:45:43 -0500460 token = parser_context_pop_token(ctxt);
Paolo Bonzini9bada892015-11-25 22:23:32 +0100461 assert(token && token->type == JSON_ESCAPE);
Markus Armbruster6b9606f2015-11-25 22:23:28 +0100462
Paolo Bonzini9bada892015-11-25 22:23:32 +0100463 if (!strcmp(token->str, "%p")) {
Markus Armbrusterd538b252015-11-25 22:23:30 +0100464 return va_arg(*ap, QObject *);
Paolo Bonzini9bada892015-11-25 22:23:32 +0100465 } else if (!strcmp(token->str, "%i")) {
Markus Armbrusterd538b252015-11-25 22:23:30 +0100466 return QOBJECT(qbool_from_bool(va_arg(*ap, int)));
Paolo Bonzini9bada892015-11-25 22:23:32 +0100467 } else if (!strcmp(token->str, "%d")) {
Marc-André Lureau01b2ffc2017-06-07 20:35:58 +0400468 return QOBJECT(qnum_from_int(va_arg(*ap, int)));
Paolo Bonzini9bada892015-11-25 22:23:32 +0100469 } else if (!strcmp(token->str, "%ld")) {
Marc-André Lureau01b2ffc2017-06-07 20:35:58 +0400470 return QOBJECT(qnum_from_int(va_arg(*ap, long)));
Paolo Bonzini9bada892015-11-25 22:23:32 +0100471 } else if (!strcmp(token->str, "%lld") ||
472 !strcmp(token->str, "%I64d")) {
Marc-André Lureau01b2ffc2017-06-07 20:35:58 +0400473 return QOBJECT(qnum_from_int(va_arg(*ap, long long)));
Marc-André Lureau2bc7cfe2017-06-07 20:36:02 +0400474 } else if (!strcmp(token->str, "%u")) {
475 return QOBJECT(qnum_from_uint(va_arg(*ap, unsigned int)));
476 } else if (!strcmp(token->str, "%lu")) {
477 return QOBJECT(qnum_from_uint(va_arg(*ap, unsigned long)));
478 } else if (!strcmp(token->str, "%llu") ||
479 !strcmp(token->str, "%I64u")) {
480 return QOBJECT(qnum_from_uint(va_arg(*ap, unsigned long long)));
Paolo Bonzini9bada892015-11-25 22:23:32 +0100481 } else if (!strcmp(token->str, "%s")) {
Markus Armbrusterd538b252015-11-25 22:23:30 +0100482 return QOBJECT(qstring_from_str(va_arg(*ap, const char *)));
Paolo Bonzini9bada892015-11-25 22:23:32 +0100483 } else if (!strcmp(token->str, "%f")) {
Marc-André Lureau01b2ffc2017-06-07 20:35:58 +0400484 return QOBJECT(qnum_from_double(va_arg(*ap, double)));
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600485 }
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600486 return NULL;
487}
488
Michael Roth65c0f1e2012-08-15 13:45:43 -0500489static QObject *parse_literal(JSONParserContext *ctxt)
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600490{
Paolo Bonzini9bada892015-11-25 22:23:32 +0100491 JSONToken *token;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600492
Michael Roth65c0f1e2012-08-15 13:45:43 -0500493 token = parser_context_pop_token(ctxt);
Markus Armbrusterd538b252015-11-25 22:23:30 +0100494 assert(token);
Anthony Liguori11e8a462011-06-01 12:14:55 -0500495
Paolo Bonzini9bada892015-11-25 22:23:32 +0100496 switch (token->type) {
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600497 case JSON_STRING:
Markus Armbrusterd538b252015-11-25 22:23:30 +0100498 return QOBJECT(qstring_from_escaped_str(ctxt, token));
Michael Roth3d5b3ec2013-05-10 17:46:05 -0500499 case JSON_INTEGER: {
Marc-André Lureau01b2ffc2017-06-07 20:35:58 +0400500 /*
501 * Represent JSON_INTEGER as QNUM_I64 if possible, else as
Marc-André Lureau2bc7cfe2017-06-07 20:36:02 +0400502 * QNUM_U64, else as QNUM_DOUBLE. Note that qemu_strtoi64()
503 * and qemu_strtou64() fail with ERANGE when it's not
504 * possible.
Michael Roth3d5b3ec2013-05-10 17:46:05 -0500505 *
Marc-André Lureau01b2ffc2017-06-07 20:35:58 +0400506 * qnum_get_int() will then work for any signed 64-bit
Marc-André Lureau2bc7cfe2017-06-07 20:36:02 +0400507 * JSON_INTEGER, qnum_get_uint() for any unsigned 64-bit
508 * integer, and qnum_get_double() both for any JSON_INTEGER
509 * and any JSON_FLOAT (with precision loss for integers beyond
510 * 53 bits)
Michael Roth3d5b3ec2013-05-10 17:46:05 -0500511 */
Marc-André Lureau2bc7cfe2017-06-07 20:36:02 +0400512 int ret;
Michael Roth3d5b3ec2013-05-10 17:46:05 -0500513 int64_t value;
Marc-André Lureau2bc7cfe2017-06-07 20:36:02 +0400514 uint64_t uvalue;
Michael Roth3d5b3ec2013-05-10 17:46:05 -0500515
Marc-André Lureau2bc7cfe2017-06-07 20:36:02 +0400516 ret = qemu_strtoi64(token->str, NULL, 10, &value);
517 if (!ret) {
Marc-André Lureau01b2ffc2017-06-07 20:35:58 +0400518 return QOBJECT(qnum_from_int(value));
Michael Roth3d5b3ec2013-05-10 17:46:05 -0500519 }
Marc-André Lureau2bc7cfe2017-06-07 20:36:02 +0400520 assert(ret == -ERANGE);
521
522 if (token->str[0] != '-') {
523 ret = qemu_strtou64(token->str, NULL, 10, &uvalue);
524 if (!ret) {
525 return QOBJECT(qnum_from_uint(uvalue));
526 }
527 assert(ret == -ERANGE);
528 }
Michael Roth3d5b3ec2013-05-10 17:46:05 -0500529 /* fall through to JSON_FLOAT */
530 }
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600531 case JSON_FLOAT:
Eric Blake6e8e5cb2016-01-29 06:48:37 -0700532 /* FIXME dependent on locale; a pervasive issue in QEMU */
533 /* FIXME our lexer matches RFC 7159 in forbidding Inf or NaN,
534 * but those might be useful extensions beyond JSON */
Marc-André Lureau01b2ffc2017-06-07 20:35:58 +0400535 return QOBJECT(qnum_from_double(strtod(token->str, NULL)));
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600536 default:
Markus Armbrusterd538b252015-11-25 22:23:30 +0100537 abort();
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600538 }
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600539}
540
Michael Roth65c0f1e2012-08-15 13:45:43 -0500541static QObject *parse_value(JSONParserContext *ctxt, va_list *ap)
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600542{
Paolo Bonzini9bada892015-11-25 22:23:32 +0100543 JSONToken *token;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600544
Markus Armbrusterd538b252015-11-25 22:23:30 +0100545 token = parser_context_peek_token(ctxt);
546 if (token == NULL) {
547 parse_error(ctxt, NULL, "premature EOI");
548 return NULL;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600549 }
550
Paolo Bonzini9bada892015-11-25 22:23:32 +0100551 switch (token->type) {
Markus Armbrusterd538b252015-11-25 22:23:30 +0100552 case JSON_LCURLY:
553 return parse_object(ctxt, ap);
554 case JSON_LSQUARE:
555 return parse_array(ctxt, ap);
556 case JSON_ESCAPE:
557 return parse_escape(ctxt, ap);
558 case JSON_INTEGER:
559 case JSON_FLOAT:
560 case JSON_STRING:
561 return parse_literal(ctxt);
562 case JSON_KEYWORD:
563 return parse_keyword(ctxt);
564 default:
565 parse_error(ctxt, token, "expecting value");
566 return NULL;
567 }
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600568}
569
Paolo Bonzini95385fe2015-11-25 22:23:31 +0100570QObject *json_parser_parse(GQueue *tokens, va_list *ap)
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600571{
Anthony Liguorief749d02011-06-01 12:14:50 -0500572 return json_parser_parse_err(tokens, ap, NULL);
573}
574
Paolo Bonzini95385fe2015-11-25 22:23:31 +0100575QObject *json_parser_parse_err(GQueue *tokens, va_list *ap, Error **errp)
Anthony Liguorief749d02011-06-01 12:14:50 -0500576{
Michael Roth65c0f1e2012-08-15 13:45:43 -0500577 JSONParserContext *ctxt = parser_context_new(tokens);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600578 QObject *result;
579
Michael Roth65c0f1e2012-08-15 13:45:43 -0500580 if (!ctxt) {
Michael Rothc1990eb2011-06-01 12:15:00 -0500581 return NULL;
582 }
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600583
Michael Roth65c0f1e2012-08-15 13:45:43 -0500584 result = parse_value(ctxt, ap);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600585
Michael Roth65c0f1e2012-08-15 13:45:43 -0500586 error_propagate(errp, ctxt->err);
587
588 parser_context_free(ctxt);
Anthony Liguorief749d02011-06-01 12:14:50 -0500589
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600590 return result;
591}