1 /* 2 * QObject JSON integration 3 * 4 * Copyright IBM, Corp. 2009 5 * 6 * Authors: 7 * Anthony Liguori <aliguori (at) us.ibm.com> 8 * 9 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. 10 * See the COPYING.LIB file in the top-level directory. 11 * 12 */ 13 14 #include "json-lexer.h" 15 #include "json-parser.h" 16 #include "json-streamer.h" 17 #include "qjson.h" 18 #include "qint.h" 19 #include "qlist.h" 20 #include "qbool.h" 21 #include "qfloat.h" 22 #include "qdict.h" 23 24 typedef struct JSONParsingState 25 { 26 JSONMessageParser parser; 27 va_list *ap; 28 QObject *result; 29 } JSONParsingState; 30 31 static void parse_json(JSONMessageParser *parser, QList *tokens) 32 { 33 JSONParsingState *s = container_of(parser, JSONParsingState, parser); 34 s->result = json_parser_parse(tokens, s->ap); 35 } 36 37 QObject *qobject_from_jsonv(const char *string, va_list *ap) 38 { 39 JSONParsingState state = {}; 40 41 state.ap = ap; 42 43 json_message_parser_init(&state.parser, parse_json); 44 json_message_parser_feed(&state.parser, string, strlen(string)); 45 json_message_parser_flush(&state.parser); 46 json_message_parser_destroy(&state.parser); 47 48 return state.result; 49 } 50 51 QObject *qobject_from_json(const char *string) 52 { 53 return qobject_from_jsonv(string, NULL); 54 } 55 56 /* 57 * IMPORTANT: This function aborts on error, thus it must not 58 * be used with untrusted arguments. 59 */ 60 QObject *qobject_from_jsonf(const char *string, ...) 61 { 62 QObject *obj; 63 va_list ap; 64 65 va_start(ap, string); 66 obj = qobject_from_jsonv(string, &ap); 67 va_end(ap); 68 69 assert(obj != NULL); 70 return obj; 71 } 72 73 typedef struct ToJsonIterState 74 { 75 int count; 76 QString *str; 77 } ToJsonIterState; 78 79 static void to_json(const QObject *obj, QString *str); 80 81 static void to_json_dict_iter(const char *key, QObject *obj, void *opaque) 82 { 83 ToJsonIterState *s = opaque; 84 QString *qkey; 85 86 if (s->count) { 87 qstring_append(s->str, ", "); 88 } 89 90 qkey = qstring_from_str(key); 91 to_json(QOBJECT(qkey), s->str); 92 QDECREF(qkey); 93 94 qstring_append(s->str, ": "); 95 to_json(obj, s->str); 96 s->count++; 97 } 98 99 static void to_json_list_iter(QObject *obj, void *opaque) 100 { 101 ToJsonIterState *s = opaque; 102 103 if (s->count) { 104 qstring_append(s->str, ", "); 105 } 106 107 to_json(obj, s->str); 108 s->count++; 109 } 110 111 static void to_json(const QObject *obj, QString *str) 112 { 113 switch (qobject_type(obj)) { 114 case QTYPE_QINT: { 115 QInt *val = qobject_to_qint(obj); 116 char buffer[1024]; 117 118 snprintf(buffer, sizeof(buffer), "%" PRId64, qint_get_int(val)); 119 qstring_append(str, buffer); 120 break; 121 } 122 case QTYPE_QSTRING: { 123 QString *val = qobject_to_qstring(obj); 124 const char *ptr; 125 126 ptr = qstring_get_str(val); 127 qstring_append(str, "\""); 128 while (*ptr) { 129 if ((ptr[0] & 0xE0) == 0xE0 && 130 (ptr[1] & 0x80) && (ptr[2] & 0x80)) { 131 uint16_t wchar; 132 char escape[7]; 133 134 wchar = (ptr[0] & 0x0F) << 12; 135 wchar |= (ptr[1] & 0x3F) << 6; 136 wchar |= (ptr[2] & 0x3F); 137 ptr += 2; 138 139 snprintf(escape, sizeof(escape), "\\u%04X", wchar); 140 qstring_append(str, escape); 141 } else if ((ptr[0] & 0xE0) == 0xC0 && (ptr[1] & 0x80)) { 142 uint16_t wchar; 143 char escape[7]; 144 145 wchar = (ptr[0] & 0x1F) << 6; 146 wchar |= (ptr[1] & 0x3F); 147 ptr++; 148 149 snprintf(escape, sizeof(escape), "\\u%04X", wchar); 150 qstring_append(str, escape); 151 } else switch (ptr[0]) { 152 case '\"': 153 qstring_append(str, "\\\""); 154 break; 155 case '\\': 156 qstring_append(str, "\\\\"); 157 break; 158 case '\b': 159 qstring_append(str, "\\b"); 160 break; 161 case '\n': 162 qstring_append(str, "\\n"); 163 break; 164 case '\r': 165 qstring_append(str, "\\r"); 166 break; 167 case '\t': 168 qstring_append(str, "\\t"); 169 break; 170 default: { 171 if (ptr[0] <= 0x1F) { 172 char escape[7]; 173 snprintf(escape, sizeof(escape), "\\u%04X", ptr[0]); 174 qstring_append(str, escape); 175 } else { 176 char buf[2] = { ptr[0], 0 }; 177 qstring_append(str, buf); 178 } 179 break; 180 } 181 } 182 ptr++; 183 } 184 qstring_append(str, "\""); 185 break; 186 } 187 case QTYPE_QDICT: { 188 ToJsonIterState s; 189 QDict *val = qobject_to_qdict(obj); 190 191 s.count = 0; 192 s.str = str; 193 qstring_append(str, "{"); 194 qdict_iter(val, to_json_dict_iter, &s); 195 qstring_append(str, "}"); 196 break; 197 } 198 case QTYPE_QLIST: { 199 ToJsonIterState s; 200 QList *val = qobject_to_qlist(obj); 201 202 s.count = 0; 203 s.str = str; 204 qstring_append(str, "["); 205 qlist_iter(val, (void *)to_json_list_iter, &s); 206 qstring_append(str, "]"); 207 break; 208 } 209 case QTYPE_QFLOAT: { 210 QFloat *val = qobject_to_qfloat(obj); 211 char buffer[1024]; 212 int len; 213 214 len = snprintf(buffer, sizeof(buffer), "%f", qfloat_get_double(val)); 215 while (len > 0 && buffer[len - 1] == '0') { 216 len--; 217 } 218 219 if (len && buffer[len - 1] == '.') { 220 buffer[len - 1] = 0; 221 } else { 222 buffer[len] = 0; 223 } 224 225 qstring_append(str, buffer); 226 break; 227 } 228 case QTYPE_QBOOL: { 229 QBool *val = qobject_to_qbool(obj); 230 231 if (qbool_get_int(val)) { 232 qstring_append(str, "true"); 233 } else { 234 qstring_append(str, "false"); 235 } 236 break; 237 } 238 case QTYPE_QERROR: 239 /* XXX: should QError be emitted? */ 240 case QTYPE_NONE: 241 break; 242 } 243 } 244 245 QString *qobject_to_json(const QObject *obj) 246 { 247 QString *str = qstring_new(); 248 249 to_json(obj, str); 250 251 return str; 252 } 253