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/error.h" 16 #include "qapi/qmp/json-lexer.h" 17 #include "qapi/qmp/json-parser.h" 18 #include "qapi/qmp/json-streamer.h" 19 #include "qapi/qmp/qjson.h" 20 #include "qapi/qmp/qbool.h" 21 #include "qapi/qmp/qdict.h" 22 #include "qapi/qmp/qlist.h" 23 #include "qapi/qmp/qnum.h" 24 #include "qapi/qmp/qstring.h" 25 #include "qemu/unicode.h" 26 27 typedef struct JSONParsingState 28 { 29 JSONMessageParser parser; 30 va_list *ap; 31 QObject *result; 32 Error *err; 33 } JSONParsingState; 34 35 static void parse_json(JSONMessageParser *parser, GQueue *tokens) 36 { 37 JSONParsingState *s = container_of(parser, JSONParsingState, parser); 38 39 s->result = json_parser_parse_err(tokens, s->ap, &s->err); 40 } 41 42 /* 43 * Parse @string as JSON value. 44 * If @ap is non-null, interpolate %-escapes. 45 * Takes ownership of %p arguments. 46 * On success, return the JSON value. 47 * On failure, store an error through @errp and return NULL. 48 * Ownership of %p arguments becomes indeterminate then. To avoid 49 * leaks, callers passing %p must terminate on error, e.g. by passing 50 * &error_abort. 51 */ 52 static QObject *qobject_from_jsonv(const char *string, va_list *ap, 53 Error **errp) 54 { 55 JSONParsingState state = {}; 56 57 state.ap = ap; 58 59 json_message_parser_init(&state.parser, parse_json); 60 json_message_parser_feed(&state.parser, string, strlen(string)); 61 json_message_parser_flush(&state.parser); 62 json_message_parser_destroy(&state.parser); 63 64 error_propagate(errp, state.err); 65 return state.result; 66 } 67 68 QObject *qobject_from_json(const char *string, Error **errp) 69 { 70 return qobject_from_jsonv(string, NULL, errp); 71 } 72 73 /* 74 * Parse @string as JSON value with %-escapes interpolated. 75 * Abort on error. Do not use with untrusted @string. 76 * Return the resulting QObject. It is never null. 77 */ 78 QObject *qobject_from_vjsonf_nofail(const char *string, va_list ap) 79 { 80 va_list ap_copy; 81 QObject *obj; 82 83 /* va_copy() is needed when va_list is an array type */ 84 va_copy(ap_copy, ap); 85 obj = qobject_from_jsonv(string, &ap_copy, &error_abort); 86 va_end(ap_copy); 87 88 assert(obj); 89 return obj; 90 } 91 92 /* 93 * Parse @string as JSON value with %-escapes interpolated. 94 * Abort on error. Do not use with untrusted @string. 95 * Return the resulting QObject. It is never null. 96 */ 97 QObject *qobject_from_jsonf_nofail(const char *string, ...) 98 { 99 QObject *obj; 100 va_list ap; 101 102 va_start(ap, string); 103 obj = qobject_from_vjsonf_nofail(string, ap); 104 va_end(ap); 105 106 return obj; 107 } 108 109 /* 110 * Parse @string as JSON object with %-escapes interpolated. 111 * Abort on error. Do not use with untrusted @string. 112 * Return the resulting QDict. It is never null. 113 */ 114 QDict *qdict_from_vjsonf_nofail(const char *string, va_list ap) 115 { 116 QDict *qdict; 117 118 qdict = qobject_to(QDict, qobject_from_vjsonf_nofail(string, ap)); 119 assert(qdict); 120 return qdict; 121 } 122 123 /* 124 * Parse @string as JSON object with %-escapes interpolated. 125 * Abort on error. Do not use with untrusted @string. 126 * Return the resulting QDict. It is never null. 127 */ 128 QDict *qdict_from_jsonf_nofail(const char *string, ...) 129 { 130 QDict *qdict; 131 va_list ap; 132 133 va_start(ap, string); 134 qdict = qdict_from_vjsonf_nofail(string, ap); 135 va_end(ap); 136 return qdict; 137 } 138 139 typedef struct ToJsonIterState 140 { 141 int indent; 142 int pretty; 143 int count; 144 QString *str; 145 } ToJsonIterState; 146 147 static void to_json(const QObject *obj, QString *str, int pretty, int indent); 148 149 static void to_json_dict_iter(const char *key, QObject *obj, void *opaque) 150 { 151 ToJsonIterState *s = opaque; 152 QString *qkey; 153 int j; 154 155 if (s->count) { 156 qstring_append(s->str, s->pretty ? "," : ", "); 157 } 158 159 if (s->pretty) { 160 qstring_append(s->str, "\n"); 161 for (j = 0 ; j < s->indent ; j++) 162 qstring_append(s->str, " "); 163 } 164 165 qkey = qstring_from_str(key); 166 to_json(QOBJECT(qkey), s->str, s->pretty, s->indent); 167 qobject_unref(qkey); 168 169 qstring_append(s->str, ": "); 170 to_json(obj, s->str, s->pretty, s->indent); 171 s->count++; 172 } 173 174 static void to_json_list_iter(QObject *obj, void *opaque) 175 { 176 ToJsonIterState *s = opaque; 177 int j; 178 179 if (s->count) { 180 qstring_append(s->str, s->pretty ? "," : ", "); 181 } 182 183 if (s->pretty) { 184 qstring_append(s->str, "\n"); 185 for (j = 0 ; j < s->indent ; j++) 186 qstring_append(s->str, " "); 187 } 188 189 to_json(obj, s->str, s->pretty, s->indent); 190 s->count++; 191 } 192 193 static void to_json(const QObject *obj, QString *str, int pretty, int indent) 194 { 195 switch (qobject_type(obj)) { 196 case QTYPE_QNULL: 197 qstring_append(str, "null"); 198 break; 199 case QTYPE_QNUM: { 200 QNum *val = qobject_to(QNum, obj); 201 char *buffer = qnum_to_string(val); 202 qstring_append(str, buffer); 203 g_free(buffer); 204 break; 205 } 206 case QTYPE_QSTRING: { 207 QString *val = qobject_to(QString, obj); 208 const char *ptr; 209 int cp; 210 char buf[16]; 211 char *end; 212 213 ptr = qstring_get_str(val); 214 qstring_append(str, "\""); 215 216 for (; *ptr; ptr = end) { 217 cp = mod_utf8_codepoint(ptr, 6, &end); 218 switch (cp) { 219 case '\"': 220 qstring_append(str, "\\\""); 221 break; 222 case '\\': 223 qstring_append(str, "\\\\"); 224 break; 225 case '\b': 226 qstring_append(str, "\\b"); 227 break; 228 case '\f': 229 qstring_append(str, "\\f"); 230 break; 231 case '\n': 232 qstring_append(str, "\\n"); 233 break; 234 case '\r': 235 qstring_append(str, "\\r"); 236 break; 237 case '\t': 238 qstring_append(str, "\\t"); 239 break; 240 default: 241 if (cp < 0) { 242 cp = 0xFFFD; /* replacement character */ 243 } 244 if (cp > 0xFFFF) { 245 /* beyond BMP; need a surrogate pair */ 246 snprintf(buf, sizeof(buf), "\\u%04X\\u%04X", 247 0xD800 + ((cp - 0x10000) >> 10), 248 0xDC00 + ((cp - 0x10000) & 0x3FF)); 249 } else if (cp < 0x20 || cp >= 0x7F) { 250 snprintf(buf, sizeof(buf), "\\u%04X", cp); 251 } else { 252 buf[0] = cp; 253 buf[1] = 0; 254 } 255 qstring_append(str, buf); 256 } 257 }; 258 259 qstring_append(str, "\""); 260 break; 261 } 262 case QTYPE_QDICT: { 263 ToJsonIterState s; 264 QDict *val = qobject_to(QDict, obj); 265 266 s.count = 0; 267 s.str = str; 268 s.indent = indent + 1; 269 s.pretty = pretty; 270 qstring_append(str, "{"); 271 qdict_iter(val, to_json_dict_iter, &s); 272 if (pretty) { 273 int j; 274 qstring_append(str, "\n"); 275 for (j = 0 ; j < indent ; j++) 276 qstring_append(str, " "); 277 } 278 qstring_append(str, "}"); 279 break; 280 } 281 case QTYPE_QLIST: { 282 ToJsonIterState s; 283 QList *val = qobject_to(QList, obj); 284 285 s.count = 0; 286 s.str = str; 287 s.indent = indent + 1; 288 s.pretty = pretty; 289 qstring_append(str, "["); 290 qlist_iter(val, (void *)to_json_list_iter, &s); 291 if (pretty) { 292 int j; 293 qstring_append(str, "\n"); 294 for (j = 0 ; j < indent ; j++) 295 qstring_append(str, " "); 296 } 297 qstring_append(str, "]"); 298 break; 299 } 300 case QTYPE_QBOOL: { 301 QBool *val = qobject_to(QBool, obj); 302 303 if (qbool_get_bool(val)) { 304 qstring_append(str, "true"); 305 } else { 306 qstring_append(str, "false"); 307 } 308 break; 309 } 310 default: 311 abort(); 312 } 313 } 314 315 QString *qobject_to_json(const QObject *obj) 316 { 317 QString *str = qstring_new(); 318 319 to_json(obj, str, 0, 0); 320 321 return str; 322 } 323 324 QString *qobject_to_json_pretty(const QObject *obj) 325 { 326 QString *str = qstring_new(); 327 328 to_json(obj, str, 1, 0); 329 330 return str; 331 } 332