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 24typedef struct JSONParsingState 25{ 26 JSONMessageParser parser; 27 va_list *ap; 28 QObject *result; 29} JSONParsingState; 30 31static 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 37QObject *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 51QObject *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 */ 60QObject *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 73typedef struct ToJsonIterState 74{ 75 int indent; 76 int pretty; 77 int count; 78 QString *str; 79} ToJsonIterState; 80 81static void to_json(const QObject *obj, QString *str, int pretty, int indent); 82 83static 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, ", "); 91 92 if (s->pretty) { 93 qstring_append(s->str, "\n"); 94 for (j = 0 ; j < s->indent ; j++) 95 qstring_append(s->str, " "); 96 } 97 98 qkey = qstring_from_str(key); 99 to_json(QOBJECT(qkey), s->str, s->pretty, s->indent); 100 QDECREF(qkey); 101 102 qstring_append(s->str, ": "); 103 to_json(obj, s->str, s->pretty, s->indent); 104 s->count++; 105} 106 107static void to_json_list_iter(QObject *obj, void *opaque) 108{ 109 ToJsonIterState *s = opaque; 110 int j; 111 112 if (s->count) 113 qstring_append(s->str, ", "); 114 115 if (s->pretty) { 116 qstring_append(s->str, "\n"); 117 for (j = 0 ; j < s->indent ; j++) 118 qstring_append(s->str, " "); 119 } 120 121 to_json(obj, s->str, s->pretty, s->indent); 122 s->count++; 123} 124 125static void to_json(const QObject *obj, QString *str, int pretty, int indent) 126{ 127 switch (qobject_type(obj)) { 128 case QTYPE_QINT: { 129 QInt *val = qobject_to_qint(obj); 130 char buffer[1024]; 131 132 snprintf(buffer, sizeof(buffer), "%" PRId64, qint_get_int(val)); 133 qstring_append(str, buffer); 134 break; 135 } 136 case QTYPE_QSTRING: { 137 QString *val = qobject_to_qstring(obj); 138 const char *ptr; 139 int cp; 140 char buf[16]; 141 char *end; 142 143 ptr = qstring_get_str(val); 144 qstring_append(str, "\""); 145 146 for (; *ptr; ptr = end) { 147 cp = mod_utf8_codepoint(ptr, 6, &end); 148 switch (cp) { 149 case '\"': 150 qstring_append(str, "\\\""); 151 break; 152 case '\\': 153 qstring_append(str, "\\\\"); 154 break; 155 case '\b': 156 qstring_append(str, "\\b"); 157 break; 158 case '\f': 159 qstring_append(str, "\\f"); 160 break; 161 case '\n': 162 qstring_append(str, "\\n"); 163 break; 164 case '\r': 165 qstring_append(str, "\\r"); 166 break; 167 case '\t': 168 qstring_append(str, "\\t"); 169 break; 170 default: 171 if (cp < 0) { 172 cp = 0xFFFD; /* replacement character */ 173 } 174 if (cp > 0xFFFF) { 175 /* beyond BMP; need a surrogate pair */ 176 snprintf(buf, sizeof(buf), "\\u%04X\\u%04X", 177 0xD800 + ((cp - 0x10000) >> 10), 178 0xDC00 + ((cp - 0x10000) & 0x3FF)); 179 } else if (cp < 0x20 || cp >= 0x7F) { 180 snprintf(buf, sizeof(buf), "\\u%04X", cp); 181 } else { 182 buf[0] = cp; 183 buf[1] = 0; 184 } 185 qstring_append(str, buf); 186 } 187 }; 188 189 qstring_append(str, "\""); 190 break; 191 } 192 case QTYPE_QDICT: { 193 ToJsonIterState s; 194 QDict *val = qobject_to_qdict(obj); 195 196 s.count = 0; 197 s.str = str; 198 s.indent = indent + 1; 199 s.pretty = pretty; 200 qstring_append(str, "{"); 201 qdict_iter(val, to_json_dict_iter, &s); 202 if (pretty) { 203 int j; 204 qstring_append(str, "\n"); 205 for (j = 0 ; j < indent ; j++) 206 qstring_append(str, " "); 207 } 208 qstring_append(str, "}"); 209 break; 210 } 211 case QTYPE_QLIST: { 212 ToJsonIterState s; 213 QList *val = qobject_to_qlist(obj); 214 215 s.count = 0; 216 s.str = str; 217 s.indent = indent + 1; 218 s.pretty = pretty; 219 qstring_append(str, "["); 220 qlist_iter(val, (void *)to_json_list_iter, &s); 221 if (pretty) { 222 int j; 223 qstring_append(str, "\n"); 224 for (j = 0 ; j < indent ; j++) 225 qstring_append(str, " "); 226 } 227 qstring_append(str, "]"); 228 break; 229 } 230 case QTYPE_QFLOAT: { 231 QFloat *val = qobject_to_qfloat(obj); 232 char buffer[1024]; 233 int len; 234 235 len = snprintf(buffer, sizeof(buffer), "%f", qfloat_get_double(val)); 236 while (len > 0 && buffer[len - 1] == '0') { 237 len--; 238 } 239 240 if (len && buffer[len - 1] == '.') { 241 buffer[len - 1] = 0; 242 } else { 243 buffer[len] = 0; 244 } 245 246 qstring_append(str, buffer); 247 break; 248 } 249 case QTYPE_QBOOL: { 250 QBool *val = qobject_to_qbool(obj); 251 252 if (qbool_get_int(val)) { 253 qstring_append(str, "true"); 254 } else { 255 qstring_append(str, "false"); 256 } 257 break; 258 } 259 case QTYPE_QERROR: 260 /* XXX: should QError be emitted? */ 261 case QTYPE_NONE: 262 break; 263 case QTYPE_MAX: 264 abort(); 265 } 266} 267 268QString *qobject_to_json(const QObject *obj) 269{ 270 QString *str = qstring_new(); 271 272 to_json(obj, str, 0, 0); 273 274 return str; 275} 276 277QString *qobject_to_json_pretty(const QObject *obj) 278{ 279 QString *str = qstring_new(); 280 281 to_json(obj, str, 1, 0); 282 283 return str; 284} 285