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