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