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" 157b1b5d19SPaolo Bonzini #include "qapi/qmp/json-lexer.h" 167b1b5d19SPaolo Bonzini #include "qapi/qmp/json-parser.h" 177b1b5d19SPaolo Bonzini #include "qapi/qmp/json-streamer.h" 187b1b5d19SPaolo Bonzini #include "qapi/qmp/qjson.h" 197b1b5d19SPaolo Bonzini #include "qapi/qmp/qint.h" 207b1b5d19SPaolo Bonzini #include "qapi/qmp/qlist.h" 217b1b5d19SPaolo Bonzini #include "qapi/qmp/qbool.h" 227b1b5d19SPaolo Bonzini #include "qapi/qmp/qfloat.h" 237b1b5d19SPaolo Bonzini #include "qapi/qmp/qdict.h" 24b4748b9bSAnthony Liguori 25b4748b9bSAnthony Liguori typedef struct JSONParsingState 26b4748b9bSAnthony Liguori { 27b4748b9bSAnthony Liguori JSONMessageParser parser; 28b4748b9bSAnthony Liguori va_list *ap; 29b4748b9bSAnthony Liguori QObject *result; 30b4748b9bSAnthony Liguori } JSONParsingState; 31b4748b9bSAnthony Liguori 3295385fe9SPaolo Bonzini static void parse_json(JSONMessageParser *parser, GQueue *tokens) 33b4748b9bSAnthony Liguori { 34b4748b9bSAnthony Liguori JSONParsingState *s = container_of(parser, JSONParsingState, parser); 35b4748b9bSAnthony Liguori s->result = json_parser_parse(tokens, s->ap); 36b4748b9bSAnthony Liguori } 37b4748b9bSAnthony Liguori 388ff5a7d3SLuiz Capitulino QObject *qobject_from_jsonv(const char *string, va_list *ap) 39b4748b9bSAnthony Liguori { 40b4748b9bSAnthony Liguori JSONParsingState state = {}; 41b4748b9bSAnthony Liguori 428ff5a7d3SLuiz Capitulino state.ap = ap; 438ff5a7d3SLuiz Capitulino 44b4748b9bSAnthony Liguori json_message_parser_init(&state.parser, parse_json); 45b4748b9bSAnthony Liguori json_message_parser_feed(&state.parser, string, strlen(string)); 46b4748b9bSAnthony Liguori json_message_parser_flush(&state.parser); 47b4748b9bSAnthony Liguori json_message_parser_destroy(&state.parser); 48b4748b9bSAnthony Liguori 49b4748b9bSAnthony Liguori return state.result; 50b4748b9bSAnthony Liguori } 51b4748b9bSAnthony Liguori 528ff5a7d3SLuiz Capitulino QObject *qobject_from_json(const char *string) 538ff5a7d3SLuiz Capitulino { 548ff5a7d3SLuiz Capitulino return qobject_from_jsonv(string, NULL); 558ff5a7d3SLuiz Capitulino } 568ff5a7d3SLuiz Capitulino 57668e3cacSLuiz Capitulino /* 58668e3cacSLuiz Capitulino * IMPORTANT: This function aborts on error, thus it must not 59668e3cacSLuiz Capitulino * be used with untrusted arguments. 60668e3cacSLuiz Capitulino */ 61b4748b9bSAnthony Liguori QObject *qobject_from_jsonf(const char *string, ...) 62b4748b9bSAnthony Liguori { 638ff5a7d3SLuiz Capitulino QObject *obj; 64b4748b9bSAnthony Liguori va_list ap; 65b4748b9bSAnthony Liguori 66b4748b9bSAnthony Liguori va_start(ap, string); 678ff5a7d3SLuiz Capitulino obj = qobject_from_jsonv(string, &ap); 68b4748b9bSAnthony Liguori va_end(ap); 69b4748b9bSAnthony Liguori 70668e3cacSLuiz Capitulino assert(obj != NULL); 718ff5a7d3SLuiz Capitulino return obj; 72b4748b9bSAnthony Liguori } 731fd825f7SAnthony Liguori 741fd825f7SAnthony Liguori typedef struct ToJsonIterState 751fd825f7SAnthony Liguori { 76212b6008SDaniel P. Berrange int indent; 77212b6008SDaniel P. Berrange int pretty; 781fd825f7SAnthony Liguori int count; 791fd825f7SAnthony Liguori QString *str; 801fd825f7SAnthony Liguori } ToJsonIterState; 811fd825f7SAnthony Liguori 82212b6008SDaniel P. Berrange static void to_json(const QObject *obj, QString *str, int pretty, int indent); 831fd825f7SAnthony Liguori 841fd825f7SAnthony Liguori static void to_json_dict_iter(const char *key, QObject *obj, void *opaque) 851fd825f7SAnthony Liguori { 861fd825f7SAnthony Liguori ToJsonIterState *s = opaque; 871fd825f7SAnthony Liguori QString *qkey; 88212b6008SDaniel P. Berrange int j; 891fd825f7SAnthony Liguori 904b58554aSMax Reitz if (s->count) { 914b58554aSMax Reitz qstring_append(s->str, s->pretty ? "," : ", "); 924b58554aSMax Reitz } 93212b6008SDaniel P. Berrange 94212b6008SDaniel P. Berrange if (s->pretty) { 95212b6008SDaniel P. Berrange qstring_append(s->str, "\n"); 96212b6008SDaniel P. Berrange for (j = 0 ; j < s->indent ; j++) 97212b6008SDaniel P. Berrange qstring_append(s->str, " "); 981fd825f7SAnthony Liguori } 991fd825f7SAnthony Liguori 1001fd825f7SAnthony Liguori qkey = qstring_from_str(key); 101212b6008SDaniel P. Berrange to_json(QOBJECT(qkey), s->str, s->pretty, s->indent); 1021fd825f7SAnthony Liguori QDECREF(qkey); 1031fd825f7SAnthony Liguori 1041fd825f7SAnthony Liguori qstring_append(s->str, ": "); 105212b6008SDaniel P. Berrange to_json(obj, s->str, s->pretty, s->indent); 1061fd825f7SAnthony Liguori s->count++; 1071fd825f7SAnthony Liguori } 1081fd825f7SAnthony Liguori 1091fd825f7SAnthony Liguori static void to_json_list_iter(QObject *obj, void *opaque) 1101fd825f7SAnthony Liguori { 1111fd825f7SAnthony Liguori ToJsonIterState *s = opaque; 112212b6008SDaniel P. Berrange int j; 1131fd825f7SAnthony Liguori 1144b58554aSMax Reitz if (s->count) { 1154b58554aSMax Reitz qstring_append(s->str, s->pretty ? "," : ", "); 1164b58554aSMax Reitz } 117212b6008SDaniel P. Berrange 118212b6008SDaniel P. Berrange if (s->pretty) { 119212b6008SDaniel P. Berrange qstring_append(s->str, "\n"); 120212b6008SDaniel P. Berrange for (j = 0 ; j < s->indent ; j++) 121212b6008SDaniel P. Berrange qstring_append(s->str, " "); 1221fd825f7SAnthony Liguori } 1231fd825f7SAnthony Liguori 124212b6008SDaniel P. Berrange to_json(obj, s->str, s->pretty, s->indent); 1251fd825f7SAnthony Liguori s->count++; 1261fd825f7SAnthony Liguori } 1271fd825f7SAnthony Liguori 128212b6008SDaniel P. Berrange static void to_json(const QObject *obj, QString *str, int pretty, int indent) 1291fd825f7SAnthony Liguori { 1301fd825f7SAnthony Liguori switch (qobject_type(obj)) { 131481b002cSMarkus Armbruster case QTYPE_QNULL: 132481b002cSMarkus Armbruster qstring_append(str, "null"); 133481b002cSMarkus Armbruster break; 1341fd825f7SAnthony Liguori case QTYPE_QINT: { 1351fd825f7SAnthony Liguori QInt *val = qobject_to_qint(obj); 1361fd825f7SAnthony Liguori char buffer[1024]; 1371fd825f7SAnthony Liguori 1381fd825f7SAnthony Liguori snprintf(buffer, sizeof(buffer), "%" PRId64, qint_get_int(val)); 1391fd825f7SAnthony Liguori qstring_append(str, buffer); 1401fd825f7SAnthony Liguori break; 1411fd825f7SAnthony Liguori } 1421fd825f7SAnthony Liguori case QTYPE_QSTRING: { 1431fd825f7SAnthony Liguori QString *val = qobject_to_qstring(obj); 1441fd825f7SAnthony Liguori const char *ptr; 145e2ec3f97SMarkus Armbruster int cp; 146e2ec3f97SMarkus Armbruster char buf[16]; 147e2ec3f97SMarkus Armbruster char *end; 1481fd825f7SAnthony Liguori 1491fd825f7SAnthony Liguori ptr = qstring_get_str(val); 1501fd825f7SAnthony Liguori qstring_append(str, "\""); 1511fd825f7SAnthony Liguori 152e2ec3f97SMarkus Armbruster for (; *ptr; ptr = end) { 153e2ec3f97SMarkus Armbruster cp = mod_utf8_codepoint(ptr, 6, &end); 154e2ec3f97SMarkus Armbruster switch (cp) { 1551fd825f7SAnthony Liguori case '\"': 1561fd825f7SAnthony Liguori qstring_append(str, "\\\""); 1571fd825f7SAnthony Liguori break; 1581fd825f7SAnthony Liguori case '\\': 1591fd825f7SAnthony Liguori qstring_append(str, "\\\\"); 1601fd825f7SAnthony Liguori break; 1611fd825f7SAnthony Liguori case '\b': 1621fd825f7SAnthony Liguori qstring_append(str, "\\b"); 1631fd825f7SAnthony Liguori break; 164bd032695SLuiz Capitulino case '\f': 165bd032695SLuiz Capitulino qstring_append(str, "\\f"); 166bd032695SLuiz Capitulino break; 1671fd825f7SAnthony Liguori case '\n': 1681fd825f7SAnthony Liguori qstring_append(str, "\\n"); 1691fd825f7SAnthony Liguori break; 1701fd825f7SAnthony Liguori case '\r': 1711fd825f7SAnthony Liguori qstring_append(str, "\\r"); 1721fd825f7SAnthony Liguori break; 1731fd825f7SAnthony Liguori case '\t': 1741fd825f7SAnthony Liguori qstring_append(str, "\\t"); 1751fd825f7SAnthony Liguori break; 176e2ec3f97SMarkus Armbruster default: 177e2ec3f97SMarkus Armbruster if (cp < 0) { 178e2ec3f97SMarkus Armbruster cp = 0xFFFD; /* replacement character */ 179e2ec3f97SMarkus Armbruster } 180e2ec3f97SMarkus Armbruster if (cp > 0xFFFF) { 181e2ec3f97SMarkus Armbruster /* beyond BMP; need a surrogate pair */ 182e2ec3f97SMarkus Armbruster snprintf(buf, sizeof(buf), "\\u%04X\\u%04X", 183e2ec3f97SMarkus Armbruster 0xD800 + ((cp - 0x10000) >> 10), 184e2ec3f97SMarkus Armbruster 0xDC00 + ((cp - 0x10000) & 0x3FF)); 185e2ec3f97SMarkus Armbruster } else if (cp < 0x20 || cp >= 0x7F) { 186e2ec3f97SMarkus Armbruster snprintf(buf, sizeof(buf), "\\u%04X", cp); 187ff06ea21SAnthony Liguori } else { 188e2ec3f97SMarkus Armbruster buf[0] = cp; 189e2ec3f97SMarkus Armbruster buf[1] = 0; 190e2ec3f97SMarkus Armbruster } 1911fd825f7SAnthony Liguori qstring_append(str, buf); 192ff06ea21SAnthony Liguori } 193e2ec3f97SMarkus Armbruster }; 194e2ec3f97SMarkus Armbruster 1951fd825f7SAnthony Liguori qstring_append(str, "\""); 1961fd825f7SAnthony Liguori break; 1971fd825f7SAnthony Liguori } 1981fd825f7SAnthony Liguori case QTYPE_QDICT: { 1991fd825f7SAnthony Liguori ToJsonIterState s; 2001fd825f7SAnthony Liguori QDict *val = qobject_to_qdict(obj); 2011fd825f7SAnthony Liguori 2021fd825f7SAnthony Liguori s.count = 0; 2031fd825f7SAnthony Liguori s.str = str; 204212b6008SDaniel P. Berrange s.indent = indent + 1; 205212b6008SDaniel P. Berrange s.pretty = pretty; 2061fd825f7SAnthony Liguori qstring_append(str, "{"); 2071fd825f7SAnthony Liguori qdict_iter(val, to_json_dict_iter, &s); 208212b6008SDaniel P. Berrange if (pretty) { 209212b6008SDaniel P. Berrange int j; 210212b6008SDaniel P. Berrange qstring_append(str, "\n"); 211212b6008SDaniel P. Berrange for (j = 0 ; j < indent ; j++) 212212b6008SDaniel P. Berrange qstring_append(str, " "); 213212b6008SDaniel P. Berrange } 2141fd825f7SAnthony Liguori qstring_append(str, "}"); 2151fd825f7SAnthony Liguori break; 2161fd825f7SAnthony Liguori } 2171fd825f7SAnthony Liguori case QTYPE_QLIST: { 2181fd825f7SAnthony Liguori ToJsonIterState s; 2191fd825f7SAnthony Liguori QList *val = qobject_to_qlist(obj); 2201fd825f7SAnthony Liguori 2211fd825f7SAnthony Liguori s.count = 0; 2221fd825f7SAnthony Liguori s.str = str; 223212b6008SDaniel P. Berrange s.indent = indent + 1; 224212b6008SDaniel P. Berrange s.pretty = pretty; 2251fd825f7SAnthony Liguori qstring_append(str, "["); 2261fd825f7SAnthony Liguori qlist_iter(val, (void *)to_json_list_iter, &s); 227212b6008SDaniel P. Berrange if (pretty) { 228212b6008SDaniel P. Berrange int j; 229212b6008SDaniel P. Berrange qstring_append(str, "\n"); 230212b6008SDaniel P. Berrange for (j = 0 ; j < indent ; j++) 231212b6008SDaniel P. Berrange qstring_append(str, " "); 232212b6008SDaniel P. Berrange } 2331fd825f7SAnthony Liguori qstring_append(str, "]"); 2341fd825f7SAnthony Liguori break; 2351fd825f7SAnthony Liguori } 2361fd825f7SAnthony Liguori case QTYPE_QFLOAT: { 2371fd825f7SAnthony Liguori QFloat *val = qobject_to_qfloat(obj); 2381fd825f7SAnthony Liguori char buffer[1024]; 2391fd825f7SAnthony Liguori int len; 2401fd825f7SAnthony Liguori 241*6e8e5cb9SEric Blake /* FIXME: snprintf() is locale dependent; but JSON requires 242*6e8e5cb9SEric Blake * numbers to be formatted as if in the C locale. Dependence 243*6e8e5cb9SEric Blake * on C locale is a pervasive issue in QEMU. */ 244*6e8e5cb9SEric Blake /* FIXME: This risks printing Inf or NaN, which are not valid 245*6e8e5cb9SEric Blake * JSON values. */ 246*6e8e5cb9SEric Blake /* FIXME: the default precision of 6 for %f often causes 247*6e8e5cb9SEric Blake * rounding errors; we should be using DBL_DECIMAL_DIG (17), 248*6e8e5cb9SEric Blake * and only rounding to a shorter number if the result would 249*6e8e5cb9SEric Blake * still produce the same floating point value. */ 2501fd825f7SAnthony Liguori len = snprintf(buffer, sizeof(buffer), "%f", qfloat_get_double(val)); 2511fd825f7SAnthony Liguori while (len > 0 && buffer[len - 1] == '0') { 2521fd825f7SAnthony Liguori len--; 2531fd825f7SAnthony Liguori } 2541fd825f7SAnthony Liguori 2551fd825f7SAnthony Liguori if (len && buffer[len - 1] == '.') { 2561fd825f7SAnthony Liguori buffer[len - 1] = 0; 2571fd825f7SAnthony Liguori } else { 2581fd825f7SAnthony Liguori buffer[len] = 0; 2591fd825f7SAnthony Liguori } 2601fd825f7SAnthony Liguori 2611fd825f7SAnthony Liguori qstring_append(str, buffer); 2621fd825f7SAnthony Liguori break; 2631fd825f7SAnthony Liguori } 2641fd825f7SAnthony Liguori case QTYPE_QBOOL: { 2651fd825f7SAnthony Liguori QBool *val = qobject_to_qbool(obj); 2661fd825f7SAnthony Liguori 267fc48ffc3SEric Blake if (qbool_get_bool(val)) { 2681fd825f7SAnthony Liguori qstring_append(str, "true"); 2691fd825f7SAnthony Liguori } else { 2701fd825f7SAnthony Liguori qstring_append(str, "false"); 2711fd825f7SAnthony Liguori } 2721fd825f7SAnthony Liguori break; 2731fd825f7SAnthony Liguori } 274a7c31816SMarkus Armbruster default: 27569dd62dfSKevin Wolf abort(); 2761fd825f7SAnthony Liguori } 2771fd825f7SAnthony Liguori } 2781fd825f7SAnthony Liguori 2791fd825f7SAnthony Liguori QString *qobject_to_json(const QObject *obj) 2801fd825f7SAnthony Liguori { 2811fd825f7SAnthony Liguori QString *str = qstring_new(); 2821fd825f7SAnthony Liguori 283212b6008SDaniel P. Berrange to_json(obj, str, 0, 0); 284212b6008SDaniel P. Berrange 285212b6008SDaniel P. Berrange return str; 286212b6008SDaniel P. Berrange } 287212b6008SDaniel P. Berrange 288212b6008SDaniel P. Berrange QString *qobject_to_json_pretty(const QObject *obj) 289212b6008SDaniel P. Berrange { 290212b6008SDaniel P. Berrange QString *str = qstring_new(); 291212b6008SDaniel P. Berrange 292212b6008SDaniel P. Berrange to_json(obj, str, 1, 0); 2931fd825f7SAnthony Liguori 2941fd825f7SAnthony Liguori return str; 2951fd825f7SAnthony Liguori } 296