xref: /qemu/qobject/qjson.c (revision 5086c997)
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