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*86cdf9ecSMarkus 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 1521fd825f7SAnthony Liguori typedef struct ToJsonIterState 1531fd825f7SAnthony Liguori { 154212b6008SDaniel P. Berrange int indent; 155212b6008SDaniel P. Berrange int pretty; 1561fd825f7SAnthony Liguori int count; 1571fd825f7SAnthony Liguori QString *str; 1581fd825f7SAnthony Liguori } ToJsonIterState; 1591fd825f7SAnthony Liguori 160212b6008SDaniel P. Berrange static void to_json(const QObject *obj, QString *str, int pretty, int indent); 1611fd825f7SAnthony Liguori 1621fd825f7SAnthony Liguori static void to_json_dict_iter(const char *key, QObject *obj, void *opaque) 1631fd825f7SAnthony Liguori { 1641fd825f7SAnthony Liguori ToJsonIterState *s = opaque; 1651fd825f7SAnthony Liguori QString *qkey; 166212b6008SDaniel P. Berrange int j; 1671fd825f7SAnthony Liguori 1684b58554aSMax Reitz if (s->count) { 1694b58554aSMax Reitz qstring_append(s->str, s->pretty ? "," : ", "); 1704b58554aSMax Reitz } 171212b6008SDaniel P. Berrange 172212b6008SDaniel P. Berrange if (s->pretty) { 173212b6008SDaniel P. Berrange qstring_append(s->str, "\n"); 174212b6008SDaniel P. Berrange for (j = 0 ; j < s->indent ; j++) 175212b6008SDaniel P. Berrange qstring_append(s->str, " "); 1761fd825f7SAnthony Liguori } 1771fd825f7SAnthony Liguori 1781fd825f7SAnthony Liguori qkey = qstring_from_str(key); 179212b6008SDaniel P. Berrange to_json(QOBJECT(qkey), s->str, s->pretty, s->indent); 180cb3e7f08SMarc-André Lureau qobject_unref(qkey); 1811fd825f7SAnthony Liguori 1821fd825f7SAnthony Liguori qstring_append(s->str, ": "); 183212b6008SDaniel P. Berrange to_json(obj, s->str, s->pretty, s->indent); 1841fd825f7SAnthony Liguori s->count++; 1851fd825f7SAnthony Liguori } 1861fd825f7SAnthony Liguori 1871fd825f7SAnthony Liguori static void to_json_list_iter(QObject *obj, void *opaque) 1881fd825f7SAnthony Liguori { 1891fd825f7SAnthony Liguori ToJsonIterState *s = opaque; 190212b6008SDaniel P. Berrange int j; 1911fd825f7SAnthony Liguori 1924b58554aSMax Reitz if (s->count) { 1934b58554aSMax Reitz qstring_append(s->str, s->pretty ? "," : ", "); 1944b58554aSMax Reitz } 195212b6008SDaniel P. Berrange 196212b6008SDaniel P. Berrange if (s->pretty) { 197212b6008SDaniel P. Berrange qstring_append(s->str, "\n"); 198212b6008SDaniel P. Berrange for (j = 0 ; j < s->indent ; j++) 199212b6008SDaniel P. Berrange qstring_append(s->str, " "); 2001fd825f7SAnthony Liguori } 2011fd825f7SAnthony Liguori 202212b6008SDaniel P. Berrange to_json(obj, s->str, s->pretty, s->indent); 2031fd825f7SAnthony Liguori s->count++; 2041fd825f7SAnthony Liguori } 2051fd825f7SAnthony Liguori 206212b6008SDaniel P. Berrange static void to_json(const QObject *obj, QString *str, int pretty, int indent) 2071fd825f7SAnthony Liguori { 2081fd825f7SAnthony Liguori switch (qobject_type(obj)) { 209481b002cSMarkus Armbruster case QTYPE_QNULL: 210481b002cSMarkus Armbruster qstring_append(str, "null"); 211481b002cSMarkus Armbruster break; 21201b2ffceSMarc-André Lureau case QTYPE_QNUM: { 2137dc847ebSMax Reitz QNum *val = qobject_to(QNum, obj); 21401b2ffceSMarc-André Lureau char *buffer = qnum_to_string(val); 2151fd825f7SAnthony Liguori qstring_append(str, buffer); 21601b2ffceSMarc-André Lureau g_free(buffer); 2171fd825f7SAnthony Liguori break; 2181fd825f7SAnthony Liguori } 2191fd825f7SAnthony Liguori case QTYPE_QSTRING: { 2207dc847ebSMax Reitz QString *val = qobject_to(QString, obj); 2211fd825f7SAnthony Liguori const char *ptr; 222e2ec3f97SMarkus Armbruster int cp; 223e2ec3f97SMarkus Armbruster char buf[16]; 224e2ec3f97SMarkus Armbruster char *end; 2251fd825f7SAnthony Liguori 2261fd825f7SAnthony Liguori ptr = qstring_get_str(val); 2271fd825f7SAnthony Liguori qstring_append(str, "\""); 2281fd825f7SAnthony Liguori 229e2ec3f97SMarkus Armbruster for (; *ptr; ptr = end) { 230e2ec3f97SMarkus Armbruster cp = mod_utf8_codepoint(ptr, 6, &end); 231e2ec3f97SMarkus Armbruster switch (cp) { 2321fd825f7SAnthony Liguori case '\"': 2331fd825f7SAnthony Liguori qstring_append(str, "\\\""); 2341fd825f7SAnthony Liguori break; 2351fd825f7SAnthony Liguori case '\\': 2361fd825f7SAnthony Liguori qstring_append(str, "\\\\"); 2371fd825f7SAnthony Liguori break; 2381fd825f7SAnthony Liguori case '\b': 2391fd825f7SAnthony Liguori qstring_append(str, "\\b"); 2401fd825f7SAnthony Liguori break; 241bd032695SLuiz Capitulino case '\f': 242bd032695SLuiz Capitulino qstring_append(str, "\\f"); 243bd032695SLuiz Capitulino break; 2441fd825f7SAnthony Liguori case '\n': 2451fd825f7SAnthony Liguori qstring_append(str, "\\n"); 2461fd825f7SAnthony Liguori break; 2471fd825f7SAnthony Liguori case '\r': 2481fd825f7SAnthony Liguori qstring_append(str, "\\r"); 2491fd825f7SAnthony Liguori break; 2501fd825f7SAnthony Liguori case '\t': 2511fd825f7SAnthony Liguori qstring_append(str, "\\t"); 2521fd825f7SAnthony Liguori break; 253e2ec3f97SMarkus Armbruster default: 254e2ec3f97SMarkus Armbruster if (cp < 0) { 255e2ec3f97SMarkus Armbruster cp = 0xFFFD; /* replacement character */ 256e2ec3f97SMarkus Armbruster } 257e2ec3f97SMarkus Armbruster if (cp > 0xFFFF) { 258e2ec3f97SMarkus Armbruster /* beyond BMP; need a surrogate pair */ 259e2ec3f97SMarkus Armbruster snprintf(buf, sizeof(buf), "\\u%04X\\u%04X", 260e2ec3f97SMarkus Armbruster 0xD800 + ((cp - 0x10000) >> 10), 261e2ec3f97SMarkus Armbruster 0xDC00 + ((cp - 0x10000) & 0x3FF)); 262e2ec3f97SMarkus Armbruster } else if (cp < 0x20 || cp >= 0x7F) { 263e2ec3f97SMarkus Armbruster snprintf(buf, sizeof(buf), "\\u%04X", cp); 264ff06ea21SAnthony Liguori } else { 265e2ec3f97SMarkus Armbruster buf[0] = cp; 266e2ec3f97SMarkus Armbruster buf[1] = 0; 267e2ec3f97SMarkus Armbruster } 2681fd825f7SAnthony Liguori qstring_append(str, buf); 269ff06ea21SAnthony Liguori } 270e2ec3f97SMarkus Armbruster }; 271e2ec3f97SMarkus Armbruster 2721fd825f7SAnthony Liguori qstring_append(str, "\""); 2731fd825f7SAnthony Liguori break; 2741fd825f7SAnthony Liguori } 2751fd825f7SAnthony Liguori case QTYPE_QDICT: { 2761fd825f7SAnthony Liguori ToJsonIterState s; 2777dc847ebSMax Reitz QDict *val = qobject_to(QDict, obj); 2781fd825f7SAnthony Liguori 2791fd825f7SAnthony Liguori s.count = 0; 2801fd825f7SAnthony Liguori s.str = str; 281212b6008SDaniel P. Berrange s.indent = indent + 1; 282212b6008SDaniel P. Berrange s.pretty = pretty; 2831fd825f7SAnthony Liguori qstring_append(str, "{"); 2841fd825f7SAnthony Liguori qdict_iter(val, to_json_dict_iter, &s); 285212b6008SDaniel P. Berrange if (pretty) { 286212b6008SDaniel P. Berrange int j; 287212b6008SDaniel P. Berrange qstring_append(str, "\n"); 288212b6008SDaniel P. Berrange for (j = 0 ; j < indent ; j++) 289212b6008SDaniel P. Berrange qstring_append(str, " "); 290212b6008SDaniel P. Berrange } 2911fd825f7SAnthony Liguori qstring_append(str, "}"); 2921fd825f7SAnthony Liguori break; 2931fd825f7SAnthony Liguori } 2941fd825f7SAnthony Liguori case QTYPE_QLIST: { 2951fd825f7SAnthony Liguori ToJsonIterState s; 2967dc847ebSMax Reitz QList *val = qobject_to(QList, obj); 2971fd825f7SAnthony Liguori 2981fd825f7SAnthony Liguori s.count = 0; 2991fd825f7SAnthony Liguori s.str = str; 300212b6008SDaniel P. Berrange s.indent = indent + 1; 301212b6008SDaniel P. Berrange s.pretty = pretty; 3021fd825f7SAnthony Liguori qstring_append(str, "["); 3031fd825f7SAnthony Liguori qlist_iter(val, (void *)to_json_list_iter, &s); 304212b6008SDaniel P. Berrange if (pretty) { 305212b6008SDaniel P. Berrange int j; 306212b6008SDaniel P. Berrange qstring_append(str, "\n"); 307212b6008SDaniel P. Berrange for (j = 0 ; j < indent ; j++) 308212b6008SDaniel P. Berrange qstring_append(str, " "); 309212b6008SDaniel P. Berrange } 3101fd825f7SAnthony Liguori qstring_append(str, "]"); 3111fd825f7SAnthony Liguori break; 3121fd825f7SAnthony Liguori } 3131fd825f7SAnthony Liguori case QTYPE_QBOOL: { 3147dc847ebSMax Reitz QBool *val = qobject_to(QBool, obj); 3151fd825f7SAnthony Liguori 316fc48ffc3SEric Blake if (qbool_get_bool(val)) { 3171fd825f7SAnthony Liguori qstring_append(str, "true"); 3181fd825f7SAnthony Liguori } else { 3191fd825f7SAnthony Liguori qstring_append(str, "false"); 3201fd825f7SAnthony Liguori } 3211fd825f7SAnthony Liguori break; 3221fd825f7SAnthony Liguori } 323a7c31816SMarkus Armbruster default: 32469dd62dfSKevin Wolf abort(); 3251fd825f7SAnthony Liguori } 3261fd825f7SAnthony Liguori } 3271fd825f7SAnthony Liguori 3281fd825f7SAnthony Liguori QString *qobject_to_json(const QObject *obj) 3291fd825f7SAnthony Liguori { 3301fd825f7SAnthony Liguori QString *str = qstring_new(); 3311fd825f7SAnthony Liguori 332212b6008SDaniel P. Berrange to_json(obj, str, 0, 0); 333212b6008SDaniel P. Berrange 334212b6008SDaniel P. Berrange return str; 335212b6008SDaniel P. Berrange } 336212b6008SDaniel P. Berrange 337212b6008SDaniel P. Berrange QString *qobject_to_json_pretty(const QObject *obj) 338212b6008SDaniel P. Berrange { 339212b6008SDaniel P. Berrange QString *str = qstring_new(); 340212b6008SDaniel P. Berrange 341212b6008SDaniel P. Berrange to_json(obj, str, 1, 0); 3421fd825f7SAnthony Liguori 3431fd825f7SAnthony Liguori return str; 3441fd825f7SAnthony Liguori } 345