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