1a372823aSPaolo Bonzini /*
2a372823aSPaolo Bonzini * QObject JSON integration
3a372823aSPaolo Bonzini *
4a372823aSPaolo Bonzini * Copyright IBM, Corp. 2009
5a372823aSPaolo Bonzini *
6a372823aSPaolo Bonzini * Authors:
7a372823aSPaolo Bonzini * Anthony Liguori <aliguori@us.ibm.com>
8a372823aSPaolo Bonzini *
9a372823aSPaolo Bonzini * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10a372823aSPaolo Bonzini * See the COPYING.LIB file in the top-level directory.
11a372823aSPaolo Bonzini *
12a372823aSPaolo Bonzini */
13a372823aSPaolo Bonzini
14f2ad72b3SPeter Maydell #include "qemu/osdep.h"
1599dbfd1dSMarkus Armbruster #include "qapi/error.h"
1686cdf9ecSMarkus Armbruster #include "qapi/qmp/json-parser.h"
17998da0b1SMarkus Armbruster #include "qapi/qmp/json-writer.h"
18a372823aSPaolo Bonzini #include "qapi/qmp/qjson.h"
196b673957SMarkus Armbruster #include "qapi/qmp/qbool.h"
20452fcdbcSMarkus Armbruster #include "qapi/qmp/qdict.h"
2147e6b297SMarkus Armbruster #include "qapi/qmp/qlist.h"
2215280c36SMarkus Armbruster #include "qapi/qmp/qnum.h"
23fc81fa1eSMarkus Armbruster #include "qapi/qmp/qstring.h"
24a372823aSPaolo Bonzini
25*5086c997SZhang Han typedef struct JSONParsingState {
26a372823aSPaolo Bonzini JSONMessageParser parser;
27a372823aSPaolo Bonzini QObject *result;
2899dbfd1dSMarkus Armbruster Error *err;
29a372823aSPaolo Bonzini } JSONParsingState;
30a372823aSPaolo Bonzini
consume_json(void * opaque,QObject * json,Error * err)3162815d85SMarkus Armbruster static void consume_json(void *opaque, QObject *json, Error *err)
32a372823aSPaolo Bonzini {
3362815d85SMarkus Armbruster JSONParsingState *s = opaque;
3499dbfd1dSMarkus Armbruster
352a4794baSMarkus Armbruster assert(!json != !err);
362a4794baSMarkus Armbruster assert(!s->result || !s->err);
372a4794baSMarkus Armbruster
382a4794baSMarkus Armbruster if (s->result) {
392a4794baSMarkus Armbruster qobject_unref(s->result);
402a4794baSMarkus Armbruster s->result = NULL;
412a4794baSMarkus Armbruster error_setg(&s->err, "Expecting at most one JSON value");
422a4794baSMarkus Armbruster }
432a4794baSMarkus Armbruster if (s->err) {
442a4794baSMarkus Armbruster qobject_unref(json);
452a4794baSMarkus Armbruster error_free(err);
462a4794baSMarkus Armbruster return;
472a4794baSMarkus Armbruster }
4862815d85SMarkus Armbruster s->result = json;
492a4794baSMarkus Armbruster s->err = err;
50a372823aSPaolo Bonzini }
51a372823aSPaolo Bonzini
522d36e843SMarkus Armbruster /*
532d36e843SMarkus Armbruster * Parse @string as JSON value.
542d36e843SMarkus Armbruster * If @ap is non-null, interpolate %-escapes.
552d36e843SMarkus Armbruster * Takes ownership of %p arguments.
562d36e843SMarkus Armbruster * On success, return the JSON value.
572d36e843SMarkus Armbruster * On failure, store an error through @errp and return NULL.
582d36e843SMarkus Armbruster * Ownership of %p arguments becomes indeterminate then. To avoid
592d36e843SMarkus Armbruster * leaks, callers passing %p must terminate on error, e.g. by passing
602d36e843SMarkus Armbruster * &error_abort.
612d36e843SMarkus Armbruster */
qobject_from_jsonv(const char * string,va_list * ap,Error ** errp)622d36e843SMarkus Armbruster static QObject *qobject_from_jsonv(const char *string, va_list *ap,
632d36e843SMarkus Armbruster Error **errp)
64a372823aSPaolo Bonzini {
65a372823aSPaolo Bonzini JSONParsingState state = {};
66a372823aSPaolo Bonzini
6762815d85SMarkus Armbruster json_message_parser_init(&state.parser, consume_json, &state, ap);
68a372823aSPaolo Bonzini json_message_parser_feed(&state.parser, string, strlen(string));
69a372823aSPaolo Bonzini json_message_parser_flush(&state.parser);
70a372823aSPaolo Bonzini json_message_parser_destroy(&state.parser);
71a372823aSPaolo Bonzini
72dd98e848SMarkus Armbruster if (!state.result && !state.err) {
73dd98e848SMarkus Armbruster error_setg(&state.err, "Expecting a JSON value");
74dd98e848SMarkus Armbruster }
75dd98e848SMarkus Armbruster
7699dbfd1dSMarkus Armbruster error_propagate(errp, state.err);
77a372823aSPaolo Bonzini return state.result;
78a372823aSPaolo Bonzini }
79a372823aSPaolo Bonzini
qobject_from_json(const char * string,Error ** errp)8057348c2fSMarkus Armbruster QObject *qobject_from_json(const char *string, Error **errp)
81a372823aSPaolo Bonzini {
8257348c2fSMarkus Armbruster return qobject_from_jsonv(string, NULL, errp);
83a372823aSPaolo Bonzini }
84a372823aSPaolo Bonzini
856ce80fd8SMarkus Armbruster /*
866ce80fd8SMarkus Armbruster * Parse @string as JSON value with %-escapes interpolated.
876ce80fd8SMarkus Armbruster * Abort on error. Do not use with untrusted @string.
886ce80fd8SMarkus Armbruster * Return the resulting QObject. It is never null.
896ce80fd8SMarkus Armbruster */
qobject_from_vjsonf_nofail(const char * string,va_list ap)904ff18468SMarkus Armbruster QObject *qobject_from_vjsonf_nofail(const char *string, va_list ap)
914ff18468SMarkus Armbruster {
924ff18468SMarkus Armbruster va_list ap_copy;
934ff18468SMarkus Armbruster QObject *obj;
944ff18468SMarkus Armbruster
954ff18468SMarkus Armbruster /* va_copy() is needed when va_list is an array type */
964ff18468SMarkus Armbruster va_copy(ap_copy, ap);
974ff18468SMarkus Armbruster obj = qobject_from_jsonv(string, &ap_copy, &error_abort);
984ff18468SMarkus Armbruster va_end(ap_copy);
994ff18468SMarkus Armbruster
1004ff18468SMarkus Armbruster assert(obj);
1014ff18468SMarkus Armbruster return obj;
1024ff18468SMarkus Armbruster }
1034ff18468SMarkus Armbruster
1044ff18468SMarkus Armbruster /*
1054ff18468SMarkus Armbruster * Parse @string as JSON value with %-escapes interpolated.
1064ff18468SMarkus Armbruster * Abort on error. Do not use with untrusted @string.
1074ff18468SMarkus Armbruster * Return the resulting QObject. It is never null.
1084ff18468SMarkus Armbruster */
qobject_from_jsonf_nofail(const char * string,...)1096ce80fd8SMarkus Armbruster QObject *qobject_from_jsonf_nofail(const char *string, ...)
110a372823aSPaolo Bonzini {
111a372823aSPaolo Bonzini QObject *obj;
112a372823aSPaolo Bonzini va_list ap;
113a372823aSPaolo Bonzini
114a372823aSPaolo Bonzini va_start(ap, string);
1154ff18468SMarkus Armbruster obj = qobject_from_vjsonf_nofail(string, ap);
116a372823aSPaolo Bonzini va_end(ap);
117a372823aSPaolo Bonzini
118a372823aSPaolo Bonzini return obj;
119a372823aSPaolo Bonzini }
120a372823aSPaolo Bonzini
121a193352fSMarkus Armbruster /*
122a193352fSMarkus Armbruster * Parse @string as JSON object with %-escapes interpolated.
123a193352fSMarkus Armbruster * Abort on error. Do not use with untrusted @string.
124a193352fSMarkus Armbruster * Return the resulting QDict. It is never null.
125a193352fSMarkus Armbruster */
qdict_from_vjsonf_nofail(const char * string,va_list ap)1264ff18468SMarkus Armbruster QDict *qdict_from_vjsonf_nofail(const char *string, va_list ap)
1274ff18468SMarkus Armbruster {
1284ff18468SMarkus Armbruster QDict *qdict;
1294ff18468SMarkus Armbruster
1304ff18468SMarkus Armbruster qdict = qobject_to(QDict, qobject_from_vjsonf_nofail(string, ap));
1314ff18468SMarkus Armbruster assert(qdict);
1324ff18468SMarkus Armbruster return qdict;
1334ff18468SMarkus Armbruster }
1344ff18468SMarkus Armbruster
1354ff18468SMarkus Armbruster /*
1364ff18468SMarkus Armbruster * Parse @string as JSON object with %-escapes interpolated.
1374ff18468SMarkus Armbruster * Abort on error. Do not use with untrusted @string.
1384ff18468SMarkus Armbruster * Return the resulting QDict. It is never null.
1394ff18468SMarkus Armbruster */
qdict_from_jsonf_nofail(const char * string,...)140a193352fSMarkus Armbruster QDict *qdict_from_jsonf_nofail(const char *string, ...)
141a193352fSMarkus Armbruster {
1424ff18468SMarkus Armbruster QDict *qdict;
143a193352fSMarkus Armbruster va_list ap;
144a193352fSMarkus Armbruster
145a193352fSMarkus Armbruster va_start(ap, string);
1464ff18468SMarkus Armbruster qdict = qdict_from_vjsonf_nofail(string, ap);
147a193352fSMarkus Armbruster va_end(ap);
1484ff18468SMarkus Armbruster return qdict;
149a193352fSMarkus Armbruster }
150a193352fSMarkus Armbruster
to_json(JSONWriter * writer,const char * name,const QObject * obj)151998da0b1SMarkus Armbruster static void to_json(JSONWriter *writer, const char *name,
152998da0b1SMarkus Armbruster const QObject *obj)
15391f54d92SMarkus Armbruster {
15491f54d92SMarkus Armbruster switch (qobject_type(obj)) {
15591f54d92SMarkus Armbruster case QTYPE_QNULL:
156998da0b1SMarkus Armbruster json_writer_null(writer, name);
15791f54d92SMarkus Armbruster break;
15891f54d92SMarkus Armbruster case QTYPE_QNUM: {
15991f54d92SMarkus Armbruster QNum *val = qobject_to(QNum, obj);
160998da0b1SMarkus Armbruster
161998da0b1SMarkus Armbruster switch (val->kind) {
162998da0b1SMarkus Armbruster case QNUM_I64:
163998da0b1SMarkus Armbruster json_writer_int64(writer, name, val->u.i64);
164998da0b1SMarkus Armbruster break;
165998da0b1SMarkus Armbruster case QNUM_U64:
166998da0b1SMarkus Armbruster json_writer_uint64(writer, name, val->u.u64);
167998da0b1SMarkus Armbruster break;
168998da0b1SMarkus Armbruster case QNUM_DOUBLE:
169998da0b1SMarkus Armbruster json_writer_double(writer, name, val->u.dbl);
170998da0b1SMarkus Armbruster break;
171998da0b1SMarkus Armbruster default:
172998da0b1SMarkus Armbruster abort();
173998da0b1SMarkus Armbruster }
17491f54d92SMarkus Armbruster break;
17591f54d92SMarkus Armbruster }
17691f54d92SMarkus Armbruster case QTYPE_QSTRING: {
177998da0b1SMarkus Armbruster QString *val = qobject_to(QString, obj);
178998da0b1SMarkus Armbruster
179998da0b1SMarkus Armbruster json_writer_str(writer, name, qstring_get_str(val));
180a372823aSPaolo Bonzini break;
181a372823aSPaolo Bonzini }
182a372823aSPaolo Bonzini case QTYPE_QDICT: {
1837dc847ebSMax Reitz QDict *val = qobject_to(QDict, obj);
1847b1cd1c6SMarkus Armbruster const QDictEntry *entry;
185a372823aSPaolo Bonzini
186998da0b1SMarkus Armbruster json_writer_start_object(writer, name);
1877b1cd1c6SMarkus Armbruster
1887b1cd1c6SMarkus Armbruster for (entry = qdict_first(val);
1897b1cd1c6SMarkus Armbruster entry;
1907b1cd1c6SMarkus Armbruster entry = qdict_next(val, entry)) {
191998da0b1SMarkus Armbruster to_json(writer, qdict_entry_key(entry), qdict_entry_value(entry));
1927b1cd1c6SMarkus Armbruster }
1937b1cd1c6SMarkus Armbruster
194998da0b1SMarkus Armbruster json_writer_end_object(writer);
195a372823aSPaolo Bonzini break;
196a372823aSPaolo Bonzini }
197a372823aSPaolo Bonzini case QTYPE_QLIST: {
1987dc847ebSMax Reitz QList *val = qobject_to(QList, obj);
1992f2ec111SMarkus Armbruster QListEntry *entry;
200a372823aSPaolo Bonzini
201998da0b1SMarkus Armbruster json_writer_start_array(writer, name);
2022f2ec111SMarkus Armbruster
2032f2ec111SMarkus Armbruster QLIST_FOREACH_ENTRY(val, entry) {
204998da0b1SMarkus Armbruster to_json(writer, NULL, qlist_entry_obj(entry));
2052f2ec111SMarkus Armbruster }
2062f2ec111SMarkus Armbruster
207998da0b1SMarkus Armbruster json_writer_end_array(writer);
208a372823aSPaolo Bonzini break;
209a372823aSPaolo Bonzini }
210a372823aSPaolo Bonzini case QTYPE_QBOOL: {
2117dc847ebSMax Reitz QBool *val = qobject_to(QBool, obj);
212a372823aSPaolo Bonzini
213998da0b1SMarkus Armbruster json_writer_bool(writer, name, qbool_get_bool(val));
214a372823aSPaolo Bonzini break;
215a372823aSPaolo Bonzini }
216a7c31816SMarkus Armbruster default:
21769dd62dfSKevin Wolf abort();
218a372823aSPaolo Bonzini }
219a372823aSPaolo Bonzini }
220a372823aSPaolo Bonzini
qobject_to_json_pretty(const QObject * obj,bool pretty)221eab3a467SMarkus Armbruster GString *qobject_to_json_pretty(const QObject *obj, bool pretty)
222a372823aSPaolo Bonzini {
223998da0b1SMarkus Armbruster JSONWriter *writer = json_writer_new(pretty);
224a372823aSPaolo Bonzini
225998da0b1SMarkus Armbruster to_json(writer, NULL, obj);
226998da0b1SMarkus Armbruster return json_writer_get_and_free(writer);
227a372823aSPaolo Bonzini }
228a372823aSPaolo Bonzini
qobject_to_json(const QObject * obj)229eab3a467SMarkus Armbruster GString *qobject_to_json(const QObject *obj)
230a372823aSPaolo Bonzini {
2316589f459SMarkus Armbruster return qobject_to_json_pretty(obj, false);
232a372823aSPaolo Bonzini }
233