xref: /openbmc/qemu/qobject/qjson.c (revision 502d0f36)
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