]> Git Repo - qemu.git/blob - qobject/qjson.c
qobject: qobject_from_jsonv() is dangerous, hide it away
[qemu.git] / qobject / qjson.c
1 /*
2  * QObject JSON integration
3  *
4  * Copyright IBM, Corp. 2009
5  *
6  * Authors:
7  *  Anthony Liguori   <[email protected]>
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 /*
43  * Parse @string as JSON value.
44  * If @ap is non-null, interpolate %-escapes.
45  * Takes ownership of %p arguments.
46  * On success, return the JSON value.
47  * On failure, store an error through @errp and return NULL.
48  * Ownership of %p arguments becomes indeterminate then.  To avoid
49  * leaks, callers passing %p must terminate on error, e.g. by passing
50  * &error_abort.
51  */
52 static QObject *qobject_from_jsonv(const char *string, va_list *ap,
53                                    Error **errp)
54 {
55     JSONParsingState state = {};
56
57     state.ap = ap;
58
59     json_message_parser_init(&state.parser, parse_json);
60     json_message_parser_feed(&state.parser, string, strlen(string));
61     json_message_parser_flush(&state.parser);
62     json_message_parser_destroy(&state.parser);
63
64     error_propagate(errp, state.err);
65     return state.result;
66 }
67
68 QObject *qobject_from_json(const char *string, Error **errp)
69 {
70     return qobject_from_jsonv(string, NULL, errp);
71 }
72
73 /*
74  * Parse @string as JSON value with %-escapes interpolated.
75  * Abort on error.  Do not use with untrusted @string.
76  * Return the resulting QObject.  It is never null.
77  */
78 QObject *qobject_from_vjsonf_nofail(const char *string, va_list ap)
79 {
80     va_list ap_copy;
81     QObject *obj;
82
83     /* va_copy() is needed when va_list is an array type */
84     va_copy(ap_copy, ap);
85     obj = qobject_from_jsonv(string, &ap_copy, &error_abort);
86     va_end(ap_copy);
87
88     assert(obj);
89     return obj;
90 }
91
92 /*
93  * Parse @string as JSON value with %-escapes interpolated.
94  * Abort on error.  Do not use with untrusted @string.
95  * Return the resulting QObject.  It is never null.
96  */
97 QObject *qobject_from_jsonf_nofail(const char *string, ...)
98 {
99     QObject *obj;
100     va_list ap;
101
102     va_start(ap, string);
103     obj = qobject_from_vjsonf_nofail(string, ap);
104     va_end(ap);
105
106     return obj;
107 }
108
109 /*
110  * Parse @string as JSON object with %-escapes interpolated.
111  * Abort on error.  Do not use with untrusted @string.
112  * Return the resulting QDict.  It is never null.
113  */
114 QDict *qdict_from_vjsonf_nofail(const char *string, va_list ap)
115 {
116     QDict *qdict;
117
118     qdict = qobject_to(QDict, qobject_from_vjsonf_nofail(string, ap));
119     assert(qdict);
120     return qdict;
121 }
122
123 /*
124  * Parse @string as JSON object with %-escapes interpolated.
125  * Abort on error.  Do not use with untrusted @string.
126  * Return the resulting QDict.  It is never null.
127  */
128 QDict *qdict_from_jsonf_nofail(const char *string, ...)
129 {
130     QDict *qdict;
131     va_list ap;
132
133     va_start(ap, string);
134     qdict = qdict_from_vjsonf_nofail(string, ap);
135     va_end(ap);
136     return qdict;
137 }
138
139 typedef struct ToJsonIterState
140 {
141     int indent;
142     int pretty;
143     int count;
144     QString *str;
145 } ToJsonIterState;
146
147 static void to_json(const QObject *obj, QString *str, int pretty, int indent);
148
149 static void to_json_dict_iter(const char *key, QObject *obj, void *opaque)
150 {
151     ToJsonIterState *s = opaque;
152     QString *qkey;
153     int j;
154
155     if (s->count) {
156         qstring_append(s->str, s->pretty ? "," : ", ");
157     }
158
159     if (s->pretty) {
160         qstring_append(s->str, "\n");
161         for (j = 0 ; j < s->indent ; j++)
162             qstring_append(s->str, "    ");
163     }
164
165     qkey = qstring_from_str(key);
166     to_json(QOBJECT(qkey), s->str, s->pretty, s->indent);
167     qobject_unref(qkey);
168
169     qstring_append(s->str, ": ");
170     to_json(obj, s->str, s->pretty, s->indent);
171     s->count++;
172 }
173
174 static void to_json_list_iter(QObject *obj, void *opaque)
175 {
176     ToJsonIterState *s = opaque;
177     int j;
178
179     if (s->count) {
180         qstring_append(s->str, s->pretty ? "," : ", ");
181     }
182
183     if (s->pretty) {
184         qstring_append(s->str, "\n");
185         for (j = 0 ; j < s->indent ; j++)
186             qstring_append(s->str, "    ");
187     }
188
189     to_json(obj, s->str, s->pretty, s->indent);
190     s->count++;
191 }
192
193 static void to_json(const QObject *obj, QString *str, int pretty, int indent)
194 {
195     switch (qobject_type(obj)) {
196     case QTYPE_QNULL:
197         qstring_append(str, "null");
198         break;
199     case QTYPE_QNUM: {
200         QNum *val = qobject_to(QNum, obj);
201         char *buffer = qnum_to_string(val);
202         qstring_append(str, buffer);
203         g_free(buffer);
204         break;
205     }
206     case QTYPE_QSTRING: {
207         QString *val = qobject_to(QString, obj);
208         const char *ptr;
209         int cp;
210         char buf[16];
211         char *end;
212
213         ptr = qstring_get_str(val);
214         qstring_append(str, "\"");
215
216         for (; *ptr; ptr = end) {
217             cp = mod_utf8_codepoint(ptr, 6, &end);
218             switch (cp) {
219             case '\"':
220                 qstring_append(str, "\\\"");
221                 break;
222             case '\\':
223                 qstring_append(str, "\\\\");
224                 break;
225             case '\b':
226                 qstring_append(str, "\\b");
227                 break;
228             case '\f':
229                 qstring_append(str, "\\f");
230                 break;
231             case '\n':
232                 qstring_append(str, "\\n");
233                 break;
234             case '\r':
235                 qstring_append(str, "\\r");
236                 break;
237             case '\t':
238                 qstring_append(str, "\\t");
239                 break;
240             default:
241                 if (cp < 0) {
242                     cp = 0xFFFD; /* replacement character */
243                 }
244                 if (cp > 0xFFFF) {
245                     /* beyond BMP; need a surrogate pair */
246                     snprintf(buf, sizeof(buf), "\\u%04X\\u%04X",
247                              0xD800 + ((cp - 0x10000) >> 10),
248                              0xDC00 + ((cp - 0x10000) & 0x3FF));
249                 } else if (cp < 0x20 || cp >= 0x7F) {
250                     snprintf(buf, sizeof(buf), "\\u%04X", cp);
251                 } else {
252                     buf[0] = cp;
253                     buf[1] = 0;
254                 }
255                 qstring_append(str, buf);
256             }
257         };
258
259         qstring_append(str, "\"");
260         break;
261     }
262     case QTYPE_QDICT: {
263         ToJsonIterState s;
264         QDict *val = qobject_to(QDict, obj);
265
266         s.count = 0;
267         s.str = str;
268         s.indent = indent + 1;
269         s.pretty = pretty;
270         qstring_append(str, "{");
271         qdict_iter(val, to_json_dict_iter, &s);
272         if (pretty) {
273             int j;
274             qstring_append(str, "\n");
275             for (j = 0 ; j < indent ; j++)
276                 qstring_append(str, "    ");
277         }
278         qstring_append(str, "}");
279         break;
280     }
281     case QTYPE_QLIST: {
282         ToJsonIterState s;
283         QList *val = qobject_to(QList, obj);
284
285         s.count = 0;
286         s.str = str;
287         s.indent = indent + 1;
288         s.pretty = pretty;
289         qstring_append(str, "[");
290         qlist_iter(val, (void *)to_json_list_iter, &s);
291         if (pretty) {
292             int j;
293             qstring_append(str, "\n");
294             for (j = 0 ; j < indent ; j++)
295                 qstring_append(str, "    ");
296         }
297         qstring_append(str, "]");
298         break;
299     }
300     case QTYPE_QBOOL: {
301         QBool *val = qobject_to(QBool, obj);
302
303         if (qbool_get_bool(val)) {
304             qstring_append(str, "true");
305         } else {
306             qstring_append(str, "false");
307         }
308         break;
309     }
310     default:
311         abort();
312     }
313 }
314
315 QString *qobject_to_json(const QObject *obj)
316 {
317     QString *str = qstring_new();
318
319     to_json(obj, str, 0, 0);
320
321     return str;
322 }
323
324 QString *qobject_to_json_pretty(const QObject *obj)
325 {
326     QString *str = qstring_new();
327
328     to_json(obj, str, 1, 0);
329
330     return str;
331 }
This page took 0.041568 seconds and 4 git commands to generate.