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