1 /* 2 * QObject JSON integration 3 * 4 * Copyright IBM, Corp. 2009 5 * 6 * Authors: 7 * Anthony Liguori <aliguori@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 "qapi/qmp/json-lexer.h" 15 #include "qapi/qmp/json-parser.h" 16 #include "qapi/qmp/json-streamer.h" 17 #include "qapi/qmp/qjson.h" 18 #include "qapi/qmp/qint.h" 19 #include "qapi/qmp/qlist.h" 20 #include "qapi/qmp/qbool.h" 21 #include "qapi/qmp/qfloat.h" 22 #include "qapi/qmp/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 indent; 76 int pretty; 77 int count; 78 QString *str; 79 } ToJsonIterState; 80 81 static void to_json(const QObject *obj, QString *str, int pretty, int indent); 82 83 static void to_json_dict_iter(const char *key, QObject *obj, void *opaque) 84 { 85 ToJsonIterState *s = opaque; 86 QString *qkey; 87 int j; 88 89 if (s->count) 90 qstring_append(s->str, ", "); 91 92 if (s->pretty) { 93 qstring_append(s->str, "\n"); 94 for (j = 0 ; j < s->indent ; j++) 95 qstring_append(s->str, " "); 96 } 97 98 qkey = qstring_from_str(key); 99 to_json(QOBJECT(qkey), s->str, s->pretty, s->indent); 100 QDECREF(qkey); 101 102 qstring_append(s->str, ": "); 103 to_json(obj, s->str, s->pretty, s->indent); 104 s->count++; 105 } 106 107 static void to_json_list_iter(QObject *obj, void *opaque) 108 { 109 ToJsonIterState *s = opaque; 110 int j; 111 112 if (s->count) 113 qstring_append(s->str, ", "); 114 115 if (s->pretty) { 116 qstring_append(s->str, "\n"); 117 for (j = 0 ; j < s->indent ; j++) 118 qstring_append(s->str, " "); 119 } 120 121 to_json(obj, s->str, s->pretty, s->indent); 122 s->count++; 123 } 124 125 static void to_json(const QObject *obj, QString *str, int pretty, int indent) 126 { 127 switch (qobject_type(obj)) { 128 case QTYPE_QINT: { 129 QInt *val = qobject_to_qint(obj); 130 char buffer[1024]; 131 132 snprintf(buffer, sizeof(buffer), "%" PRId64, qint_get_int(val)); 133 qstring_append(str, buffer); 134 break; 135 } 136 case QTYPE_QSTRING: { 137 QString *val = qobject_to_qstring(obj); 138 const char *ptr; 139 140 ptr = qstring_get_str(val); 141 qstring_append(str, "\""); 142 while (*ptr) { 143 if ((ptr[0] & 0xE0) == 0xE0 && 144 (ptr[1] & 0x80) && (ptr[2] & 0x80)) { 145 uint16_t wchar; 146 char escape[7]; 147 148 wchar = (ptr[0] & 0x0F) << 12; 149 wchar |= (ptr[1] & 0x3F) << 6; 150 wchar |= (ptr[2] & 0x3F); 151 ptr += 2; 152 153 snprintf(escape, sizeof(escape), "\\u%04X", wchar); 154 qstring_append(str, escape); 155 } else if ((ptr[0] & 0xE0) == 0xC0 && (ptr[1] & 0x80)) { 156 uint16_t wchar; 157 char escape[7]; 158 159 wchar = (ptr[0] & 0x1F) << 6; 160 wchar |= (ptr[1] & 0x3F); 161 ptr++; 162 163 snprintf(escape, sizeof(escape), "\\u%04X", wchar); 164 qstring_append(str, escape); 165 } else switch (ptr[0]) { 166 case '\"': 167 qstring_append(str, "\\\""); 168 break; 169 case '\\': 170 qstring_append(str, "\\\\"); 171 break; 172 case '\b': 173 qstring_append(str, "\\b"); 174 break; 175 case '\f': 176 qstring_append(str, "\\f"); 177 break; 178 case '\n': 179 qstring_append(str, "\\n"); 180 break; 181 case '\r': 182 qstring_append(str, "\\r"); 183 break; 184 case '\t': 185 qstring_append(str, "\\t"); 186 break; 187 default: { 188 if (ptr[0] <= 0x1F) { 189 char escape[7]; 190 snprintf(escape, sizeof(escape), "\\u%04X", ptr[0]); 191 qstring_append(str, escape); 192 } else { 193 char buf[2] = { ptr[0], 0 }; 194 qstring_append(str, buf); 195 } 196 break; 197 } 198 } 199 ptr++; 200 } 201 qstring_append(str, "\""); 202 break; 203 } 204 case QTYPE_QDICT: { 205 ToJsonIterState s; 206 QDict *val = qobject_to_qdict(obj); 207 208 s.count = 0; 209 s.str = str; 210 s.indent = indent + 1; 211 s.pretty = pretty; 212 qstring_append(str, "{"); 213 qdict_iter(val, to_json_dict_iter, &s); 214 if (pretty) { 215 int j; 216 qstring_append(str, "\n"); 217 for (j = 0 ; j < indent ; j++) 218 qstring_append(str, " "); 219 } 220 qstring_append(str, "}"); 221 break; 222 } 223 case QTYPE_QLIST: { 224 ToJsonIterState s; 225 QList *val = qobject_to_qlist(obj); 226 227 s.count = 0; 228 s.str = str; 229 s.indent = indent + 1; 230 s.pretty = pretty; 231 qstring_append(str, "["); 232 qlist_iter(val, (void *)to_json_list_iter, &s); 233 if (pretty) { 234 int j; 235 qstring_append(str, "\n"); 236 for (j = 0 ; j < indent ; j++) 237 qstring_append(str, " "); 238 } 239 qstring_append(str, "]"); 240 break; 241 } 242 case QTYPE_QFLOAT: { 243 QFloat *val = qobject_to_qfloat(obj); 244 char buffer[1024]; 245 int len; 246 247 len = snprintf(buffer, sizeof(buffer), "%f", qfloat_get_double(val)); 248 while (len > 0 && buffer[len - 1] == '0') { 249 len--; 250 } 251 252 if (len && buffer[len - 1] == '.') { 253 buffer[len - 1] = 0; 254 } else { 255 buffer[len] = 0; 256 } 257 258 qstring_append(str, buffer); 259 break; 260 } 261 case QTYPE_QBOOL: { 262 QBool *val = qobject_to_qbool(obj); 263 264 if (qbool_get_int(val)) { 265 qstring_append(str, "true"); 266 } else { 267 qstring_append(str, "false"); 268 } 269 break; 270 } 271 case QTYPE_QERROR: 272 /* XXX: should QError be emitted? */ 273 case QTYPE_NONE: 274 break; 275 } 276 } 277 278 QString *qobject_to_json(const QObject *obj) 279 { 280 QString *str = qstring_new(); 281 282 to_json(obj, str, 0, 0); 283 284 return str; 285 } 286 287 QString *qobject_to_json_pretty(const QObject *obj) 288 { 289 QString *str = qstring_new(); 290 291 to_json(obj, str, 1, 0); 292 293 return str; 294 } 295