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 "qapi/qmp/json-lexer.h" 15 #include "qapi/qmp/json-parser.h" 16 #include "qapi/qmp/json-streamer.h" 17 #include "qapi/qmp/qjson.h" 18 #include "qapi/qmp/qint.h" 19 #include "qapi/qmp/qlist.h" 20 #include "qapi/qmp/qbool.h" 21 #include "qapi/qmp/qfloat.h" 22 #include "qapi/qmp/qdict.h" 23 24 typedef struct JSONParsingState 25 { 26 JSONMessageParser parser; 27 va_list *ap; 28 QObject *result; 29 } JSONParsingState; 30 31 static void parse_json(JSONMessageParser *parser, QList *tokens) 32 { 33 JSONParsingState *s = container_of(parser, JSONParsingState, parser); 34 s->result = json_parser_parse(tokens, s->ap); 35 } 36 37 QObject *qobject_from_jsonv(const char *string, va_list *ap) 38 { 39 JSONParsingState state = {}; 40 41 state.ap = ap; 42 43 json_message_parser_init(&state.parser, parse_json); 44 json_message_parser_feed(&state.parser, string, strlen(string)); 45 json_message_parser_flush(&state.parser); 46 json_message_parser_destroy(&state.parser); 47 48 return state.result; 49 } 50 51 QObject *qobject_from_json(const char *string) 52 { 53 return qobject_from_jsonv(string, NULL); 54 } 55 56 /* 57 * IMPORTANT: This function aborts on error, thus it must not 58 * be used with untrusted arguments. 59 */ 60 QObject *qobject_from_jsonf(const char *string, ...) 61 { 62 QObject *obj; 63 va_list ap; 64 65 va_start(ap, string); 66 obj = qobject_from_jsonv(string, &ap); 67 va_end(ap); 68 69 assert(obj != NULL); 70 return obj; 71 } 72 73 typedef struct ToJsonIterState 74 { 75 int indent; 76 int pretty; 77 int count; 78 QString *str; 79 } ToJsonIterState; 80 81 static void to_json(const QObject *obj, QString *str, int pretty, int indent); 82 83 static void to_json_dict_iter(const char *key, QObject *obj, void *opaque) 84 { 85 ToJsonIterState *s = opaque; 86 QString *qkey; 87 int j; 88 89 if (s->count) { 90 qstring_append(s->str, s->pretty ? "," : ", "); 91 } 92 93 if (s->pretty) { 94 qstring_append(s->str, "\n"); 95 for (j = 0 ; j < s->indent ; j++) 96 qstring_append(s->str, " "); 97 } 98 99 qkey = qstring_from_str(key); 100 to_json(QOBJECT(qkey), s->str, s->pretty, s->indent); 101 QDECREF(qkey); 102 103 qstring_append(s->str, ": "); 104 to_json(obj, s->str, s->pretty, s->indent); 105 s->count++; 106 } 107 108 static void to_json_list_iter(QObject *obj, void *opaque) 109 { 110 ToJsonIterState *s = opaque; 111 int j; 112 113 if (s->count) { 114 qstring_append(s->str, s->pretty ? "," : ", "); 115 } 116 117 if (s->pretty) { 118 qstring_append(s->str, "\n"); 119 for (j = 0 ; j < s->indent ; j++) 120 qstring_append(s->str, " "); 121 } 122 123 to_json(obj, s->str, s->pretty, s->indent); 124 s->count++; 125 } 126 127 static void to_json(const QObject *obj, QString *str, int pretty, int indent) 128 { 129 switch (qobject_type(obj)) { 130 case QTYPE_QINT: { 131 QInt *val = qobject_to_qint(obj); 132 char buffer[1024]; 133 134 snprintf(buffer, sizeof(buffer), "%" PRId64, qint_get_int(val)); 135 qstring_append(str, buffer); 136 break; 137 } 138 case QTYPE_QSTRING: { 139 QString *val = qobject_to_qstring(obj); 140 const char *ptr; 141 int cp; 142 char buf[16]; 143 char *end; 144 145 ptr = qstring_get_str(val); 146 qstring_append(str, "\""); 147 148 for (; *ptr; ptr = end) { 149 cp = mod_utf8_codepoint(ptr, 6, &end); 150 switch (cp) { 151 case '\"': 152 qstring_append(str, "\\\""); 153 break; 154 case '\\': 155 qstring_append(str, "\\\\"); 156 break; 157 case '\b': 158 qstring_append(str, "\\b"); 159 break; 160 case '\f': 161 qstring_append(str, "\\f"); 162 break; 163 case '\n': 164 qstring_append(str, "\\n"); 165 break; 166 case '\r': 167 qstring_append(str, "\\r"); 168 break; 169 case '\t': 170 qstring_append(str, "\\t"); 171 break; 172 default: 173 if (cp < 0) { 174 cp = 0xFFFD; /* replacement character */ 175 } 176 if (cp > 0xFFFF) { 177 /* beyond BMP; need a surrogate pair */ 178 snprintf(buf, sizeof(buf), "\\u%04X\\u%04X", 179 0xD800 + ((cp - 0x10000) >> 10), 180 0xDC00 + ((cp - 0x10000) & 0x3FF)); 181 } else if (cp < 0x20 || cp >= 0x7F) { 182 snprintf(buf, sizeof(buf), "\\u%04X", cp); 183 } else { 184 buf[0] = cp; 185 buf[1] = 0; 186 } 187 qstring_append(str, buf); 188 } 189 }; 190 191 qstring_append(str, "\""); 192 break; 193 } 194 case QTYPE_QDICT: { 195 ToJsonIterState s; 196 QDict *val = qobject_to_qdict(obj); 197 198 s.count = 0; 199 s.str = str; 200 s.indent = indent + 1; 201 s.pretty = pretty; 202 qstring_append(str, "{"); 203 qdict_iter(val, to_json_dict_iter, &s); 204 if (pretty) { 205 int j; 206 qstring_append(str, "\n"); 207 for (j = 0 ; j < indent ; j++) 208 qstring_append(str, " "); 209 } 210 qstring_append(str, "}"); 211 break; 212 } 213 case QTYPE_QLIST: { 214 ToJsonIterState s; 215 QList *val = qobject_to_qlist(obj); 216 217 s.count = 0; 218 s.str = str; 219 s.indent = indent + 1; 220 s.pretty = pretty; 221 qstring_append(str, "["); 222 qlist_iter(val, (void *)to_json_list_iter, &s); 223 if (pretty) { 224 int j; 225 qstring_append(str, "\n"); 226 for (j = 0 ; j < indent ; j++) 227 qstring_append(str, " "); 228 } 229 qstring_append(str, "]"); 230 break; 231 } 232 case QTYPE_QFLOAT: { 233 QFloat *val = qobject_to_qfloat(obj); 234 char buffer[1024]; 235 int len; 236 237 len = snprintf(buffer, sizeof(buffer), "%f", qfloat_get_double(val)); 238 while (len > 0 && buffer[len - 1] == '0') { 239 len--; 240 } 241 242 if (len && buffer[len - 1] == '.') { 243 buffer[len - 1] = 0; 244 } else { 245 buffer[len] = 0; 246 } 247 248 qstring_append(str, buffer); 249 break; 250 } 251 case QTYPE_QBOOL: { 252 QBool *val = qobject_to_qbool(obj); 253 254 if (qbool_get_int(val)) { 255 qstring_append(str, "true"); 256 } else { 257 qstring_append(str, "false"); 258 } 259 break; 260 } 261 case QTYPE_QERROR: 262 /* XXX: should QError be emitted? */ 263 case QTYPE_NONE: 264 break; 265 case QTYPE_MAX: 266 abort(); 267 } 268 } 269 270 QString *qobject_to_json(const QObject *obj) 271 { 272 QString *str = qstring_new(); 273 274 to_json(obj, str, 0, 0); 275 276 return str; 277 } 278 279 QString *qobject_to_json_pretty(const QObject *obj) 280 { 281 QString *str = qstring_new(); 282 283 to_json(obj, str, 1, 0); 284 285 return str; 286 } 287