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 "qemu/osdep.h" 15 #include "qapi/qmp/json-lexer.h" 16 #include "qapi/qmp/json-parser.h" 17 #include "qapi/qmp/json-streamer.h" 18 #include "qapi/qmp/qjson.h" 19 #include "qapi/qmp/types.h" 20 #include "qemu/unicode.h" 21 22 typedef struct JSONParsingState 23 { 24 JSONMessageParser parser; 25 va_list *ap; 26 QObject *result; 27 } JSONParsingState; 28 29 static void parse_json(JSONMessageParser *parser, GQueue *tokens) 30 { 31 JSONParsingState *s = container_of(parser, JSONParsingState, parser); 32 s->result = json_parser_parse(tokens, s->ap); 33 } 34 35 QObject *qobject_from_jsonv(const char *string, va_list *ap) 36 { 37 JSONParsingState state = {}; 38 39 state.ap = ap; 40 41 json_message_parser_init(&state.parser, parse_json); 42 json_message_parser_feed(&state.parser, string, strlen(string)); 43 json_message_parser_flush(&state.parser); 44 json_message_parser_destroy(&state.parser); 45 46 return state.result; 47 } 48 49 QObject *qobject_from_json(const char *string) 50 { 51 return qobject_from_jsonv(string, NULL); 52 } 53 54 /* 55 * IMPORTANT: This function aborts on error, thus it must not 56 * be used with untrusted arguments. 57 */ 58 QObject *qobject_from_jsonf(const char *string, ...) 59 { 60 QObject *obj; 61 va_list ap; 62 63 va_start(ap, string); 64 obj = qobject_from_jsonv(string, &ap); 65 va_end(ap); 66 67 assert(obj != NULL); 68 return obj; 69 } 70 71 typedef struct ToJsonIterState 72 { 73 int indent; 74 int pretty; 75 int count; 76 QString *str; 77 } ToJsonIterState; 78 79 static void to_json(const QObject *obj, QString *str, int pretty, int indent); 80 81 static void to_json_dict_iter(const char *key, QObject *obj, void *opaque) 82 { 83 ToJsonIterState *s = opaque; 84 QString *qkey; 85 int j; 86 87 if (s->count) { 88 qstring_append(s->str, s->pretty ? "," : ", "); 89 } 90 91 if (s->pretty) { 92 qstring_append(s->str, "\n"); 93 for (j = 0 ; j < s->indent ; j++) 94 qstring_append(s->str, " "); 95 } 96 97 qkey = qstring_from_str(key); 98 to_json(QOBJECT(qkey), s->str, s->pretty, s->indent); 99 QDECREF(qkey); 100 101 qstring_append(s->str, ": "); 102 to_json(obj, s->str, s->pretty, s->indent); 103 s->count++; 104 } 105 106 static void to_json_list_iter(QObject *obj, void *opaque) 107 { 108 ToJsonIterState *s = opaque; 109 int j; 110 111 if (s->count) { 112 qstring_append(s->str, s->pretty ? "," : ", "); 113 } 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_QNULL: 129 qstring_append(str, "null"); 130 break; 131 case QTYPE_QINT: { 132 QInt *val = qobject_to_qint(obj); 133 char buffer[1024]; 134 135 snprintf(buffer, sizeof(buffer), "%" PRId64, qint_get_int(val)); 136 qstring_append(str, buffer); 137 break; 138 } 139 case QTYPE_QSTRING: { 140 QString *val = qobject_to_qstring(obj); 141 const char *ptr; 142 int cp; 143 char buf[16]; 144 char *end; 145 146 ptr = qstring_get_str(val); 147 qstring_append(str, "\""); 148 149 for (; *ptr; ptr = end) { 150 cp = mod_utf8_codepoint(ptr, 6, &end); 151 switch (cp) { 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 '\f': 162 qstring_append(str, "\\f"); 163 break; 164 case '\n': 165 qstring_append(str, "\\n"); 166 break; 167 case '\r': 168 qstring_append(str, "\\r"); 169 break; 170 case '\t': 171 qstring_append(str, "\\t"); 172 break; 173 default: 174 if (cp < 0) { 175 cp = 0xFFFD; /* replacement character */ 176 } 177 if (cp > 0xFFFF) { 178 /* beyond BMP; need a surrogate pair */ 179 snprintf(buf, sizeof(buf), "\\u%04X\\u%04X", 180 0xD800 + ((cp - 0x10000) >> 10), 181 0xDC00 + ((cp - 0x10000) & 0x3FF)); 182 } else if (cp < 0x20 || cp >= 0x7F) { 183 snprintf(buf, sizeof(buf), "\\u%04X", cp); 184 } else { 185 buf[0] = cp; 186 buf[1] = 0; 187 } 188 qstring_append(str, buf); 189 } 190 }; 191 192 qstring_append(str, "\""); 193 break; 194 } 195 case QTYPE_QDICT: { 196 ToJsonIterState s; 197 QDict *val = qobject_to_qdict(obj); 198 199 s.count = 0; 200 s.str = str; 201 s.indent = indent + 1; 202 s.pretty = pretty; 203 qstring_append(str, "{"); 204 qdict_iter(val, to_json_dict_iter, &s); 205 if (pretty) { 206 int j; 207 qstring_append(str, "\n"); 208 for (j = 0 ; j < indent ; j++) 209 qstring_append(str, " "); 210 } 211 qstring_append(str, "}"); 212 break; 213 } 214 case QTYPE_QLIST: { 215 ToJsonIterState s; 216 QList *val = qobject_to_qlist(obj); 217 218 s.count = 0; 219 s.str = str; 220 s.indent = indent + 1; 221 s.pretty = pretty; 222 qstring_append(str, "["); 223 qlist_iter(val, (void *)to_json_list_iter, &s); 224 if (pretty) { 225 int j; 226 qstring_append(str, "\n"); 227 for (j = 0 ; j < indent ; j++) 228 qstring_append(str, " "); 229 } 230 qstring_append(str, "]"); 231 break; 232 } 233 case QTYPE_QFLOAT: { 234 QFloat *val = qobject_to_qfloat(obj); 235 char buffer[1024]; 236 int len; 237 238 /* FIXME: snprintf() is locale dependent; but JSON requires 239 * numbers to be formatted as if in the C locale. Dependence 240 * on C locale is a pervasive issue in QEMU. */ 241 /* FIXME: This risks printing Inf or NaN, which are not valid 242 * JSON values. */ 243 /* FIXME: the default precision of 6 for %f often causes 244 * rounding errors; we should be using DBL_DECIMAL_DIG (17), 245 * and only rounding to a shorter number if the result would 246 * still produce the same floating point value. */ 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_bool(val)) { 265 qstring_append(str, "true"); 266 } else { 267 qstring_append(str, "false"); 268 } 269 break; 270 } 271 default: 272 abort(); 273 } 274 } 275 276 QString *qobject_to_json(const QObject *obj) 277 { 278 QString *str = qstring_new(); 279 280 to_json(obj, str, 0, 0); 281 282 return str; 283 } 284 285 QString *qobject_to_json_pretty(const QObject *obj) 286 { 287 QString *str = qstring_new(); 288 289 to_json(obj, str, 1, 0); 290 291 return str; 292 } 293