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" 167b1b5d19SPaolo Bonzini #include "qapi/qmp/json-lexer.h" 177b1b5d19SPaolo Bonzini #include "qapi/qmp/json-parser.h" 187b1b5d19SPaolo Bonzini #include "qapi/qmp/json-streamer.h" 197b1b5d19SPaolo Bonzini #include "qapi/qmp/qjson.h" 206b673957SMarkus Armbruster #include "qapi/qmp/qbool.h" 21452fcdbcSMarkus Armbruster #include "qapi/qmp/qdict.h" 2247e6b297SMarkus Armbruster #include "qapi/qmp/qlist.h" 2315280c36SMarkus Armbruster #include "qapi/qmp/qnum.h" 24fc81fa1eSMarkus Armbruster #include "qapi/qmp/qstring.h" 25f348b6d1SVeronia Bahaa #include "qemu/unicode.h" 26b4748b9bSAnthony Liguori 27b4748b9bSAnthony Liguori typedef struct JSONParsingState 28b4748b9bSAnthony Liguori { 29b4748b9bSAnthony Liguori JSONMessageParser parser; 30b4748b9bSAnthony Liguori va_list *ap; 31b4748b9bSAnthony Liguori QObject *result; 3299dbfd1dSMarkus Armbruster Error *err; 33b4748b9bSAnthony Liguori } JSONParsingState; 34b4748b9bSAnthony Liguori 3595385fe9SPaolo Bonzini static void parse_json(JSONMessageParser *parser, GQueue *tokens) 36b4748b9bSAnthony Liguori { 37b4748b9bSAnthony Liguori JSONParsingState *s = container_of(parser, JSONParsingState, parser); 3899dbfd1dSMarkus Armbruster 3999dbfd1dSMarkus Armbruster s->result = json_parser_parse_err(tokens, s->ap, &s->err); 40b4748b9bSAnthony Liguori } 41b4748b9bSAnthony Liguori 4299dbfd1dSMarkus Armbruster QObject *qobject_from_jsonv(const char *string, va_list *ap, Error **errp) 43b4748b9bSAnthony Liguori { 44b4748b9bSAnthony Liguori JSONParsingState state = {}; 45b4748b9bSAnthony Liguori 468ff5a7d3SLuiz Capitulino state.ap = ap; 478ff5a7d3SLuiz Capitulino 48b4748b9bSAnthony Liguori json_message_parser_init(&state.parser, parse_json); 49b4748b9bSAnthony Liguori json_message_parser_feed(&state.parser, string, strlen(string)); 50b4748b9bSAnthony Liguori json_message_parser_flush(&state.parser); 51b4748b9bSAnthony Liguori json_message_parser_destroy(&state.parser); 52b4748b9bSAnthony Liguori 5399dbfd1dSMarkus Armbruster error_propagate(errp, state.err); 54b4748b9bSAnthony Liguori return state.result; 55b4748b9bSAnthony Liguori } 56b4748b9bSAnthony Liguori 5757348c2fSMarkus Armbruster QObject *qobject_from_json(const char *string, Error **errp) 588ff5a7d3SLuiz Capitulino { 5957348c2fSMarkus Armbruster return qobject_from_jsonv(string, NULL, errp); 608ff5a7d3SLuiz Capitulino } 618ff5a7d3SLuiz Capitulino 62668e3cacSLuiz Capitulino /* 63668e3cacSLuiz Capitulino * IMPORTANT: This function aborts on error, thus it must not 64668e3cacSLuiz Capitulino * be used with untrusted arguments. 65668e3cacSLuiz Capitulino */ 66b4748b9bSAnthony Liguori QObject *qobject_from_jsonf(const char *string, ...) 67b4748b9bSAnthony Liguori { 688ff5a7d3SLuiz Capitulino QObject *obj; 69b4748b9bSAnthony Liguori va_list ap; 70b4748b9bSAnthony Liguori 71b4748b9bSAnthony Liguori va_start(ap, string); 72ea5ef5c8SMarkus Armbruster obj = qobject_from_jsonv(string, &ap, &error_abort); 73b4748b9bSAnthony Liguori va_end(ap); 74b4748b9bSAnthony Liguori 75668e3cacSLuiz Capitulino assert(obj != NULL); 768ff5a7d3SLuiz Capitulino return obj; 77b4748b9bSAnthony Liguori } 781fd825f7SAnthony Liguori 79*a193352fSMarkus Armbruster /* 80*a193352fSMarkus Armbruster * Parse @string as JSON object with %-escapes interpolated. 81*a193352fSMarkus Armbruster * Abort on error. Do not use with untrusted @string. 82*a193352fSMarkus Armbruster * Return the resulting QDict. It is never null. 83*a193352fSMarkus Armbruster */ 84*a193352fSMarkus Armbruster QDict *qdict_from_jsonf_nofail(const char *string, ...) 85*a193352fSMarkus Armbruster { 86*a193352fSMarkus Armbruster QDict *obj; 87*a193352fSMarkus Armbruster va_list ap; 88*a193352fSMarkus Armbruster 89*a193352fSMarkus Armbruster va_start(ap, string); 90*a193352fSMarkus Armbruster obj = qobject_to(QDict, qobject_from_jsonv(string, &ap, &error_abort)); 91*a193352fSMarkus Armbruster va_end(ap); 92*a193352fSMarkus Armbruster 93*a193352fSMarkus Armbruster assert(obj); 94*a193352fSMarkus Armbruster return obj; 95*a193352fSMarkus Armbruster } 96*a193352fSMarkus Armbruster 971fd825f7SAnthony Liguori typedef struct ToJsonIterState 981fd825f7SAnthony Liguori { 99212b6008SDaniel P. Berrange int indent; 100212b6008SDaniel P. Berrange int pretty; 1011fd825f7SAnthony Liguori int count; 1021fd825f7SAnthony Liguori QString *str; 1031fd825f7SAnthony Liguori } ToJsonIterState; 1041fd825f7SAnthony Liguori 105212b6008SDaniel P. Berrange static void to_json(const QObject *obj, QString *str, int pretty, int indent); 1061fd825f7SAnthony Liguori 1071fd825f7SAnthony Liguori static void to_json_dict_iter(const char *key, QObject *obj, void *opaque) 1081fd825f7SAnthony Liguori { 1091fd825f7SAnthony Liguori ToJsonIterState *s = opaque; 1101fd825f7SAnthony Liguori QString *qkey; 111212b6008SDaniel P. Berrange int j; 1121fd825f7SAnthony Liguori 1134b58554aSMax Reitz if (s->count) { 1144b58554aSMax Reitz qstring_append(s->str, s->pretty ? "," : ", "); 1154b58554aSMax Reitz } 116212b6008SDaniel P. Berrange 117212b6008SDaniel P. Berrange if (s->pretty) { 118212b6008SDaniel P. Berrange qstring_append(s->str, "\n"); 119212b6008SDaniel P. Berrange for (j = 0 ; j < s->indent ; j++) 120212b6008SDaniel P. Berrange qstring_append(s->str, " "); 1211fd825f7SAnthony Liguori } 1221fd825f7SAnthony Liguori 1231fd825f7SAnthony Liguori qkey = qstring_from_str(key); 124212b6008SDaniel P. Berrange to_json(QOBJECT(qkey), s->str, s->pretty, s->indent); 125cb3e7f08SMarc-André Lureau qobject_unref(qkey); 1261fd825f7SAnthony Liguori 1271fd825f7SAnthony Liguori qstring_append(s->str, ": "); 128212b6008SDaniel P. Berrange to_json(obj, s->str, s->pretty, s->indent); 1291fd825f7SAnthony Liguori s->count++; 1301fd825f7SAnthony Liguori } 1311fd825f7SAnthony Liguori 1321fd825f7SAnthony Liguori static void to_json_list_iter(QObject *obj, void *opaque) 1331fd825f7SAnthony Liguori { 1341fd825f7SAnthony Liguori ToJsonIterState *s = opaque; 135212b6008SDaniel P. Berrange int j; 1361fd825f7SAnthony Liguori 1374b58554aSMax Reitz if (s->count) { 1384b58554aSMax Reitz qstring_append(s->str, s->pretty ? "," : ", "); 1394b58554aSMax Reitz } 140212b6008SDaniel P. Berrange 141212b6008SDaniel P. Berrange if (s->pretty) { 142212b6008SDaniel P. Berrange qstring_append(s->str, "\n"); 143212b6008SDaniel P. Berrange for (j = 0 ; j < s->indent ; j++) 144212b6008SDaniel P. Berrange qstring_append(s->str, " "); 1451fd825f7SAnthony Liguori } 1461fd825f7SAnthony Liguori 147212b6008SDaniel P. Berrange to_json(obj, s->str, s->pretty, s->indent); 1481fd825f7SAnthony Liguori s->count++; 1491fd825f7SAnthony Liguori } 1501fd825f7SAnthony Liguori 151212b6008SDaniel P. Berrange static void to_json(const QObject *obj, QString *str, int pretty, int indent) 1521fd825f7SAnthony Liguori { 1531fd825f7SAnthony Liguori switch (qobject_type(obj)) { 154481b002cSMarkus Armbruster case QTYPE_QNULL: 155481b002cSMarkus Armbruster qstring_append(str, "null"); 156481b002cSMarkus Armbruster break; 15701b2ffceSMarc-André Lureau case QTYPE_QNUM: { 1587dc847ebSMax Reitz QNum *val = qobject_to(QNum, obj); 15901b2ffceSMarc-André Lureau char *buffer = qnum_to_string(val); 1601fd825f7SAnthony Liguori qstring_append(str, buffer); 16101b2ffceSMarc-André Lureau g_free(buffer); 1621fd825f7SAnthony Liguori break; 1631fd825f7SAnthony Liguori } 1641fd825f7SAnthony Liguori case QTYPE_QSTRING: { 1657dc847ebSMax Reitz QString *val = qobject_to(QString, obj); 1661fd825f7SAnthony Liguori const char *ptr; 167e2ec3f97SMarkus Armbruster int cp; 168e2ec3f97SMarkus Armbruster char buf[16]; 169e2ec3f97SMarkus Armbruster char *end; 1701fd825f7SAnthony Liguori 1711fd825f7SAnthony Liguori ptr = qstring_get_str(val); 1721fd825f7SAnthony Liguori qstring_append(str, "\""); 1731fd825f7SAnthony Liguori 174e2ec3f97SMarkus Armbruster for (; *ptr; ptr = end) { 175e2ec3f97SMarkus Armbruster cp = mod_utf8_codepoint(ptr, 6, &end); 176e2ec3f97SMarkus Armbruster switch (cp) { 1771fd825f7SAnthony Liguori case '\"': 1781fd825f7SAnthony Liguori qstring_append(str, "\\\""); 1791fd825f7SAnthony Liguori break; 1801fd825f7SAnthony Liguori case '\\': 1811fd825f7SAnthony Liguori qstring_append(str, "\\\\"); 1821fd825f7SAnthony Liguori break; 1831fd825f7SAnthony Liguori case '\b': 1841fd825f7SAnthony Liguori qstring_append(str, "\\b"); 1851fd825f7SAnthony Liguori break; 186bd032695SLuiz Capitulino case '\f': 187bd032695SLuiz Capitulino qstring_append(str, "\\f"); 188bd032695SLuiz Capitulino break; 1891fd825f7SAnthony Liguori case '\n': 1901fd825f7SAnthony Liguori qstring_append(str, "\\n"); 1911fd825f7SAnthony Liguori break; 1921fd825f7SAnthony Liguori case '\r': 1931fd825f7SAnthony Liguori qstring_append(str, "\\r"); 1941fd825f7SAnthony Liguori break; 1951fd825f7SAnthony Liguori case '\t': 1961fd825f7SAnthony Liguori qstring_append(str, "\\t"); 1971fd825f7SAnthony Liguori break; 198e2ec3f97SMarkus Armbruster default: 199e2ec3f97SMarkus Armbruster if (cp < 0) { 200e2ec3f97SMarkus Armbruster cp = 0xFFFD; /* replacement character */ 201e2ec3f97SMarkus Armbruster } 202e2ec3f97SMarkus Armbruster if (cp > 0xFFFF) { 203e2ec3f97SMarkus Armbruster /* beyond BMP; need a surrogate pair */ 204e2ec3f97SMarkus Armbruster snprintf(buf, sizeof(buf), "\\u%04X\\u%04X", 205e2ec3f97SMarkus Armbruster 0xD800 + ((cp - 0x10000) >> 10), 206e2ec3f97SMarkus Armbruster 0xDC00 + ((cp - 0x10000) & 0x3FF)); 207e2ec3f97SMarkus Armbruster } else if (cp < 0x20 || cp >= 0x7F) { 208e2ec3f97SMarkus Armbruster snprintf(buf, sizeof(buf), "\\u%04X", cp); 209ff06ea21SAnthony Liguori } else { 210e2ec3f97SMarkus Armbruster buf[0] = cp; 211e2ec3f97SMarkus Armbruster buf[1] = 0; 212e2ec3f97SMarkus Armbruster } 2131fd825f7SAnthony Liguori qstring_append(str, buf); 214ff06ea21SAnthony Liguori } 215e2ec3f97SMarkus Armbruster }; 216e2ec3f97SMarkus Armbruster 2171fd825f7SAnthony Liguori qstring_append(str, "\""); 2181fd825f7SAnthony Liguori break; 2191fd825f7SAnthony Liguori } 2201fd825f7SAnthony Liguori case QTYPE_QDICT: { 2211fd825f7SAnthony Liguori ToJsonIterState s; 2227dc847ebSMax Reitz QDict *val = qobject_to(QDict, obj); 2231fd825f7SAnthony Liguori 2241fd825f7SAnthony Liguori s.count = 0; 2251fd825f7SAnthony Liguori s.str = str; 226212b6008SDaniel P. Berrange s.indent = indent + 1; 227212b6008SDaniel P. Berrange s.pretty = pretty; 2281fd825f7SAnthony Liguori qstring_append(str, "{"); 2291fd825f7SAnthony Liguori qdict_iter(val, to_json_dict_iter, &s); 230212b6008SDaniel P. Berrange if (pretty) { 231212b6008SDaniel P. Berrange int j; 232212b6008SDaniel P. Berrange qstring_append(str, "\n"); 233212b6008SDaniel P. Berrange for (j = 0 ; j < indent ; j++) 234212b6008SDaniel P. Berrange qstring_append(str, " "); 235212b6008SDaniel P. Berrange } 2361fd825f7SAnthony Liguori qstring_append(str, "}"); 2371fd825f7SAnthony Liguori break; 2381fd825f7SAnthony Liguori } 2391fd825f7SAnthony Liguori case QTYPE_QLIST: { 2401fd825f7SAnthony Liguori ToJsonIterState s; 2417dc847ebSMax Reitz QList *val = qobject_to(QList, obj); 2421fd825f7SAnthony Liguori 2431fd825f7SAnthony Liguori s.count = 0; 2441fd825f7SAnthony Liguori s.str = str; 245212b6008SDaniel P. Berrange s.indent = indent + 1; 246212b6008SDaniel P. Berrange s.pretty = pretty; 2471fd825f7SAnthony Liguori qstring_append(str, "["); 2481fd825f7SAnthony Liguori qlist_iter(val, (void *)to_json_list_iter, &s); 249212b6008SDaniel P. Berrange if (pretty) { 250212b6008SDaniel P. Berrange int j; 251212b6008SDaniel P. Berrange qstring_append(str, "\n"); 252212b6008SDaniel P. Berrange for (j = 0 ; j < indent ; j++) 253212b6008SDaniel P. Berrange qstring_append(str, " "); 254212b6008SDaniel P. Berrange } 2551fd825f7SAnthony Liguori qstring_append(str, "]"); 2561fd825f7SAnthony Liguori break; 2571fd825f7SAnthony Liguori } 2581fd825f7SAnthony Liguori case QTYPE_QBOOL: { 2597dc847ebSMax Reitz QBool *val = qobject_to(QBool, obj); 2601fd825f7SAnthony Liguori 261fc48ffc3SEric Blake if (qbool_get_bool(val)) { 2621fd825f7SAnthony Liguori qstring_append(str, "true"); 2631fd825f7SAnthony Liguori } else { 2641fd825f7SAnthony Liguori qstring_append(str, "false"); 2651fd825f7SAnthony Liguori } 2661fd825f7SAnthony Liguori break; 2671fd825f7SAnthony Liguori } 268a7c31816SMarkus Armbruster default: 26969dd62dfSKevin Wolf abort(); 2701fd825f7SAnthony Liguori } 2711fd825f7SAnthony Liguori } 2721fd825f7SAnthony Liguori 2731fd825f7SAnthony Liguori QString *qobject_to_json(const QObject *obj) 2741fd825f7SAnthony Liguori { 2751fd825f7SAnthony Liguori QString *str = qstring_new(); 2761fd825f7SAnthony Liguori 277212b6008SDaniel P. Berrange to_json(obj, str, 0, 0); 278212b6008SDaniel P. Berrange 279212b6008SDaniel P. Berrange return str; 280212b6008SDaniel P. Berrange } 281212b6008SDaniel P. Berrange 282212b6008SDaniel P. Berrange QString *qobject_to_json_pretty(const QObject *obj) 283212b6008SDaniel P. Berrange { 284212b6008SDaniel P. Berrange QString *str = qstring_new(); 285212b6008SDaniel P. Berrange 286212b6008SDaniel P. Berrange to_json(obj, str, 1, 0); 2871fd825f7SAnthony Liguori 2881fd825f7SAnthony Liguori return str; 2891fd825f7SAnthony Liguori } 290