xref: /openbmc/qemu/qobject/qjson.c (revision 2e1cacfb)
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-parser.h"
17 #include "qapi/qmp/json-writer.h"
18 #include "qapi/qmp/qjson.h"
19 #include "qapi/qmp/qbool.h"
20 #include "qapi/qmp/qdict.h"
21 #include "qapi/qmp/qlist.h"
22 #include "qapi/qmp/qnum.h"
23 #include "qapi/qmp/qstring.h"
24 
25 typedef struct JSONParsingState {
26     JSONMessageParser parser;
27     QObject *result;
28     Error *err;
29 } JSONParsingState;
30 
31 static void consume_json(void *opaque, QObject *json, Error *err)
32 {
33     JSONParsingState *s = opaque;
34 
35     assert(!json != !err);
36     assert(!s->result || !s->err);
37 
38     if (s->result) {
39         qobject_unref(s->result);
40         s->result = NULL;
41         error_setg(&s->err, "Expecting at most one JSON value");
42     }
43     if (s->err) {
44         qobject_unref(json);
45         error_free(err);
46         return;
47     }
48     s->result = json;
49     s->err = err;
50 }
51 
52 /*
53  * Parse @string as JSON value.
54  * If @ap is non-null, interpolate %-escapes.
55  * Takes ownership of %p arguments.
56  * On success, return the JSON value.
57  * On failure, store an error through @errp and return NULL.
58  * Ownership of %p arguments becomes indeterminate then.  To avoid
59  * leaks, callers passing %p must terminate on error, e.g. by passing
60  * &error_abort.
61  */
62 static QObject *qobject_from_jsonv(const char *string, va_list *ap,
63                                    Error **errp)
64 {
65     JSONParsingState state = {};
66 
67     json_message_parser_init(&state.parser, consume_json, &state, ap);
68     json_message_parser_feed(&state.parser, string, strlen(string));
69     json_message_parser_flush(&state.parser);
70     json_message_parser_destroy(&state.parser);
71 
72     if (!state.result && !state.err) {
73         error_setg(&state.err, "Expecting a JSON value");
74     }
75 
76     error_propagate(errp, state.err);
77     return state.result;
78 }
79 
80 QObject *qobject_from_json(const char *string, Error **errp)
81 {
82     return qobject_from_jsonv(string, NULL, errp);
83 }
84 
85 /*
86  * Parse @string as JSON value with %-escapes interpolated.
87  * Abort on error.  Do not use with untrusted @string.
88  * Return the resulting QObject.  It is never null.
89  */
90 QObject *qobject_from_vjsonf_nofail(const char *string, va_list ap)
91 {
92     va_list ap_copy;
93     QObject *obj;
94 
95     /* va_copy() is needed when va_list is an array type */
96     va_copy(ap_copy, ap);
97     obj = qobject_from_jsonv(string, &ap_copy, &error_abort);
98     va_end(ap_copy);
99 
100     assert(obj);
101     return obj;
102 }
103 
104 /*
105  * Parse @string as JSON value with %-escapes interpolated.
106  * Abort on error.  Do not use with untrusted @string.
107  * Return the resulting QObject.  It is never null.
108  */
109 QObject *qobject_from_jsonf_nofail(const char *string, ...)
110 {
111     QObject *obj;
112     va_list ap;
113 
114     va_start(ap, string);
115     obj = qobject_from_vjsonf_nofail(string, ap);
116     va_end(ap);
117 
118     return obj;
119 }
120 
121 /*
122  * Parse @string as JSON object with %-escapes interpolated.
123  * Abort on error.  Do not use with untrusted @string.
124  * Return the resulting QDict.  It is never null.
125  */
126 QDict *qdict_from_vjsonf_nofail(const char *string, va_list ap)
127 {
128     QDict *qdict;
129 
130     qdict = qobject_to(QDict, qobject_from_vjsonf_nofail(string, ap));
131     assert(qdict);
132     return qdict;
133 }
134 
135 /*
136  * Parse @string as JSON object with %-escapes interpolated.
137  * Abort on error.  Do not use with untrusted @string.
138  * Return the resulting QDict.  It is never null.
139  */
140 QDict *qdict_from_jsonf_nofail(const char *string, ...)
141 {
142     QDict *qdict;
143     va_list ap;
144 
145     va_start(ap, string);
146     qdict = qdict_from_vjsonf_nofail(string, ap);
147     va_end(ap);
148     return qdict;
149 }
150 
151 static void to_json(JSONWriter *writer, const char *name,
152                     const QObject *obj)
153 {
154     switch (qobject_type(obj)) {
155     case QTYPE_QNULL:
156         json_writer_null(writer, name);
157         break;
158     case QTYPE_QNUM: {
159         QNum *val = qobject_to(QNum, obj);
160 
161         switch (val->kind) {
162         case QNUM_I64:
163             json_writer_int64(writer, name, val->u.i64);
164             break;
165         case QNUM_U64:
166             json_writer_uint64(writer, name, val->u.u64);
167             break;
168         case QNUM_DOUBLE:
169             json_writer_double(writer, name, val->u.dbl);
170             break;
171         default:
172             abort();
173         }
174         break;
175     }
176     case QTYPE_QSTRING: {
177         QString *val = qobject_to(QString, obj);
178 
179         json_writer_str(writer, name, qstring_get_str(val));
180         break;
181     }
182     case QTYPE_QDICT: {
183         QDict *val = qobject_to(QDict, obj);
184         const QDictEntry *entry;
185 
186         json_writer_start_object(writer, name);
187 
188         for (entry = qdict_first(val);
189              entry;
190              entry = qdict_next(val, entry)) {
191             to_json(writer, qdict_entry_key(entry), qdict_entry_value(entry));
192         }
193 
194         json_writer_end_object(writer);
195         break;
196     }
197     case QTYPE_QLIST: {
198         QList *val = qobject_to(QList, obj);
199         QListEntry *entry;
200 
201         json_writer_start_array(writer, name);
202 
203         QLIST_FOREACH_ENTRY(val, entry) {
204             to_json(writer, NULL, qlist_entry_obj(entry));
205         }
206 
207         json_writer_end_array(writer);
208         break;
209     }
210     case QTYPE_QBOOL: {
211         QBool *val = qobject_to(QBool, obj);
212 
213         json_writer_bool(writer, name, qbool_get_bool(val));
214         break;
215     }
216     default:
217         abort();
218     }
219 }
220 
221 GString *qobject_to_json_pretty(const QObject *obj, bool pretty)
222 {
223     JSONWriter *writer = json_writer_new(pretty);
224 
225     to_json(writer, NULL, obj);
226     return json_writer_get_and_free(writer);
227 }
228 
229 GString *qobject_to_json(const QObject *obj)
230 {
231     return qobject_to_json_pretty(obj, false);
232 }
233