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