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 14b4748b9bSAnthony Liguori #include "json-lexer.h" 15b4748b9bSAnthony Liguori #include "json-parser.h" 16b4748b9bSAnthony Liguori #include "json-streamer.h" 17b4748b9bSAnthony Liguori #include "qjson.h" 181fd825f7SAnthony Liguori #include "qint.h" 191fd825f7SAnthony Liguori #include "qlist.h" 201fd825f7SAnthony Liguori #include "qbool.h" 211fd825f7SAnthony Liguori #include "qfloat.h" 221fd825f7SAnthony Liguori #include "qdict.h" 23b4748b9bSAnthony Liguori 24b4748b9bSAnthony Liguori typedef struct JSONParsingState 25b4748b9bSAnthony Liguori { 26b4748b9bSAnthony Liguori JSONMessageParser parser; 27b4748b9bSAnthony Liguori va_list *ap; 28b4748b9bSAnthony Liguori QObject *result; 29b4748b9bSAnthony Liguori } JSONParsingState; 30b4748b9bSAnthony Liguori 31b4748b9bSAnthony Liguori static void parse_json(JSONMessageParser *parser, QList *tokens) 32b4748b9bSAnthony Liguori { 33b4748b9bSAnthony Liguori JSONParsingState *s = container_of(parser, JSONParsingState, parser); 34b4748b9bSAnthony Liguori s->result = json_parser_parse(tokens, s->ap); 35b4748b9bSAnthony Liguori } 36b4748b9bSAnthony Liguori 378ff5a7d3SLuiz Capitulino QObject *qobject_from_jsonv(const char *string, va_list *ap) 38b4748b9bSAnthony Liguori { 39b4748b9bSAnthony Liguori JSONParsingState state = {}; 40b4748b9bSAnthony Liguori 418ff5a7d3SLuiz Capitulino state.ap = ap; 428ff5a7d3SLuiz Capitulino 43b4748b9bSAnthony Liguori json_message_parser_init(&state.parser, parse_json); 44b4748b9bSAnthony Liguori json_message_parser_feed(&state.parser, string, strlen(string)); 45b4748b9bSAnthony Liguori json_message_parser_flush(&state.parser); 46b4748b9bSAnthony Liguori json_message_parser_destroy(&state.parser); 47b4748b9bSAnthony Liguori 48b4748b9bSAnthony Liguori return state.result; 49b4748b9bSAnthony Liguori } 50b4748b9bSAnthony Liguori 518ff5a7d3SLuiz Capitulino QObject *qobject_from_json(const char *string) 528ff5a7d3SLuiz Capitulino { 538ff5a7d3SLuiz Capitulino return qobject_from_jsonv(string, NULL); 548ff5a7d3SLuiz Capitulino } 558ff5a7d3SLuiz Capitulino 56668e3cacSLuiz Capitulino /* 57668e3cacSLuiz Capitulino * IMPORTANT: This function aborts on error, thus it must not 58668e3cacSLuiz Capitulino * be used with untrusted arguments. 59668e3cacSLuiz Capitulino */ 60b4748b9bSAnthony Liguori QObject *qobject_from_jsonf(const char *string, ...) 61b4748b9bSAnthony Liguori { 628ff5a7d3SLuiz Capitulino QObject *obj; 63b4748b9bSAnthony Liguori va_list ap; 64b4748b9bSAnthony Liguori 65b4748b9bSAnthony Liguori va_start(ap, string); 668ff5a7d3SLuiz Capitulino obj = qobject_from_jsonv(string, &ap); 67b4748b9bSAnthony Liguori va_end(ap); 68b4748b9bSAnthony Liguori 69668e3cacSLuiz Capitulino assert(obj != NULL); 708ff5a7d3SLuiz Capitulino return obj; 71b4748b9bSAnthony Liguori } 721fd825f7SAnthony Liguori 731fd825f7SAnthony Liguori typedef struct ToJsonIterState 741fd825f7SAnthony Liguori { 751fd825f7SAnthony Liguori int count; 761fd825f7SAnthony Liguori QString *str; 771fd825f7SAnthony Liguori } ToJsonIterState; 781fd825f7SAnthony Liguori 791fd825f7SAnthony Liguori static void to_json(const QObject *obj, QString *str); 801fd825f7SAnthony Liguori 811fd825f7SAnthony Liguori static void to_json_dict_iter(const char *key, QObject *obj, void *opaque) 821fd825f7SAnthony Liguori { 831fd825f7SAnthony Liguori ToJsonIterState *s = opaque; 841fd825f7SAnthony Liguori QString *qkey; 851fd825f7SAnthony Liguori 861fd825f7SAnthony Liguori if (s->count) { 871fd825f7SAnthony Liguori qstring_append(s->str, ", "); 881fd825f7SAnthony Liguori } 891fd825f7SAnthony Liguori 901fd825f7SAnthony Liguori qkey = qstring_from_str(key); 911fd825f7SAnthony Liguori to_json(QOBJECT(qkey), s->str); 921fd825f7SAnthony Liguori QDECREF(qkey); 931fd825f7SAnthony Liguori 941fd825f7SAnthony Liguori qstring_append(s->str, ": "); 951fd825f7SAnthony Liguori to_json(obj, s->str); 961fd825f7SAnthony Liguori s->count++; 971fd825f7SAnthony Liguori } 981fd825f7SAnthony Liguori 991fd825f7SAnthony Liguori static void to_json_list_iter(QObject *obj, void *opaque) 1001fd825f7SAnthony Liguori { 1011fd825f7SAnthony Liguori ToJsonIterState *s = opaque; 1021fd825f7SAnthony Liguori 1031fd825f7SAnthony Liguori if (s->count) { 1041fd825f7SAnthony Liguori qstring_append(s->str, ", "); 1051fd825f7SAnthony Liguori } 1061fd825f7SAnthony Liguori 1071fd825f7SAnthony Liguori to_json(obj, s->str); 1081fd825f7SAnthony Liguori s->count++; 1091fd825f7SAnthony Liguori } 1101fd825f7SAnthony Liguori 1111fd825f7SAnthony Liguori static void to_json(const QObject *obj, QString *str) 1121fd825f7SAnthony Liguori { 1131fd825f7SAnthony Liguori switch (qobject_type(obj)) { 1141fd825f7SAnthony Liguori case QTYPE_QINT: { 1151fd825f7SAnthony Liguori QInt *val = qobject_to_qint(obj); 1161fd825f7SAnthony Liguori char buffer[1024]; 1171fd825f7SAnthony Liguori 1181fd825f7SAnthony Liguori snprintf(buffer, sizeof(buffer), "%" PRId64, qint_get_int(val)); 1191fd825f7SAnthony Liguori qstring_append(str, buffer); 1201fd825f7SAnthony Liguori break; 1211fd825f7SAnthony Liguori } 1221fd825f7SAnthony Liguori case QTYPE_QSTRING: { 1231fd825f7SAnthony Liguori QString *val = qobject_to_qstring(obj); 1241fd825f7SAnthony Liguori const char *ptr; 1251fd825f7SAnthony Liguori 1261fd825f7SAnthony Liguori ptr = qstring_get_str(val); 1271fd825f7SAnthony Liguori qstring_append(str, "\""); 1281fd825f7SAnthony Liguori while (*ptr) { 1291fd825f7SAnthony Liguori if ((ptr[0] & 0xE0) == 0xE0 && 1301fd825f7SAnthony Liguori (ptr[1] & 0x80) && (ptr[2] & 0x80)) { 1311fd825f7SAnthony Liguori uint16_t wchar; 1321fd825f7SAnthony Liguori char escape[7]; 1331fd825f7SAnthony Liguori 1341fd825f7SAnthony Liguori wchar = (ptr[0] & 0x0F) << 12; 1351fd825f7SAnthony Liguori wchar |= (ptr[1] & 0x3F) << 6; 1361fd825f7SAnthony Liguori wchar |= (ptr[2] & 0x3F); 1371fd825f7SAnthony Liguori ptr += 2; 1381fd825f7SAnthony Liguori 1391fd825f7SAnthony Liguori snprintf(escape, sizeof(escape), "\\u%04X", wchar); 1401fd825f7SAnthony Liguori qstring_append(str, escape); 1411fd825f7SAnthony Liguori } else if ((ptr[0] & 0xE0) == 0xC0 && (ptr[1] & 0x80)) { 1421fd825f7SAnthony Liguori uint16_t wchar; 1431fd825f7SAnthony Liguori char escape[7]; 1441fd825f7SAnthony Liguori 1451fd825f7SAnthony Liguori wchar = (ptr[0] & 0x1F) << 6; 1461fd825f7SAnthony Liguori wchar |= (ptr[1] & 0x3F); 1471fd825f7SAnthony Liguori ptr++; 1481fd825f7SAnthony Liguori 1491fd825f7SAnthony Liguori snprintf(escape, sizeof(escape), "\\u%04X", wchar); 1501fd825f7SAnthony Liguori qstring_append(str, escape); 1511fd825f7SAnthony Liguori } else switch (ptr[0]) { 1521fd825f7SAnthony Liguori case '\"': 1531fd825f7SAnthony Liguori qstring_append(str, "\\\""); 1541fd825f7SAnthony Liguori break; 1551fd825f7SAnthony Liguori case '\\': 1561fd825f7SAnthony Liguori qstring_append(str, "\\\\"); 1571fd825f7SAnthony Liguori break; 1581fd825f7SAnthony Liguori case '\b': 1591fd825f7SAnthony Liguori qstring_append(str, "\\b"); 1601fd825f7SAnthony Liguori break; 161*bd032695SLuiz Capitulino case '\f': 162*bd032695SLuiz Capitulino qstring_append(str, "\\f"); 163*bd032695SLuiz Capitulino break; 1641fd825f7SAnthony Liguori case '\n': 1651fd825f7SAnthony Liguori qstring_append(str, "\\n"); 1661fd825f7SAnthony Liguori break; 1671fd825f7SAnthony Liguori case '\r': 1681fd825f7SAnthony Liguori qstring_append(str, "\\r"); 1691fd825f7SAnthony Liguori break; 1701fd825f7SAnthony Liguori case '\t': 1711fd825f7SAnthony Liguori qstring_append(str, "\\t"); 1721fd825f7SAnthony Liguori break; 1731fd825f7SAnthony Liguori default: { 174ff06ea21SAnthony Liguori if (ptr[0] <= 0x1F) { 175ff06ea21SAnthony Liguori char escape[7]; 176ff06ea21SAnthony Liguori snprintf(escape, sizeof(escape), "\\u%04X", ptr[0]); 177ff06ea21SAnthony Liguori qstring_append(str, escape); 178ff06ea21SAnthony Liguori } else { 1791fd825f7SAnthony Liguori char buf[2] = { ptr[0], 0 }; 1801fd825f7SAnthony Liguori qstring_append(str, buf); 181ff06ea21SAnthony Liguori } 1821fd825f7SAnthony Liguori break; 1831fd825f7SAnthony Liguori } 1841fd825f7SAnthony Liguori } 1851fd825f7SAnthony Liguori ptr++; 1861fd825f7SAnthony Liguori } 1871fd825f7SAnthony Liguori qstring_append(str, "\""); 1881fd825f7SAnthony Liguori break; 1891fd825f7SAnthony Liguori } 1901fd825f7SAnthony Liguori case QTYPE_QDICT: { 1911fd825f7SAnthony Liguori ToJsonIterState s; 1921fd825f7SAnthony Liguori QDict *val = qobject_to_qdict(obj); 1931fd825f7SAnthony Liguori 1941fd825f7SAnthony Liguori s.count = 0; 1951fd825f7SAnthony Liguori s.str = str; 1961fd825f7SAnthony Liguori qstring_append(str, "{"); 1971fd825f7SAnthony Liguori qdict_iter(val, to_json_dict_iter, &s); 1981fd825f7SAnthony Liguori qstring_append(str, "}"); 1991fd825f7SAnthony Liguori break; 2001fd825f7SAnthony Liguori } 2011fd825f7SAnthony Liguori case QTYPE_QLIST: { 2021fd825f7SAnthony Liguori ToJsonIterState s; 2031fd825f7SAnthony Liguori QList *val = qobject_to_qlist(obj); 2041fd825f7SAnthony Liguori 2051fd825f7SAnthony Liguori s.count = 0; 2061fd825f7SAnthony Liguori s.str = str; 2071fd825f7SAnthony Liguori qstring_append(str, "["); 2081fd825f7SAnthony Liguori qlist_iter(val, (void *)to_json_list_iter, &s); 2091fd825f7SAnthony Liguori qstring_append(str, "]"); 2101fd825f7SAnthony Liguori break; 2111fd825f7SAnthony Liguori } 2121fd825f7SAnthony Liguori case QTYPE_QFLOAT: { 2131fd825f7SAnthony Liguori QFloat *val = qobject_to_qfloat(obj); 2141fd825f7SAnthony Liguori char buffer[1024]; 2151fd825f7SAnthony Liguori int len; 2161fd825f7SAnthony Liguori 2171fd825f7SAnthony Liguori len = snprintf(buffer, sizeof(buffer), "%f", qfloat_get_double(val)); 2181fd825f7SAnthony Liguori while (len > 0 && buffer[len - 1] == '0') { 2191fd825f7SAnthony Liguori len--; 2201fd825f7SAnthony Liguori } 2211fd825f7SAnthony Liguori 2221fd825f7SAnthony Liguori if (len && buffer[len - 1] == '.') { 2231fd825f7SAnthony Liguori buffer[len - 1] = 0; 2241fd825f7SAnthony Liguori } else { 2251fd825f7SAnthony Liguori buffer[len] = 0; 2261fd825f7SAnthony Liguori } 2271fd825f7SAnthony Liguori 2281fd825f7SAnthony Liguori qstring_append(str, buffer); 2291fd825f7SAnthony Liguori break; 2301fd825f7SAnthony Liguori } 2311fd825f7SAnthony Liguori case QTYPE_QBOOL: { 2321fd825f7SAnthony Liguori QBool *val = qobject_to_qbool(obj); 2331fd825f7SAnthony Liguori 2341fd825f7SAnthony Liguori if (qbool_get_int(val)) { 2351fd825f7SAnthony Liguori qstring_append(str, "true"); 2361fd825f7SAnthony Liguori } else { 2371fd825f7SAnthony Liguori qstring_append(str, "false"); 2381fd825f7SAnthony Liguori } 2391fd825f7SAnthony Liguori break; 2401fd825f7SAnthony Liguori } 2419f9daf9aSLuiz Capitulino case QTYPE_QERROR: 2429f9daf9aSLuiz Capitulino /* XXX: should QError be emitted? */ 2431fd825f7SAnthony Liguori case QTYPE_NONE: 2441fd825f7SAnthony Liguori break; 2451fd825f7SAnthony Liguori } 2461fd825f7SAnthony Liguori } 2471fd825f7SAnthony Liguori 2481fd825f7SAnthony Liguori QString *qobject_to_json(const QObject *obj) 2491fd825f7SAnthony Liguori { 2501fd825f7SAnthony Liguori QString *str = qstring_new(); 2511fd825f7SAnthony Liguori 2521fd825f7SAnthony Liguori to_json(obj, str); 2531fd825f7SAnthony Liguori 2541fd825f7SAnthony Liguori return str; 2551fd825f7SAnthony Liguori } 256