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/types.h" 21 #include "qemu/unicode.h" 22 23 typedef struct JSONParsingState 24 { 25 JSONMessageParser parser; 26 va_list *ap; 27 QObject *result; 28 Error *err; 29 } JSONParsingState; 30 31 static void parse_json(JSONMessageParser *parser, GQueue *tokens) 32 { 33 JSONParsingState *s = container_of(parser, JSONParsingState, parser); 34 35 s->result = json_parser_parse_err(tokens, s->ap, &s->err); 36 } 37 38 QObject *qobject_from_jsonv(const char *string, va_list *ap, Error **errp) 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 error_propagate(errp, state.err); 50 return state.result; 51 } 52 53 QObject *qobject_from_json(const char *string, Error **errp) 54 { 55 return qobject_from_jsonv(string, NULL, errp); 56 } 57 58 /* 59 * IMPORTANT: This function aborts on error, thus it must not 60 * be used with untrusted arguments. 61 */ 62 QObject *qobject_from_jsonf(const char *string, ...) 63 { 64 QObject *obj; 65 va_list ap; 66 67 va_start(ap, string); 68 obj = qobject_from_jsonv(string, &ap, &error_abort); 69 va_end(ap); 70 71 assert(obj != NULL); 72 return obj; 73 } 74 75 typedef struct ToJsonIterState 76 { 77 int indent; 78 int pretty; 79 int count; 80 QString *str; 81 } ToJsonIterState; 82 83 static void to_json(const QObject *obj, QString *str, int pretty, int indent); 84 85 static void to_json_dict_iter(const char *key, QObject *obj, void *opaque) 86 { 87 ToJsonIterState *s = opaque; 88 QString *qkey; 89 int j; 90 91 if (s->count) { 92 qstring_append(s->str, s->pretty ? "," : ", "); 93 } 94 95 if (s->pretty) { 96 qstring_append(s->str, "\n"); 97 for (j = 0 ; j < s->indent ; j++) 98 qstring_append(s->str, " "); 99 } 100 101 qkey = qstring_from_str(key); 102 to_json(QOBJECT(qkey), s->str, s->pretty, s->indent); 103 QDECREF(qkey); 104 105 qstring_append(s->str, ": "); 106 to_json(obj, s->str, s->pretty, s->indent); 107 s->count++; 108 } 109 110 static void to_json_list_iter(QObject *obj, void *opaque) 111 { 112 ToJsonIterState *s = opaque; 113 int j; 114 115 if (s->count) { 116 qstring_append(s->str, s->pretty ? "," : ", "); 117 } 118 119 if (s->pretty) { 120 qstring_append(s->str, "\n"); 121 for (j = 0 ; j < s->indent ; j++) 122 qstring_append(s->str, " "); 123 } 124 125 to_json(obj, s->str, s->pretty, s->indent); 126 s->count++; 127 } 128 129 static void to_json(const QObject *obj, QString *str, int pretty, int indent) 130 { 131 switch (qobject_type(obj)) { 132 case QTYPE_QNULL: 133 qstring_append(str, "null"); 134 break; 135 case QTYPE_QNUM: { 136 QNum *val = qobject_to_qnum(obj); 137 char *buffer = qnum_to_string(val); 138 qstring_append(str, buffer); 139 g_free(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_QBOOL: { 237 QBool *val = qobject_to_qbool(obj); 238 239 if (qbool_get_bool(val)) { 240 qstring_append(str, "true"); 241 } else { 242 qstring_append(str, "false"); 243 } 244 break; 245 } 246 default: 247 abort(); 248 } 249 } 250 251 QString *qobject_to_json(const QObject *obj) 252 { 253 QString *str = qstring_new(); 254 255 to_json(obj, str, 0, 0); 256 257 return str; 258 } 259 260 QString *qobject_to_json_pretty(const QObject *obj) 261 { 262 QString *str = qstring_new(); 263 264 to_json(obj, str, 1, 0); 265 266 return str; 267 } 268