blob: 60dd6243a6f1bb310a0abf51e96d49bd4efc9f68 [file] [log] [blame]
Anthony Liguori4a5fcab2009-11-11 10:39:23 -06001/*
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
Amos Kongc96c84a2010-03-24 23:12:05 +080014#include <stdarg.h>
Anthony Liguori4a5fcab2009-11-11 10:39:23 -060015
16#include "qemu-common.h"
Paolo Bonzini7b1b5d12012-12-17 18:19:43 +010017#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"
Anthony Liguori4a5fcab2009-11-11 10:39:23 -060025
26typedef struct JSONParserContext
27{
Anthony Liguorief749d02011-06-01 12:14:50 -050028 Error *err;
Michael Roth65c0f1e2012-08-15 13:45:43 -050029 struct {
30 QObject **buf;
31 size_t pos;
32 size_t count;
33 } tokens;
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/**
50 * Token manipulators
51 *
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.
55 */
56static const char *token_get_value(QObject *obj)
57{
58 return qdict_get_str(qobject_to_qdict(obj), "token");
59}
60
61static JSONTokenType token_get_type(QObject *obj)
62{
63 return qdict_get_int(qobject_to_qdict(obj), "type");
64}
65
Anthony Liguori4a5fcab2009-11-11 10:39:23 -060066/**
67 * Error handler
68 */
Stefan Weil8b7968f2010-09-23 21:28:05 +020069static void GCC_FMT_ATTR(3, 4) parse_error(JSONParserContext *ctxt,
70 QObject *token, const char *msg, ...)
Anthony Liguori4a5fcab2009-11-11 10:39:23 -060071{
Amos Kongc96c84a2010-03-24 23:12:05 +080072 va_list ap;
Anthony Liguorief749d02011-06-01 12:14:50 -050073 char message[1024];
Amos Kongc96c84a2010-03-24 23:12:05 +080074 va_start(ap, msg);
Anthony Liguorief749d02011-06-01 12:14:50 -050075 vsnprintf(message, sizeof(message), msg, ap);
Amos Kongc96c84a2010-03-24 23:12:05 +080076 va_end(ap);
Anthony Liguorief749d02011-06-01 12:14:50 -050077 if (ctxt->err) {
78 error_free(ctxt->err);
79 ctxt->err = NULL;
80 }
Cole Robinsonf231b882014-03-21 19:42:26 -040081 error_setg(&ctxt->err, "JSON parse error, %s", message);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -060082}
83
84/**
85 * String helpers
86 *
87 * These helpers are used to unescape strings.
88 */
89static void wchar_to_utf8(uint16_t wchar, char *buffer, size_t buffer_length)
90{
91 if (wchar <= 0x007F) {
92 BUG_ON(buffer_length < 2);
93
94 buffer[0] = wchar & 0x7F;
95 buffer[1] = 0;
96 } else if (wchar <= 0x07FF) {
97 BUG_ON(buffer_length < 3);
98
99 buffer[0] = 0xC0 | ((wchar >> 6) & 0x1F);
100 buffer[1] = 0x80 | (wchar & 0x3F);
101 buffer[2] = 0;
102 } else {
103 BUG_ON(buffer_length < 4);
104
105 buffer[0] = 0xE0 | ((wchar >> 12) & 0x0F);
106 buffer[1] = 0x80 | ((wchar >> 6) & 0x3F);
107 buffer[2] = 0x80 | (wchar & 0x3F);
108 buffer[3] = 0;
109 }
110}
111
112static int hex2decimal(char ch)
113{
114 if (ch >= '0' && ch <= '9') {
115 return (ch - '0');
116 } else if (ch >= 'a' && ch <= 'f') {
117 return 10 + (ch - 'a');
118 } else if (ch >= 'A' && ch <= 'F') {
119 return 10 + (ch - 'A');
120 }
121
122 return -1;
123}
124
125/**
126 * parse_string(): Parse a json string and return a QObject
127 *
128 * string
129 * ""
130 * " chars "
131 * chars
132 * char
133 * char chars
134 * char
135 * any-Unicode-character-
136 * except-"-or-\-or-
137 * control-character
138 * \"
139 * \\
140 * \/
141 * \b
142 * \f
143 * \n
144 * \r
145 * \t
146 * \u four-hex-digits
147 */
148static QString *qstring_from_escaped_str(JSONParserContext *ctxt, QObject *token)
149{
150 const char *ptr = token_get_value(token);
151 QString *str;
152 int double_quote = 1;
153
154 if (*ptr == '"') {
155 double_quote = 1;
156 } else {
157 double_quote = 0;
158 }
159 ptr++;
160
161 str = qstring_new();
162 while (*ptr &&
163 ((double_quote && *ptr != '"') || (!double_quote && *ptr != '\''))) {
164 if (*ptr == '\\') {
165 ptr++;
166
167 switch (*ptr) {
168 case '"':
169 qstring_append(str, "\"");
170 ptr++;
171 break;
172 case '\'':
173 qstring_append(str, "'");
174 ptr++;
175 break;
176 case '\\':
177 qstring_append(str, "\\");
178 ptr++;
179 break;
180 case '/':
181 qstring_append(str, "/");
182 ptr++;
183 break;
184 case 'b':
185 qstring_append(str, "\b");
186 ptr++;
187 break;
Luiz Capitulinobd032692010-05-19 17:06:15 -0300188 case 'f':
189 qstring_append(str, "\f");
190 ptr++;
191 break;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600192 case 'n':
193 qstring_append(str, "\n");
194 ptr++;
195 break;
196 case 'r':
197 qstring_append(str, "\r");
198 ptr++;
199 break;
200 case 't':
201 qstring_append(str, "\t");
202 ptr++;
203 break;
204 case 'u': {
205 uint16_t unicode_char = 0;
206 char utf8_char[4];
207 int i = 0;
208
209 ptr++;
210
211 for (i = 0; i < 4; i++) {
212 if (qemu_isxdigit(*ptr)) {
213 unicode_char |= hex2decimal(*ptr) << ((3 - i) * 4);
214 } else {
215 parse_error(ctxt, token,
216 "invalid hex escape sequence in string");
217 goto out;
218 }
219 ptr++;
220 }
221
222 wchar_to_utf8(unicode_char, utf8_char, sizeof(utf8_char));
223 qstring_append(str, utf8_char);
224 } break;
225 default:
226 parse_error(ctxt, token, "invalid escape sequence in string");
227 goto out;
228 }
229 } else {
230 char dummy[2];
231
232 dummy[0] = *ptr++;
233 dummy[1] = 0;
234
235 qstring_append(str, dummy);
236 }
237 }
238
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600239 return str;
240
241out:
242 QDECREF(str);
243 return NULL;
244}
245
Michael Roth65c0f1e2012-08-15 13:45:43 -0500246static QObject *parser_context_pop_token(JSONParserContext *ctxt)
247{
248 QObject *token;
249 g_assert(ctxt->tokens.pos < ctxt->tokens.count);
250 token = ctxt->tokens.buf[ctxt->tokens.pos];
251 ctxt->tokens.pos++;
252 return token;
253}
254
255/* Note: parser_context_{peek|pop}_token do not increment the
256 * token object's refcount. In both cases the references will continue
257 * to be tracked and cleaned up in parser_context_free(), so do not
258 * attempt to free the token object.
259 */
260static QObject *parser_context_peek_token(JSONParserContext *ctxt)
261{
262 QObject *token;
263 g_assert(ctxt->tokens.pos < ctxt->tokens.count);
264 token = ctxt->tokens.buf[ctxt->tokens.pos];
265 return token;
266}
267
Michael Roth65c0f1e2012-08-15 13:45:43 -0500268static void tokens_append_from_iter(QObject *obj, void *opaque)
269{
270 JSONParserContext *ctxt = opaque;
271 g_assert(ctxt->tokens.pos < ctxt->tokens.count);
272 ctxt->tokens.buf[ctxt->tokens.pos++] = obj;
273 qobject_incref(obj);
274}
275
276static JSONParserContext *parser_context_new(QList *tokens)
277{
278 JSONParserContext *ctxt;
279 size_t count;
280
281 if (!tokens) {
282 return NULL;
283 }
284
285 count = qlist_size(tokens);
286 if (count == 0) {
287 return NULL;
288 }
289
290 ctxt = g_malloc0(sizeof(JSONParserContext));
291 ctxt->tokens.pos = 0;
292 ctxt->tokens.count = count;
293 ctxt->tokens.buf = g_malloc(count * sizeof(QObject *));
294 qlist_iter(tokens, tokens_append_from_iter, ctxt);
295 ctxt->tokens.pos = 0;
296
297 return ctxt;
298}
299
300/* to support error propagation, ctxt->err must be freed separately */
301static void parser_context_free(JSONParserContext *ctxt)
302{
303 int i;
304 if (ctxt) {
305 for (i = 0; i < ctxt->tokens.count; i++) {
306 qobject_decref(ctxt->tokens.buf[i]);
307 }
308 g_free(ctxt->tokens.buf);
309 g_free(ctxt);
310 }
311}
312
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600313/**
314 * Parsing rules
315 */
Michael Roth65c0f1e2012-08-15 13:45:43 -0500316static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap)
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600317{
Anthony Liguori11e8a462011-06-01 12:14:55 -0500318 QObject *key = NULL, *token = NULL, *value, *peek;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600319
Michael Roth65c0f1e2012-08-15 13:45:43 -0500320 peek = parser_context_peek_token(ctxt);
Anthony Liguori11e8a462011-06-01 12:14:55 -0500321 if (peek == NULL) {
322 parse_error(ctxt, NULL, "premature EOI");
323 goto out;
324 }
325
Michael Roth65c0f1e2012-08-15 13:45:43 -0500326 key = parse_value(ctxt, ap);
Kevin Wolfd758d902010-02-24 16:17:58 +0100327 if (!key || qobject_type(key) != QTYPE_QSTRING) {
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600328 parse_error(ctxt, peek, "key is not a string in object");
329 goto out;
330 }
331
Michael Roth65c0f1e2012-08-15 13:45:43 -0500332 token = parser_context_pop_token(ctxt);
Anthony Liguori11e8a462011-06-01 12:14:55 -0500333 if (token == NULL) {
334 parse_error(ctxt, NULL, "premature EOI");
335 goto out;
336 }
337
Markus Armbrusterc5461662015-11-25 22:23:26 +0100338 if (token_get_type(token) != JSON_COLON) {
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600339 parse_error(ctxt, token, "missing : in object pair");
340 goto out;
341 }
342
Michael Roth65c0f1e2012-08-15 13:45:43 -0500343 value = parse_value(ctxt, ap);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600344 if (value == NULL) {
345 parse_error(ctxt, token, "Missing value in dict");
346 goto out;
347 }
348
349 qdict_put_obj(dict, qstring_get_str(qobject_to_qstring(key)), value);
350
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600351 qobject_decref(key);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600352
353 return 0;
354
355out:
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600356 qobject_decref(key);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600357
358 return -1;
359}
360
Michael Roth65c0f1e2012-08-15 13:45:43 -0500361static QObject *parse_object(JSONParserContext *ctxt, va_list *ap)
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600362{
363 QDict *dict = NULL;
364 QObject *token, *peek;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600365
Michael Roth65c0f1e2012-08-15 13:45:43 -0500366 token = parser_context_pop_token(ctxt);
Markus Armbrusterd538b252015-11-25 22:23:30 +0100367 assert(token && token_get_type(token) == JSON_LCURLY);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600368
369 dict = qdict_new();
370
Michael Roth65c0f1e2012-08-15 13:45:43 -0500371 peek = parser_context_peek_token(ctxt);
Anthony Liguori11e8a462011-06-01 12:14:55 -0500372 if (peek == NULL) {
373 parse_error(ctxt, NULL, "premature EOI");
374 goto out;
375 }
376
Markus Armbrusterc5461662015-11-25 22:23:26 +0100377 if (token_get_type(peek) != JSON_RCURLY) {
Michael Roth65c0f1e2012-08-15 13:45:43 -0500378 if (parse_pair(ctxt, dict, ap) == -1) {
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600379 goto out;
380 }
381
Michael Roth65c0f1e2012-08-15 13:45:43 -0500382 token = parser_context_pop_token(ctxt);
Anthony Liguori11e8a462011-06-01 12:14:55 -0500383 if (token == NULL) {
384 parse_error(ctxt, NULL, "premature EOI");
385 goto out;
386 }
387
Markus Armbrusterc5461662015-11-25 22:23:26 +0100388 while (token_get_type(token) != JSON_RCURLY) {
389 if (token_get_type(token) != JSON_COMMA) {
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600390 parse_error(ctxt, token, "expected separator in dict");
391 goto out;
392 }
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600393
Michael Roth65c0f1e2012-08-15 13:45:43 -0500394 if (parse_pair(ctxt, dict, ap) == -1) {
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600395 goto out;
396 }
397
Michael Roth65c0f1e2012-08-15 13:45:43 -0500398 token = parser_context_pop_token(ctxt);
Anthony Liguori11e8a462011-06-01 12:14:55 -0500399 if (token == NULL) {
400 parse_error(ctxt, NULL, "premature EOI");
401 goto out;
402 }
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600403 }
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600404 } else {
Gongleia491af42014-06-10 17:20:24 +0800405 (void)parser_context_pop_token(ctxt);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600406 }
407
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600408 return QOBJECT(dict);
409
410out:
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600411 QDECREF(dict);
412 return NULL;
413}
414
Michael Roth65c0f1e2012-08-15 13:45:43 -0500415static QObject *parse_array(JSONParserContext *ctxt, va_list *ap)
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600416{
417 QList *list = NULL;
418 QObject *token, *peek;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600419
Michael Roth65c0f1e2012-08-15 13:45:43 -0500420 token = parser_context_pop_token(ctxt);
Markus Armbrusterd538b252015-11-25 22:23:30 +0100421 assert(token && token_get_type(token) == JSON_LSQUARE);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600422
423 list = qlist_new();
424
Michael Roth65c0f1e2012-08-15 13:45:43 -0500425 peek = parser_context_peek_token(ctxt);
Anthony Liguori11e8a462011-06-01 12:14:55 -0500426 if (peek == NULL) {
427 parse_error(ctxt, NULL, "premature EOI");
428 goto out;
429 }
430
Markus Armbrusterc5461662015-11-25 22:23:26 +0100431 if (token_get_type(peek) != JSON_RSQUARE) {
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600432 QObject *obj;
433
Michael Roth65c0f1e2012-08-15 13:45:43 -0500434 obj = parse_value(ctxt, ap);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600435 if (obj == NULL) {
436 parse_error(ctxt, token, "expecting value");
437 goto out;
438 }
439
440 qlist_append_obj(list, obj);
441
Michael Roth65c0f1e2012-08-15 13:45:43 -0500442 token = parser_context_pop_token(ctxt);
Anthony Liguori11e8a462011-06-01 12:14:55 -0500443 if (token == NULL) {
444 parse_error(ctxt, NULL, "premature EOI");
445 goto out;
446 }
447
Markus Armbrusterc5461662015-11-25 22:23:26 +0100448 while (token_get_type(token) != JSON_RSQUARE) {
449 if (token_get_type(token) != JSON_COMMA) {
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600450 parse_error(ctxt, token, "expected separator in list");
451 goto out;
452 }
453
Michael Roth65c0f1e2012-08-15 13:45:43 -0500454 obj = parse_value(ctxt, ap);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600455 if (obj == NULL) {
456 parse_error(ctxt, token, "expecting value");
457 goto out;
458 }
459
460 qlist_append_obj(list, obj);
461
Michael Roth65c0f1e2012-08-15 13:45:43 -0500462 token = parser_context_pop_token(ctxt);
Anthony Liguori11e8a462011-06-01 12:14:55 -0500463 if (token == NULL) {
464 parse_error(ctxt, NULL, "premature EOI");
465 goto out;
466 }
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600467 }
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600468 } else {
Gongleia491af42014-06-10 17:20:24 +0800469 (void)parser_context_pop_token(ctxt);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600470 }
471
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600472 return QOBJECT(list);
473
474out:
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600475 QDECREF(list);
476 return NULL;
477}
478
Michael Roth65c0f1e2012-08-15 13:45:43 -0500479static QObject *parse_keyword(JSONParserContext *ctxt)
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600480{
Markus Armbrusterd538b252015-11-25 22:23:30 +0100481 QObject *token;
Markus Armbruster50e2a462015-11-25 22:23:27 +0100482 const char *val;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600483
Michael Roth65c0f1e2012-08-15 13:45:43 -0500484 token = parser_context_pop_token(ctxt);
Markus Armbrusterd538b252015-11-25 22:23:30 +0100485 assert(token && token_get_type(token) == JSON_KEYWORD);
Markus Armbruster50e2a462015-11-25 22:23:27 +0100486 val = token_get_value(token);
487
488 if (!strcmp(val, "true")) {
Markus Armbrusterd538b252015-11-25 22:23:30 +0100489 return QOBJECT(qbool_from_bool(true));
Markus Armbruster50e2a462015-11-25 22:23:27 +0100490 } else if (!strcmp(val, "false")) {
Markus Armbrusterd538b252015-11-25 22:23:30 +0100491 return QOBJECT(qbool_from_bool(false));
Markus Armbruster50e2a462015-11-25 22:23:27 +0100492 } else if (!strcmp(val, "null")) {
Markus Armbrusterd538b252015-11-25 22:23:30 +0100493 return qnull();
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600494 }
Markus Armbrusterd538b252015-11-25 22:23:30 +0100495 parse_error(ctxt, token, "invalid keyword '%s'", val);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600496 return NULL;
497}
498
Michael Roth65c0f1e2012-08-15 13:45:43 -0500499static QObject *parse_escape(JSONParserContext *ctxt, va_list *ap)
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600500{
Markus Armbrusterd538b252015-11-25 22:23:30 +0100501 QObject *token;
Markus Armbruster6b9606f2015-11-25 22:23:28 +0100502 const char *val;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600503
504 if (ap == NULL) {
Markus Armbrusterd538b252015-11-25 22:23:30 +0100505 return NULL;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600506 }
507
Michael Roth65c0f1e2012-08-15 13:45:43 -0500508 token = parser_context_pop_token(ctxt);
Markus Armbrusterd538b252015-11-25 22:23:30 +0100509 assert(token && token_get_type(token) == JSON_ESCAPE);
Markus Armbruster6b9606f2015-11-25 22:23:28 +0100510 val = token_get_value(token);
511
512 if (!strcmp(val, "%p")) {
Markus Armbrusterd538b252015-11-25 22:23:30 +0100513 return va_arg(*ap, QObject *);
Markus Armbruster6b9606f2015-11-25 22:23:28 +0100514 } else if (!strcmp(val, "%i")) {
Markus Armbrusterd538b252015-11-25 22:23:30 +0100515 return QOBJECT(qbool_from_bool(va_arg(*ap, int)));
Markus Armbruster6b9606f2015-11-25 22:23:28 +0100516 } else if (!strcmp(val, "%d")) {
Markus Armbrusterd538b252015-11-25 22:23:30 +0100517 return QOBJECT(qint_from_int(va_arg(*ap, int)));
Markus Armbruster6b9606f2015-11-25 22:23:28 +0100518 } else if (!strcmp(val, "%ld")) {
Markus Armbrusterd538b252015-11-25 22:23:30 +0100519 return QOBJECT(qint_from_int(va_arg(*ap, long)));
Markus Armbruster6b9606f2015-11-25 22:23:28 +0100520 } else if (!strcmp(val, "%lld") ||
521 !strcmp(val, "%I64d")) {
Markus Armbrusterd538b252015-11-25 22:23:30 +0100522 return QOBJECT(qint_from_int(va_arg(*ap, long long)));
Markus Armbruster6b9606f2015-11-25 22:23:28 +0100523 } else if (!strcmp(val, "%s")) {
Markus Armbrusterd538b252015-11-25 22:23:30 +0100524 return QOBJECT(qstring_from_str(va_arg(*ap, const char *)));
Markus Armbruster6b9606f2015-11-25 22:23:28 +0100525 } else if (!strcmp(val, "%f")) {
Markus Armbrusterd538b252015-11-25 22:23:30 +0100526 return QOBJECT(qfloat_from_double(va_arg(*ap, double)));
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600527 }
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600528 return NULL;
529}
530
Michael Roth65c0f1e2012-08-15 13:45:43 -0500531static QObject *parse_literal(JSONParserContext *ctxt)
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600532{
Markus Armbrusterd538b252015-11-25 22:23:30 +0100533 QObject *token;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600534
Michael Roth65c0f1e2012-08-15 13:45:43 -0500535 token = parser_context_pop_token(ctxt);
Markus Armbrusterd538b252015-11-25 22:23:30 +0100536 assert(token);
Anthony Liguori11e8a462011-06-01 12:14:55 -0500537
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600538 switch (token_get_type(token)) {
539 case JSON_STRING:
Markus Armbrusterd538b252015-11-25 22:23:30 +0100540 return QOBJECT(qstring_from_escaped_str(ctxt, token));
Michael Roth3d5b3ec2013-05-10 17:46:05 -0500541 case JSON_INTEGER: {
542 /* A possibility exists that this is a whole-valued float where the
543 * fractional part was left out due to being 0 (.0). It's not a big
544 * deal to treat these as ints in the parser, so long as users of the
545 * resulting QObject know to expect a QInt in place of a QFloat in
546 * cases like these.
547 *
548 * However, in some cases these values will overflow/underflow a
549 * QInt/int64 container, thus we should assume these are to be handled
550 * as QFloats/doubles rather than silently changing their values.
551 *
552 * strtoll() indicates these instances by setting errno to ERANGE
553 */
554 int64_t value;
555
556 errno = 0; /* strtoll doesn't set errno on success */
557 value = strtoll(token_get_value(token), NULL, 10);
558 if (errno != ERANGE) {
Markus Armbrusterd538b252015-11-25 22:23:30 +0100559 return QOBJECT(qint_from_int(value));
Michael Roth3d5b3ec2013-05-10 17:46:05 -0500560 }
561 /* fall through to JSON_FLOAT */
562 }
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600563 case JSON_FLOAT:
564 /* FIXME dependent on locale */
Markus Armbrusterd538b252015-11-25 22:23:30 +0100565 return QOBJECT(qfloat_from_double(strtod(token_get_value(token),
566 NULL)));
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600567 default:
Markus Armbrusterd538b252015-11-25 22:23:30 +0100568 abort();
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600569 }
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600570}
571
Michael Roth65c0f1e2012-08-15 13:45:43 -0500572static QObject *parse_value(JSONParserContext *ctxt, va_list *ap)
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600573{
Markus Armbrusterd538b252015-11-25 22:23:30 +0100574 QObject *token;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600575
Markus Armbrusterd538b252015-11-25 22:23:30 +0100576 token = parser_context_peek_token(ctxt);
577 if (token == NULL) {
578 parse_error(ctxt, NULL, "premature EOI");
579 return NULL;
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600580 }
581
Markus Armbrusterd538b252015-11-25 22:23:30 +0100582 switch (token_get_type(token)) {
583 case JSON_LCURLY:
584 return parse_object(ctxt, ap);
585 case JSON_LSQUARE:
586 return parse_array(ctxt, ap);
587 case JSON_ESCAPE:
588 return parse_escape(ctxt, ap);
589 case JSON_INTEGER:
590 case JSON_FLOAT:
591 case JSON_STRING:
592 return parse_literal(ctxt);
593 case JSON_KEYWORD:
594 return parse_keyword(ctxt);
595 default:
596 parse_error(ctxt, token, "expecting value");
597 return NULL;
598 }
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600599}
600
601QObject *json_parser_parse(QList *tokens, va_list *ap)
602{
Anthony Liguorief749d02011-06-01 12:14:50 -0500603 return json_parser_parse_err(tokens, ap, NULL);
604}
605
606QObject *json_parser_parse_err(QList *tokens, va_list *ap, Error **errp)
607{
Michael Roth65c0f1e2012-08-15 13:45:43 -0500608 JSONParserContext *ctxt = parser_context_new(tokens);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600609 QObject *result;
610
Michael Roth65c0f1e2012-08-15 13:45:43 -0500611 if (!ctxt) {
Michael Rothc1990eb2011-06-01 12:15:00 -0500612 return NULL;
613 }
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600614
Michael Roth65c0f1e2012-08-15 13:45:43 -0500615 result = parse_value(ctxt, ap);
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600616
Michael Roth65c0f1e2012-08-15 13:45:43 -0500617 error_propagate(errp, ctxt->err);
618
619 parser_context_free(ctxt);
Anthony Liguorief749d02011-06-01 12:14:50 -0500620
Anthony Liguori4a5fcab2009-11-11 10:39:23 -0600621 return result;
622}