xref: /openbmc/qemu/qobject/qjson.c (revision d38ea87a)
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/qmp/json-lexer.h"
16 #include "qapi/qmp/json-parser.h"
17 #include "qapi/qmp/json-streamer.h"
18 #include "qapi/qmp/qjson.h"
19 #include "qapi/qmp/qint.h"
20 #include "qapi/qmp/qlist.h"
21 #include "qapi/qmp/qbool.h"
22 #include "qapi/qmp/qfloat.h"
23 #include "qapi/qmp/qdict.h"
24 
25 typedef struct JSONParsingState
26 {
27     JSONMessageParser parser;
28     va_list *ap;
29     QObject *result;
30 } JSONParsingState;
31 
32 static void parse_json(JSONMessageParser *parser, GQueue *tokens)
33 {
34     JSONParsingState *s = container_of(parser, JSONParsingState, parser);
35     s->result = json_parser_parse(tokens, s->ap);
36 }
37 
38 QObject *qobject_from_jsonv(const char *string, va_list *ap)
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     return state.result;
50 }
51 
52 QObject *qobject_from_json(const char *string)
53 {
54     return qobject_from_jsonv(string, NULL);
55 }
56 
57 /*
58  * IMPORTANT: This function aborts on error, thus it must not
59  * be used with untrusted arguments.
60  */
61 QObject *qobject_from_jsonf(const char *string, ...)
62 {
63     QObject *obj;
64     va_list ap;
65 
66     va_start(ap, string);
67     obj = qobject_from_jsonv(string, &ap);
68     va_end(ap);
69 
70     assert(obj != NULL);
71     return obj;
72 }
73 
74 typedef struct ToJsonIterState
75 {
76     int indent;
77     int pretty;
78     int count;
79     QString *str;
80 } ToJsonIterState;
81 
82 static void to_json(const QObject *obj, QString *str, int pretty, int indent);
83 
84 static void to_json_dict_iter(const char *key, QObject *obj, void *opaque)
85 {
86     ToJsonIterState *s = opaque;
87     QString *qkey;
88     int j;
89 
90     if (s->count) {
91         qstring_append(s->str, s->pretty ? "," : ", ");
92     }
93 
94     if (s->pretty) {
95         qstring_append(s->str, "\n");
96         for (j = 0 ; j < s->indent ; j++)
97             qstring_append(s->str, "    ");
98     }
99 
100     qkey = qstring_from_str(key);
101     to_json(QOBJECT(qkey), s->str, s->pretty, s->indent);
102     QDECREF(qkey);
103 
104     qstring_append(s->str, ": ");
105     to_json(obj, s->str, s->pretty, s->indent);
106     s->count++;
107 }
108 
109 static void to_json_list_iter(QObject *obj, void *opaque)
110 {
111     ToJsonIterState *s = opaque;
112     int j;
113 
114     if (s->count) {
115         qstring_append(s->str, s->pretty ? "," : ", ");
116     }
117 
118     if (s->pretty) {
119         qstring_append(s->str, "\n");
120         for (j = 0 ; j < s->indent ; j++)
121             qstring_append(s->str, "    ");
122     }
123 
124     to_json(obj, s->str, s->pretty, s->indent);
125     s->count++;
126 }
127 
128 static void to_json(const QObject *obj, QString *str, int pretty, int indent)
129 {
130     switch (qobject_type(obj)) {
131     case QTYPE_QNULL:
132         qstring_append(str, "null");
133         break;
134     case QTYPE_QINT: {
135         QInt *val = qobject_to_qint(obj);
136         char buffer[1024];
137 
138         snprintf(buffer, sizeof(buffer), "%" PRId64, qint_get_int(val));
139         qstring_append(str, 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_QFLOAT: {
237         QFloat *val = qobject_to_qfloat(obj);
238         char buffer[1024];
239         int len;
240 
241         len = snprintf(buffer, sizeof(buffer), "%f", qfloat_get_double(val));
242         while (len > 0 && buffer[len - 1] == '0') {
243             len--;
244         }
245 
246         if (len && buffer[len - 1] == '.') {
247             buffer[len - 1] = 0;
248         } else {
249             buffer[len] = 0;
250         }
251 
252         qstring_append(str, buffer);
253         break;
254     }
255     case QTYPE_QBOOL: {
256         QBool *val = qobject_to_qbool(obj);
257 
258         if (qbool_get_bool(val)) {
259             qstring_append(str, "true");
260         } else {
261             qstring_append(str, "false");
262         }
263         break;
264     }
265     default:
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