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 * IMPORTANT: This function aborts on error, thus it must not 64 * be used with untrusted arguments. 65 */ 66 QObject *qobject_from_jsonf(const char *string, ...) 67 { 68 QObject *obj; 69 va_list ap; 70 71 va_start(ap, string); 72 obj = qobject_from_jsonv(string, &ap, &error_abort); 73 va_end(ap); 74 75 assert(obj != NULL); 76 return obj; 77 } 78 79 typedef struct ToJsonIterState 80 { 81 int indent; 82 int pretty; 83 int count; 84 QString *str; 85 } ToJsonIterState; 86 87 static void to_json(const QObject *obj, QString *str, int pretty, int indent); 88 89 static void to_json_dict_iter(const char *key, QObject *obj, void *opaque) 90 { 91 ToJsonIterState *s = opaque; 92 QString *qkey; 93 int j; 94 95 if (s->count) { 96 qstring_append(s->str, s->pretty ? "," : ", "); 97 } 98 99 if (s->pretty) { 100 qstring_append(s->str, "\n"); 101 for (j = 0 ; j < s->indent ; j++) 102 qstring_append(s->str, " "); 103 } 104 105 qkey = qstring_from_str(key); 106 to_json(QOBJECT(qkey), s->str, s->pretty, s->indent); 107 QDECREF(qkey); 108 109 qstring_append(s->str, ": "); 110 to_json(obj, s->str, s->pretty, s->indent); 111 s->count++; 112 } 113 114 static void to_json_list_iter(QObject *obj, void *opaque) 115 { 116 ToJsonIterState *s = opaque; 117 int j; 118 119 if (s->count) { 120 qstring_append(s->str, s->pretty ? "," : ", "); 121 } 122 123 if (s->pretty) { 124 qstring_append(s->str, "\n"); 125 for (j = 0 ; j < s->indent ; j++) 126 qstring_append(s->str, " "); 127 } 128 129 to_json(obj, s->str, s->pretty, s->indent); 130 s->count++; 131 } 132 133 static void to_json(const QObject *obj, QString *str, int pretty, int indent) 134 { 135 switch (qobject_type(obj)) { 136 case QTYPE_QNULL: 137 qstring_append(str, "null"); 138 break; 139 case QTYPE_QNUM: { 140 QNum *val = qobject_to(QNum, obj); 141 char *buffer = qnum_to_string(val); 142 qstring_append(str, buffer); 143 g_free(buffer); 144 break; 145 } 146 case QTYPE_QSTRING: { 147 QString *val = qobject_to(QString, obj); 148 const char *ptr; 149 int cp; 150 char buf[16]; 151 char *end; 152 153 ptr = qstring_get_str(val); 154 qstring_append(str, "\""); 155 156 for (; *ptr; ptr = end) { 157 cp = mod_utf8_codepoint(ptr, 6, &end); 158 switch (cp) { 159 case '\"': 160 qstring_append(str, "\\\""); 161 break; 162 case '\\': 163 qstring_append(str, "\\\\"); 164 break; 165 case '\b': 166 qstring_append(str, "\\b"); 167 break; 168 case '\f': 169 qstring_append(str, "\\f"); 170 break; 171 case '\n': 172 qstring_append(str, "\\n"); 173 break; 174 case '\r': 175 qstring_append(str, "\\r"); 176 break; 177 case '\t': 178 qstring_append(str, "\\t"); 179 break; 180 default: 181 if (cp < 0) { 182 cp = 0xFFFD; /* replacement character */ 183 } 184 if (cp > 0xFFFF) { 185 /* beyond BMP; need a surrogate pair */ 186 snprintf(buf, sizeof(buf), "\\u%04X\\u%04X", 187 0xD800 + ((cp - 0x10000) >> 10), 188 0xDC00 + ((cp - 0x10000) & 0x3FF)); 189 } else if (cp < 0x20 || cp >= 0x7F) { 190 snprintf(buf, sizeof(buf), "\\u%04X", cp); 191 } else { 192 buf[0] = cp; 193 buf[1] = 0; 194 } 195 qstring_append(str, buf); 196 } 197 }; 198 199 qstring_append(str, "\""); 200 break; 201 } 202 case QTYPE_QDICT: { 203 ToJsonIterState s; 204 QDict *val = qobject_to(QDict, obj); 205 206 s.count = 0; 207 s.str = str; 208 s.indent = indent + 1; 209 s.pretty = pretty; 210 qstring_append(str, "{"); 211 qdict_iter(val, to_json_dict_iter, &s); 212 if (pretty) { 213 int j; 214 qstring_append(str, "\n"); 215 for (j = 0 ; j < indent ; j++) 216 qstring_append(str, " "); 217 } 218 qstring_append(str, "}"); 219 break; 220 } 221 case QTYPE_QLIST: { 222 ToJsonIterState s; 223 QList *val = qobject_to(QList, obj); 224 225 s.count = 0; 226 s.str = str; 227 s.indent = indent + 1; 228 s.pretty = pretty; 229 qstring_append(str, "["); 230 qlist_iter(val, (void *)to_json_list_iter, &s); 231 if (pretty) { 232 int j; 233 qstring_append(str, "\n"); 234 for (j = 0 ; j < indent ; j++) 235 qstring_append(str, " "); 236 } 237 qstring_append(str, "]"); 238 break; 239 } 240 case QTYPE_QBOOL: { 241 QBool *val = qobject_to(QBool, obj); 242 243 if (qbool_get_bool(val)) { 244 qstring_append(str, "true"); 245 } else { 246 qstring_append(str, "false"); 247 } 248 break; 249 } 250 default: 251 abort(); 252 } 253 } 254 255 QString *qobject_to_json(const QObject *obj) 256 { 257 QString *str = qstring_new(); 258 259 to_json(obj, str, 0, 0); 260 261 return str; 262 } 263 264 QString *qobject_to_json_pretty(const QObject *obj) 265 { 266 QString *str = qstring_new(); 267 268 to_json(obj, str, 1, 0); 269 270 return str; 271 } 272