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