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" 1686cdf9ecSMarkus Armbruster #include "qapi/qmp/json-parser.h" 177b1b5d19SPaolo Bonzini #include "qapi/qmp/qjson.h" 186b673957SMarkus Armbruster #include "qapi/qmp/qbool.h" 19452fcdbcSMarkus Armbruster #include "qapi/qmp/qdict.h" 2047e6b297SMarkus Armbruster #include "qapi/qmp/qlist.h" 2115280c36SMarkus Armbruster #include "qapi/qmp/qnum.h" 22fc81fa1eSMarkus Armbruster #include "qapi/qmp/qstring.h" 23f348b6d1SVeronia Bahaa #include "qemu/unicode.h" 24b4748b9bSAnthony Liguori 25b4748b9bSAnthony Liguori typedef struct JSONParsingState 26b4748b9bSAnthony Liguori { 27b4748b9bSAnthony Liguori JSONMessageParser parser; 28b4748b9bSAnthony Liguori QObject *result; 2999dbfd1dSMarkus Armbruster Error *err; 30b4748b9bSAnthony Liguori } JSONParsingState; 31b4748b9bSAnthony Liguori 3262815d85SMarkus Armbruster static void consume_json(void *opaque, QObject *json, Error *err) 33b4748b9bSAnthony Liguori { 3462815d85SMarkus Armbruster JSONParsingState *s = opaque; 3599dbfd1dSMarkus Armbruster 362a4794baSMarkus Armbruster assert(!json != !err); 372a4794baSMarkus Armbruster assert(!s->result || !s->err); 382a4794baSMarkus Armbruster 392a4794baSMarkus Armbruster if (s->result) { 402a4794baSMarkus Armbruster qobject_unref(s->result); 412a4794baSMarkus Armbruster s->result = NULL; 422a4794baSMarkus Armbruster error_setg(&s->err, "Expecting at most one JSON value"); 432a4794baSMarkus Armbruster } 442a4794baSMarkus Armbruster if (s->err) { 452a4794baSMarkus Armbruster qobject_unref(json); 462a4794baSMarkus Armbruster error_free(err); 472a4794baSMarkus Armbruster return; 482a4794baSMarkus Armbruster } 4962815d85SMarkus Armbruster s->result = json; 502a4794baSMarkus Armbruster s->err = err; 51b4748b9bSAnthony Liguori } 52b4748b9bSAnthony Liguori 532d36e843SMarkus Armbruster /* 542d36e843SMarkus Armbruster * Parse @string as JSON value. 552d36e843SMarkus Armbruster * If @ap is non-null, interpolate %-escapes. 562d36e843SMarkus Armbruster * Takes ownership of %p arguments. 572d36e843SMarkus Armbruster * On success, return the JSON value. 582d36e843SMarkus Armbruster * On failure, store an error through @errp and return NULL. 592d36e843SMarkus Armbruster * Ownership of %p arguments becomes indeterminate then. To avoid 602d36e843SMarkus Armbruster * leaks, callers passing %p must terminate on error, e.g. by passing 612d36e843SMarkus Armbruster * &error_abort. 622d36e843SMarkus Armbruster */ 632d36e843SMarkus Armbruster static QObject *qobject_from_jsonv(const char *string, va_list *ap, 642d36e843SMarkus Armbruster Error **errp) 65b4748b9bSAnthony Liguori { 66b4748b9bSAnthony Liguori JSONParsingState state = {}; 67b4748b9bSAnthony Liguori 6862815d85SMarkus Armbruster json_message_parser_init(&state.parser, consume_json, &state, ap); 69b4748b9bSAnthony Liguori json_message_parser_feed(&state.parser, string, strlen(string)); 70b4748b9bSAnthony Liguori json_message_parser_flush(&state.parser); 71b4748b9bSAnthony Liguori json_message_parser_destroy(&state.parser); 72b4748b9bSAnthony Liguori 73dd98e848SMarkus Armbruster if (!state.result && !state.err) { 74dd98e848SMarkus Armbruster error_setg(&state.err, "Expecting a JSON value"); 75dd98e848SMarkus Armbruster } 76dd98e848SMarkus Armbruster 7799dbfd1dSMarkus Armbruster error_propagate(errp, state.err); 78b4748b9bSAnthony Liguori return state.result; 79b4748b9bSAnthony Liguori } 80b4748b9bSAnthony Liguori 8157348c2fSMarkus Armbruster QObject *qobject_from_json(const char *string, Error **errp) 828ff5a7d3SLuiz Capitulino { 8357348c2fSMarkus Armbruster return qobject_from_jsonv(string, NULL, errp); 848ff5a7d3SLuiz Capitulino } 858ff5a7d3SLuiz Capitulino 866ce80fd8SMarkus Armbruster /* 876ce80fd8SMarkus Armbruster * Parse @string as JSON value with %-escapes interpolated. 886ce80fd8SMarkus Armbruster * Abort on error. Do not use with untrusted @string. 896ce80fd8SMarkus Armbruster * Return the resulting QObject. It is never null. 906ce80fd8SMarkus Armbruster */ 914ff18468SMarkus Armbruster QObject *qobject_from_vjsonf_nofail(const char *string, va_list ap) 924ff18468SMarkus Armbruster { 934ff18468SMarkus Armbruster va_list ap_copy; 944ff18468SMarkus Armbruster QObject *obj; 954ff18468SMarkus Armbruster 964ff18468SMarkus Armbruster /* va_copy() is needed when va_list is an array type */ 974ff18468SMarkus Armbruster va_copy(ap_copy, ap); 984ff18468SMarkus Armbruster obj = qobject_from_jsonv(string, &ap_copy, &error_abort); 994ff18468SMarkus Armbruster va_end(ap_copy); 1004ff18468SMarkus Armbruster 1014ff18468SMarkus Armbruster assert(obj); 1024ff18468SMarkus Armbruster return obj; 1034ff18468SMarkus Armbruster } 1044ff18468SMarkus Armbruster 1054ff18468SMarkus Armbruster /* 1064ff18468SMarkus Armbruster * Parse @string as JSON value with %-escapes interpolated. 1074ff18468SMarkus Armbruster * Abort on error. Do not use with untrusted @string. 1084ff18468SMarkus Armbruster * Return the resulting QObject. It is never null. 1094ff18468SMarkus Armbruster */ 1106ce80fd8SMarkus Armbruster QObject *qobject_from_jsonf_nofail(const char *string, ...) 111b4748b9bSAnthony Liguori { 1128ff5a7d3SLuiz Capitulino QObject *obj; 113b4748b9bSAnthony Liguori va_list ap; 114b4748b9bSAnthony Liguori 115b4748b9bSAnthony Liguori va_start(ap, string); 1164ff18468SMarkus Armbruster obj = qobject_from_vjsonf_nofail(string, ap); 117b4748b9bSAnthony Liguori va_end(ap); 118b4748b9bSAnthony Liguori 1198ff5a7d3SLuiz Capitulino return obj; 120b4748b9bSAnthony Liguori } 1211fd825f7SAnthony Liguori 122a193352fSMarkus Armbruster /* 123a193352fSMarkus Armbruster * Parse @string as JSON object with %-escapes interpolated. 124a193352fSMarkus Armbruster * Abort on error. Do not use with untrusted @string. 125a193352fSMarkus Armbruster * Return the resulting QDict. It is never null. 126a193352fSMarkus Armbruster */ 1274ff18468SMarkus Armbruster QDict *qdict_from_vjsonf_nofail(const char *string, va_list ap) 1284ff18468SMarkus Armbruster { 1294ff18468SMarkus Armbruster QDict *qdict; 1304ff18468SMarkus Armbruster 1314ff18468SMarkus Armbruster qdict = qobject_to(QDict, qobject_from_vjsonf_nofail(string, ap)); 1324ff18468SMarkus Armbruster assert(qdict); 1334ff18468SMarkus Armbruster return qdict; 1344ff18468SMarkus Armbruster } 1354ff18468SMarkus Armbruster 1364ff18468SMarkus Armbruster /* 1374ff18468SMarkus Armbruster * Parse @string as JSON object with %-escapes interpolated. 1384ff18468SMarkus Armbruster * Abort on error. Do not use with untrusted @string. 1394ff18468SMarkus Armbruster * Return the resulting QDict. It is never null. 1404ff18468SMarkus Armbruster */ 141a193352fSMarkus Armbruster QDict *qdict_from_jsonf_nofail(const char *string, ...) 142a193352fSMarkus Armbruster { 1434ff18468SMarkus Armbruster QDict *qdict; 144a193352fSMarkus Armbruster va_list ap; 145a193352fSMarkus Armbruster 146a193352fSMarkus Armbruster va_start(ap, string); 1474ff18468SMarkus Armbruster qdict = qdict_from_vjsonf_nofail(string, ap); 148a193352fSMarkus Armbruster va_end(ap); 1494ff18468SMarkus Armbruster return qdict; 150a193352fSMarkus Armbruster } 151a193352fSMarkus Armbruster 152212b6008SDaniel P. Berrange static void to_json(const QObject *obj, QString *str, int pretty, int indent); 1531fd825f7SAnthony Liguori 1541cd7741eSMarkus Armbruster static void json_pretty_newline(QString *str, bool pretty, int indent) 1551cd7741eSMarkus Armbruster { 1561cd7741eSMarkus Armbruster int i; 1571cd7741eSMarkus Armbruster 1581cd7741eSMarkus Armbruster if (pretty) { 1591cd7741eSMarkus Armbruster qstring_append(str, "\n"); 1601cd7741eSMarkus Armbruster for (i = 0; i < indent; i++) { 1611cd7741eSMarkus Armbruster qstring_append(str, " "); 1621cd7741eSMarkus Armbruster } 1631cd7741eSMarkus Armbruster } 1641cd7741eSMarkus Armbruster } 1651cd7741eSMarkus Armbruster 166212b6008SDaniel P. Berrange static void to_json(const QObject *obj, QString *str, int pretty, int indent) 1671fd825f7SAnthony Liguori { 1681fd825f7SAnthony Liguori switch (qobject_type(obj)) { 169481b002cSMarkus Armbruster case QTYPE_QNULL: 170481b002cSMarkus Armbruster qstring_append(str, "null"); 171481b002cSMarkus Armbruster break; 17201b2ffceSMarc-André Lureau case QTYPE_QNUM: { 1737dc847ebSMax Reitz QNum *val = qobject_to(QNum, obj); 17401b2ffceSMarc-André Lureau char *buffer = qnum_to_string(val); 1751fd825f7SAnthony Liguori qstring_append(str, buffer); 17601b2ffceSMarc-André Lureau g_free(buffer); 1771fd825f7SAnthony Liguori break; 1781fd825f7SAnthony Liguori } 1791fd825f7SAnthony Liguori case QTYPE_QSTRING: { 1807dc847ebSMax Reitz QString *val = qobject_to(QString, obj); 1811fd825f7SAnthony Liguori const char *ptr; 182e2ec3f97SMarkus Armbruster int cp; 183e2ec3f97SMarkus Armbruster char buf[16]; 184e2ec3f97SMarkus Armbruster char *end; 1851fd825f7SAnthony Liguori 1861fd825f7SAnthony Liguori ptr = qstring_get_str(val); 1871fd825f7SAnthony Liguori qstring_append(str, "\""); 1881fd825f7SAnthony Liguori 189e2ec3f97SMarkus Armbruster for (; *ptr; ptr = end) { 190e2ec3f97SMarkus Armbruster cp = mod_utf8_codepoint(ptr, 6, &end); 191e2ec3f97SMarkus Armbruster switch (cp) { 1921fd825f7SAnthony Liguori case '\"': 1931fd825f7SAnthony Liguori qstring_append(str, "\\\""); 1941fd825f7SAnthony Liguori break; 1951fd825f7SAnthony Liguori case '\\': 1961fd825f7SAnthony Liguori qstring_append(str, "\\\\"); 1971fd825f7SAnthony Liguori break; 1981fd825f7SAnthony Liguori case '\b': 1991fd825f7SAnthony Liguori qstring_append(str, "\\b"); 2001fd825f7SAnthony Liguori break; 201bd032695SLuiz Capitulino case '\f': 202bd032695SLuiz Capitulino qstring_append(str, "\\f"); 203bd032695SLuiz Capitulino break; 2041fd825f7SAnthony Liguori case '\n': 2051fd825f7SAnthony Liguori qstring_append(str, "\\n"); 2061fd825f7SAnthony Liguori break; 2071fd825f7SAnthony Liguori case '\r': 2081fd825f7SAnthony Liguori qstring_append(str, "\\r"); 2091fd825f7SAnthony Liguori break; 2101fd825f7SAnthony Liguori case '\t': 2111fd825f7SAnthony Liguori qstring_append(str, "\\t"); 2121fd825f7SAnthony Liguori break; 213e2ec3f97SMarkus Armbruster default: 214e2ec3f97SMarkus Armbruster if (cp < 0) { 215e2ec3f97SMarkus Armbruster cp = 0xFFFD; /* replacement character */ 216e2ec3f97SMarkus Armbruster } 217e2ec3f97SMarkus Armbruster if (cp > 0xFFFF) { 218e2ec3f97SMarkus Armbruster /* beyond BMP; need a surrogate pair */ 219e2ec3f97SMarkus Armbruster snprintf(buf, sizeof(buf), "\\u%04X\\u%04X", 220e2ec3f97SMarkus Armbruster 0xD800 + ((cp - 0x10000) >> 10), 221e2ec3f97SMarkus Armbruster 0xDC00 + ((cp - 0x10000) & 0x3FF)); 222e2ec3f97SMarkus Armbruster } else if (cp < 0x20 || cp >= 0x7F) { 223e2ec3f97SMarkus Armbruster snprintf(buf, sizeof(buf), "\\u%04X", cp); 224ff06ea21SAnthony Liguori } else { 225e2ec3f97SMarkus Armbruster buf[0] = cp; 226e2ec3f97SMarkus Armbruster buf[1] = 0; 227e2ec3f97SMarkus Armbruster } 2281fd825f7SAnthony Liguori qstring_append(str, buf); 229ff06ea21SAnthony Liguori } 230e2ec3f97SMarkus Armbruster }; 231e2ec3f97SMarkus Armbruster 2321fd825f7SAnthony Liguori qstring_append(str, "\""); 2331fd825f7SAnthony Liguori break; 2341fd825f7SAnthony Liguori } 2351fd825f7SAnthony Liguori case QTYPE_QDICT: { 2367dc847ebSMax Reitz QDict *val = qobject_to(QDict, obj); 237*7b1cd1c6SMarkus Armbruster const char *comma = pretty ? "," : ", "; 238*7b1cd1c6SMarkus Armbruster const char *sep = ""; 239*7b1cd1c6SMarkus Armbruster const QDictEntry *entry; 240*7b1cd1c6SMarkus Armbruster QString *qkey; 2411fd825f7SAnthony Liguori 2421fd825f7SAnthony Liguori qstring_append(str, "{"); 243*7b1cd1c6SMarkus Armbruster 244*7b1cd1c6SMarkus Armbruster for (entry = qdict_first(val); 245*7b1cd1c6SMarkus Armbruster entry; 246*7b1cd1c6SMarkus Armbruster entry = qdict_next(val, entry)) { 247*7b1cd1c6SMarkus Armbruster qstring_append(str, sep); 248*7b1cd1c6SMarkus Armbruster json_pretty_newline(str, pretty, indent + 1); 249*7b1cd1c6SMarkus Armbruster 250*7b1cd1c6SMarkus Armbruster qkey = qstring_from_str(qdict_entry_key(entry)); 251*7b1cd1c6SMarkus Armbruster to_json(QOBJECT(qkey), str, pretty, indent + 1); 252*7b1cd1c6SMarkus Armbruster qobject_unref(qkey); 253*7b1cd1c6SMarkus Armbruster 254*7b1cd1c6SMarkus Armbruster qstring_append(str, ": "); 255*7b1cd1c6SMarkus Armbruster to_json(qdict_entry_value(entry), str, pretty, indent + 1); 256*7b1cd1c6SMarkus Armbruster sep = comma; 257*7b1cd1c6SMarkus Armbruster } 258*7b1cd1c6SMarkus Armbruster 2591cd7741eSMarkus Armbruster json_pretty_newline(str, pretty, indent); 2601fd825f7SAnthony Liguori qstring_append(str, "}"); 2611fd825f7SAnthony Liguori break; 2621fd825f7SAnthony Liguori } 2631fd825f7SAnthony Liguori case QTYPE_QLIST: { 2647dc847ebSMax Reitz QList *val = qobject_to(QList, obj); 2652f2ec111SMarkus Armbruster const char *comma = pretty ? "," : ", "; 2662f2ec111SMarkus Armbruster const char *sep = ""; 2672f2ec111SMarkus Armbruster QListEntry *entry; 2681fd825f7SAnthony Liguori 2691fd825f7SAnthony Liguori qstring_append(str, "["); 2702f2ec111SMarkus Armbruster 2712f2ec111SMarkus Armbruster QLIST_FOREACH_ENTRY(val, entry) { 2722f2ec111SMarkus Armbruster qstring_append(str, sep); 2732f2ec111SMarkus Armbruster json_pretty_newline(str, pretty, indent + 1); 2742f2ec111SMarkus Armbruster to_json(qlist_entry_obj(entry), str, pretty, indent + 1); 2752f2ec111SMarkus Armbruster sep = comma; 2762f2ec111SMarkus Armbruster } 2772f2ec111SMarkus Armbruster 2781cd7741eSMarkus Armbruster json_pretty_newline(str, pretty, indent); 2791fd825f7SAnthony Liguori qstring_append(str, "]"); 2801fd825f7SAnthony Liguori break; 2811fd825f7SAnthony Liguori } 2821fd825f7SAnthony Liguori case QTYPE_QBOOL: { 2837dc847ebSMax Reitz QBool *val = qobject_to(QBool, obj); 2841fd825f7SAnthony Liguori 285fc48ffc3SEric Blake if (qbool_get_bool(val)) { 2861fd825f7SAnthony Liguori qstring_append(str, "true"); 2871fd825f7SAnthony Liguori } else { 2881fd825f7SAnthony Liguori qstring_append(str, "false"); 2891fd825f7SAnthony Liguori } 2901fd825f7SAnthony Liguori break; 2911fd825f7SAnthony Liguori } 292a7c31816SMarkus Armbruster default: 29369dd62dfSKevin Wolf abort(); 2941fd825f7SAnthony Liguori } 2951fd825f7SAnthony Liguori } 2961fd825f7SAnthony Liguori 2971fd825f7SAnthony Liguori QString *qobject_to_json(const QObject *obj) 2981fd825f7SAnthony Liguori { 2991fd825f7SAnthony Liguori QString *str = qstring_new(); 3001fd825f7SAnthony Liguori 301212b6008SDaniel P. Berrange to_json(obj, str, 0, 0); 302212b6008SDaniel P. Berrange 303212b6008SDaniel P. Berrange return str; 304212b6008SDaniel P. Berrange } 305212b6008SDaniel P. Berrange 306212b6008SDaniel P. Berrange QString *qobject_to_json_pretty(const QObject *obj) 307212b6008SDaniel P. Berrange { 308212b6008SDaniel P. Berrange QString *str = qstring_new(); 309212b6008SDaniel P. Berrange 310212b6008SDaniel P. Berrange to_json(obj, str, 1, 0); 3111fd825f7SAnthony Liguori 3121fd825f7SAnthony Liguori return str; 3131fd825f7SAnthony Liguori } 314