1b4748b9bSAnthony Liguori /*
2b4748b9bSAnthony Liguori * QObject JSON integration
3b4748b9bSAnthony Liguori *
4b4748b9bSAnthony Liguori * Copyright IBM, Corp. 2009
5b4748b9bSAnthony Liguori *
6b4748b9bSAnthony Liguori * Authors:
7b4748b9bSAnthony Liguori * Anthony Liguori <aliguori@us.ibm.com>
8b4748b9bSAnthony Liguori *
9b4748b9bSAnthony Liguori * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10b4748b9bSAnthony Liguori * See the COPYING.LIB file in the top-level directory.
11b4748b9bSAnthony Liguori *
12b4748b9bSAnthony Liguori */
13b4748b9bSAnthony Liguori
14f2ad72b3SPeter Maydell #include "qemu/osdep.h"
1599dbfd1dSMarkus Armbruster #include "qapi/error.h"
16*407bc4bfSDaniel P. Berrangé #include "qobject/json-parser.h"
17*407bc4bfSDaniel P. Berrangé #include "qobject/json-writer.h"
18*407bc4bfSDaniel P. Berrangé #include "qobject/qjson.h"
19*407bc4bfSDaniel P. Berrangé #include "qobject/qbool.h"
20*407bc4bfSDaniel P. Berrangé #include "qobject/qdict.h"
21*407bc4bfSDaniel P. Berrangé #include "qobject/qlist.h"
22*407bc4bfSDaniel P. Berrangé #include "qobject/qnum.h"
23*407bc4bfSDaniel P. Berrangé #include "qobject/qstring.h"
24b4748b9bSAnthony Liguori
255086c997SZhang Han typedef struct JSONParsingState {
26b4748b9bSAnthony Liguori JSONMessageParser parser;
27b4748b9bSAnthony Liguori QObject *result;
2899dbfd1dSMarkus Armbruster Error *err;
29b4748b9bSAnthony Liguori } JSONParsingState;
30b4748b9bSAnthony Liguori
consume_json(void * opaque,QObject * json,Error * err)3162815d85SMarkus Armbruster static void consume_json(void *opaque, QObject *json, Error *err)
32b4748b9bSAnthony Liguori {
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;
50b4748b9bSAnthony Liguori }
51b4748b9bSAnthony Liguori
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)
64b4748b9bSAnthony Liguori {
65b4748b9bSAnthony Liguori JSONParsingState state = {};
66b4748b9bSAnthony Liguori
6762815d85SMarkus Armbruster json_message_parser_init(&state.parser, consume_json, &state, ap);
68b4748b9bSAnthony Liguori json_message_parser_feed(&state.parser, string, strlen(string));
69b4748b9bSAnthony Liguori json_message_parser_flush(&state.parser);
70b4748b9bSAnthony Liguori json_message_parser_destroy(&state.parser);
71b4748b9bSAnthony Liguori
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);
77b4748b9bSAnthony Liguori return state.result;
78b4748b9bSAnthony Liguori }
79b4748b9bSAnthony Liguori
qobject_from_json(const char * string,Error ** errp)8057348c2fSMarkus Armbruster QObject *qobject_from_json(const char *string, Error **errp)
818ff5a7d3SLuiz Capitulino {
8257348c2fSMarkus Armbruster return qobject_from_jsonv(string, NULL, errp);
838ff5a7d3SLuiz Capitulino }
848ff5a7d3SLuiz Capitulino
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, ...)
110b4748b9bSAnthony Liguori {
1118ff5a7d3SLuiz Capitulino QObject *obj;
112b4748b9bSAnthony Liguori va_list ap;
113b4748b9bSAnthony Liguori
114b4748b9bSAnthony Liguori va_start(ap, string);
1154ff18468SMarkus Armbruster obj = qobject_from_vjsonf_nofail(string, ap);
116b4748b9bSAnthony Liguori va_end(ap);
117b4748b9bSAnthony Liguori
1188ff5a7d3SLuiz Capitulino return obj;
119b4748b9bSAnthony Liguori }
1201fd825f7SAnthony Liguori
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));
1801fd825f7SAnthony Liguori break;
1811fd825f7SAnthony Liguori }
1821fd825f7SAnthony Liguori case QTYPE_QDICT: {
1837dc847ebSMax Reitz QDict *val = qobject_to(QDict, obj);
1847b1cd1c6SMarkus Armbruster const QDictEntry *entry;
1851fd825f7SAnthony Liguori
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);
1951fd825f7SAnthony Liguori break;
1961fd825f7SAnthony Liguori }
1971fd825f7SAnthony Liguori case QTYPE_QLIST: {
1987dc847ebSMax Reitz QList *val = qobject_to(QList, obj);
1992f2ec111SMarkus Armbruster QListEntry *entry;
2001fd825f7SAnthony Liguori
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);
2081fd825f7SAnthony Liguori break;
2091fd825f7SAnthony Liguori }
2101fd825f7SAnthony Liguori case QTYPE_QBOOL: {
2117dc847ebSMax Reitz QBool *val = qobject_to(QBool, obj);
2121fd825f7SAnthony Liguori
213998da0b1SMarkus Armbruster json_writer_bool(writer, name, qbool_get_bool(val));
2141fd825f7SAnthony Liguori break;
2151fd825f7SAnthony Liguori }
216a7c31816SMarkus Armbruster default:
21769dd62dfSKevin Wolf abort();
2181fd825f7SAnthony Liguori }
2191fd825f7SAnthony Liguori }
2201fd825f7SAnthony Liguori
qobject_to_json_pretty(const QObject * obj,bool pretty)221eab3a467SMarkus Armbruster GString *qobject_to_json_pretty(const QObject *obj, bool pretty)
2221fd825f7SAnthony Liguori {
223998da0b1SMarkus Armbruster JSONWriter *writer = json_writer_new(pretty);
2241fd825f7SAnthony Liguori
225998da0b1SMarkus Armbruster to_json(writer, NULL, obj);
226998da0b1SMarkus Armbruster return json_writer_get_and_free(writer);
227212b6008SDaniel P. Berrange }
228212b6008SDaniel P. Berrange
qobject_to_json(const QObject * obj)229eab3a467SMarkus Armbruster GString *qobject_to_json(const QObject *obj)
230212b6008SDaniel P. Berrange {
2316589f459SMarkus Armbruster return qobject_to_json_pretty(obj, false);
2321fd825f7SAnthony Liguori }
233