virtio-gpu: fix ui idx check
[qemu/ar7.git] / qapi / qmp-input-visitor.c
blobaea90a1378e2898bb010b51802d89b2ea0a5d0cd
1 /*
2 * Input Visitor
4 * Copyright (C) 2012-2016 Red Hat, Inc.
5 * Copyright IBM, Corp. 2011
7 * Authors:
8 * Anthony Liguori <aliguori@us.ibm.com>
10 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
11 * See the COPYING.LIB file in the top-level directory.
15 #include "qemu/osdep.h"
16 #include "qapi/error.h"
17 #include "qapi/qmp-input-visitor.h"
18 #include "qapi/visitor-impl.h"
19 #include "qemu/queue.h"
20 #include "qemu-common.h"
21 #include "qapi/qmp/types.h"
22 #include "qapi/qmp/qerror.h"
24 #define QIV_STACK_SIZE 1024
26 typedef struct StackObject
28 QObject *obj; /* Object being visited */
30 GHashTable *h; /* If obj is dict: unvisited keys */
31 const QListEntry *entry; /* If obj is list: unvisited tail */
32 } StackObject;
34 struct QmpInputVisitor
36 Visitor visitor;
38 /* Root of visit at visitor creation. */
39 QObject *root;
41 /* Stack of objects being visited (all entries will be either
42 * QDict or QList). */
43 StackObject stack[QIV_STACK_SIZE];
44 int nb_stack;
46 /* True to reject parse in visit_end_struct() if unvisited keys remain. */
47 bool strict;
50 static QmpInputVisitor *to_qiv(Visitor *v)
52 return container_of(v, QmpInputVisitor, visitor);
55 static QObject *qmp_input_get_object(QmpInputVisitor *qiv,
56 const char *name,
57 bool consume)
59 StackObject *tos;
60 QObject *qobj;
61 QObject *ret;
63 if (!qiv->nb_stack) {
64 /* Starting at root, name is ignored. */
65 return qiv->root;
68 /* We are in a container; find the next element. */
69 tos = &qiv->stack[qiv->nb_stack - 1];
70 qobj = tos->obj;
71 assert(qobj);
73 if (qobject_type(qobj) == QTYPE_QDICT) {
74 assert(name);
75 ret = qdict_get(qobject_to_qdict(qobj), name);
76 if (tos->h && consume && ret) {
77 bool removed = g_hash_table_remove(tos->h, name);
78 assert(removed);
80 } else {
81 assert(qobject_type(qobj) == QTYPE_QLIST);
82 assert(!name);
83 ret = qlist_entry_obj(tos->entry);
84 if (consume) {
85 tos->entry = qlist_next(tos->entry);
89 return ret;
92 static void qdict_add_key(const char *key, QObject *obj, void *opaque)
94 GHashTable *h = opaque;
95 g_hash_table_insert(h, (gpointer) key, NULL);
98 static const QListEntry *qmp_input_push(QmpInputVisitor *qiv, QObject *obj,
99 Error **errp)
101 GHashTable *h;
102 StackObject *tos = &qiv->stack[qiv->nb_stack];
104 assert(obj);
105 if (qiv->nb_stack >= QIV_STACK_SIZE) {
106 error_setg(errp, "An internal buffer overran");
107 return NULL;
110 tos->obj = obj;
111 assert(!tos->h);
112 assert(!tos->entry);
114 if (qiv->strict && qobject_type(obj) == QTYPE_QDICT) {
115 h = g_hash_table_new(g_str_hash, g_str_equal);
116 qdict_iter(qobject_to_qdict(obj), qdict_add_key, h);
117 tos->h = h;
118 } else if (qobject_type(obj) == QTYPE_QLIST) {
119 tos->entry = qlist_first(qobject_to_qlist(obj));
122 qiv->nb_stack++;
123 return tos->entry;
127 static void qmp_input_check_struct(Visitor *v, Error **errp)
129 QmpInputVisitor *qiv = to_qiv(v);
130 StackObject *tos = &qiv->stack[qiv->nb_stack - 1];
132 assert(qiv->nb_stack > 0);
134 if (qiv->strict) {
135 GHashTable *const top_ht = tos->h;
136 if (top_ht) {
137 GHashTableIter iter;
138 const char *key;
140 g_hash_table_iter_init(&iter, top_ht);
141 if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) {
142 error_setg(errp, QERR_QMP_EXTRA_MEMBER, key);
148 static void qmp_input_pop(Visitor *v)
150 QmpInputVisitor *qiv = to_qiv(v);
151 StackObject *tos = &qiv->stack[qiv->nb_stack - 1];
153 assert(qiv->nb_stack > 0);
155 if (qiv->strict) {
156 GHashTable * const top_ht = qiv->stack[qiv->nb_stack - 1].h;
157 if (top_ht) {
158 g_hash_table_unref(top_ht);
160 tos->h = NULL;
163 qiv->nb_stack--;
166 static void qmp_input_start_struct(Visitor *v, const char *name, void **obj,
167 size_t size, Error **errp)
169 QmpInputVisitor *qiv = to_qiv(v);
170 QObject *qobj = qmp_input_get_object(qiv, name, true);
171 Error *err = NULL;
173 if (obj) {
174 *obj = NULL;
176 if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
177 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
178 "QDict");
179 return;
182 qmp_input_push(qiv, qobj, &err);
183 if (err) {
184 error_propagate(errp, err);
185 return;
188 if (obj) {
189 *obj = g_malloc0(size);
194 static void qmp_input_start_list(Visitor *v, const char *name,
195 GenericList **list, size_t size, Error **errp)
197 QmpInputVisitor *qiv = to_qiv(v);
198 QObject *qobj = qmp_input_get_object(qiv, name, true);
199 const QListEntry *entry;
201 if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
202 if (list) {
203 *list = NULL;
205 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
206 "list");
207 return;
210 entry = qmp_input_push(qiv, qobj, errp);
211 if (list) {
212 if (entry) {
213 *list = g_malloc0(size);
214 } else {
215 *list = NULL;
220 static GenericList *qmp_input_next_list(Visitor *v, GenericList *tail,
221 size_t size)
223 QmpInputVisitor *qiv = to_qiv(v);
224 StackObject *so = &qiv->stack[qiv->nb_stack - 1];
226 if (!so->entry) {
227 return NULL;
229 tail->next = g_malloc0(size);
230 return tail->next;
234 static void qmp_input_start_alternate(Visitor *v, const char *name,
235 GenericAlternate **obj, size_t size,
236 bool promote_int, Error **errp)
238 QmpInputVisitor *qiv = to_qiv(v);
239 QObject *qobj = qmp_input_get_object(qiv, name, false);
241 if (!qobj) {
242 *obj = NULL;
243 error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null");
244 return;
246 *obj = g_malloc0(size);
247 (*obj)->type = qobject_type(qobj);
248 if (promote_int && (*obj)->type == QTYPE_QINT) {
249 (*obj)->type = QTYPE_QFLOAT;
253 static void qmp_input_type_int64(Visitor *v, const char *name, int64_t *obj,
254 Error **errp)
256 QmpInputVisitor *qiv = to_qiv(v);
257 QInt *qint = qobject_to_qint(qmp_input_get_object(qiv, name, true));
259 if (!qint) {
260 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
261 "integer");
262 return;
265 *obj = qint_get_int(qint);
268 static void qmp_input_type_uint64(Visitor *v, const char *name, uint64_t *obj,
269 Error **errp)
271 /* FIXME: qobject_to_qint mishandles values over INT64_MAX */
272 QmpInputVisitor *qiv = to_qiv(v);
273 QInt *qint = qobject_to_qint(qmp_input_get_object(qiv, name, true));
275 if (!qint) {
276 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
277 "integer");
278 return;
281 *obj = qint_get_int(qint);
284 static void qmp_input_type_bool(Visitor *v, const char *name, bool *obj,
285 Error **errp)
287 QmpInputVisitor *qiv = to_qiv(v);
288 QBool *qbool = qobject_to_qbool(qmp_input_get_object(qiv, name, true));
290 if (!qbool) {
291 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
292 "boolean");
293 return;
296 *obj = qbool_get_bool(qbool);
299 static void qmp_input_type_str(Visitor *v, const char *name, char **obj,
300 Error **errp)
302 QmpInputVisitor *qiv = to_qiv(v);
303 QString *qstr = qobject_to_qstring(qmp_input_get_object(qiv, name, true));
305 if (!qstr) {
306 *obj = NULL;
307 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
308 "string");
309 return;
312 *obj = g_strdup(qstring_get_str(qstr));
315 static void qmp_input_type_number(Visitor *v, const char *name, double *obj,
316 Error **errp)
318 QmpInputVisitor *qiv = to_qiv(v);
319 QObject *qobj = qmp_input_get_object(qiv, name, true);
320 QInt *qint;
321 QFloat *qfloat;
323 qint = qobject_to_qint(qobj);
324 if (qint) {
325 *obj = qint_get_int(qobject_to_qint(qobj));
326 return;
329 qfloat = qobject_to_qfloat(qobj);
330 if (qfloat) {
331 *obj = qfloat_get_double(qobject_to_qfloat(qobj));
332 return;
335 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
336 "number");
339 static void qmp_input_type_any(Visitor *v, const char *name, QObject **obj,
340 Error **errp)
342 QmpInputVisitor *qiv = to_qiv(v);
343 QObject *qobj = qmp_input_get_object(qiv, name, true);
345 qobject_incref(qobj);
346 *obj = qobj;
349 static void qmp_input_type_null(Visitor *v, const char *name, Error **errp)
351 QmpInputVisitor *qiv = to_qiv(v);
352 QObject *qobj = qmp_input_get_object(qiv, name, true);
354 if (qobject_type(qobj) != QTYPE_QNULL) {
355 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
356 "null");
360 static void qmp_input_optional(Visitor *v, const char *name, bool *present)
362 QmpInputVisitor *qiv = to_qiv(v);
363 QObject *qobj = qmp_input_get_object(qiv, name, false);
365 if (!qobj) {
366 *present = false;
367 return;
370 *present = true;
373 Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
375 return &v->visitor;
378 void qmp_input_visitor_cleanup(QmpInputVisitor *v)
380 qobject_decref(v->root);
381 g_free(v);
384 QmpInputVisitor *qmp_input_visitor_new(QObject *obj, bool strict)
386 QmpInputVisitor *v;
388 v = g_malloc0(sizeof(*v));
390 v->visitor.type = VISITOR_INPUT;
391 v->visitor.start_struct = qmp_input_start_struct;
392 v->visitor.check_struct = qmp_input_check_struct;
393 v->visitor.end_struct = qmp_input_pop;
394 v->visitor.start_list = qmp_input_start_list;
395 v->visitor.next_list = qmp_input_next_list;
396 v->visitor.end_list = qmp_input_pop;
397 v->visitor.start_alternate = qmp_input_start_alternate;
398 v->visitor.type_int64 = qmp_input_type_int64;
399 v->visitor.type_uint64 = qmp_input_type_uint64;
400 v->visitor.type_bool = qmp_input_type_bool;
401 v->visitor.type_str = qmp_input_type_str;
402 v->visitor.type_number = qmp_input_type_number;
403 v->visitor.type_any = qmp_input_type_any;
404 v->visitor.type_null = qmp_input_type_null;
405 v->visitor.optional = qmp_input_optional;
406 v->strict = strict;
408 v->root = obj;
409 qobject_incref(obj);
411 return v;