blob: 8015a986b07ffe9f6f2cb96467ddae0c6dca0060 [file] [log] [blame]
Michael Rothc40cc0a2011-07-19 14:50:33 -05001/*
2 * Input Visitor
3 *
Eric Blake08f95412016-01-29 06:48:59 -07004 * Copyright (C) 2012-2016 Red Hat, Inc.
Michael Rothc40cc0a2011-07-19 14:50:33 -05005 * Copyright IBM, Corp. 2011
6 *
7 * Authors:
8 * Anthony Liguori <aliguori@us.ibm.com>
9 *
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.
12 *
13 */
14
Peter Maydellcbf21152016-01-29 17:49:57 +000015#include "qemu/osdep.h"
Markus Armbrusterda34e652016-03-14 09:01:28 +010016#include "qapi/error.h"
Daniel P. Berrangeb3db2112016-09-30 15:45:27 +010017#include "qapi/qobject-input-visitor.h"
Paolo Bonzini7b1b5d12012-12-17 18:19:43 +010018#include "qapi/visitor-impl.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010019#include "qemu/queue.h"
Michael Rothc40cc0a2011-07-19 14:50:33 -050020#include "qemu-common.h"
Paolo Bonzini7b1b5d12012-12-17 18:19:43 +010021#include "qapi/qmp/types.h"
22#include "qapi/qmp/qerror.h"
Michael Rothc40cc0a2011-07-19 14:50:33 -050023
Markus Armbrustera9fc37f2017-03-03 13:32:34 +010024typedef struct StackObject {
25 const char *name; /* Name of @obj in its parent, if any */
26 QObject *obj; /* QDict or QList being visited */
Eric Blake1158bb22016-06-09 10:48:34 -060027 void *qapi; /* sanity check that caller uses same pointer */
Eric Blakeb471d012016-04-28 15:45:12 -060028
Markus Armbrustera9fc37f2017-03-03 13:32:34 +010029 GHashTable *h; /* If @obj is QDict: unvisited keys */
30 const QListEntry *entry; /* If @obj is QList: unvisited tail */
31 unsigned index; /* If @obj is QList: list index of @entry */
Paolo Bonzini3d344c22016-07-07 17:53:18 +020032
Markus Armbrustera9fc37f2017-03-03 13:32:34 +010033 QSLIST_ENTRY(StackObject) node; /* parent */
Michael Rothc40cc0a2011-07-19 14:50:33 -050034} StackObject;
35
Markus Armbrustera9fc37f2017-03-03 13:32:34 +010036struct QObjectInputVisitor {
Michael Rothc40cc0a2011-07-19 14:50:33 -050037 Visitor visitor;
Eric Blakeb471d012016-04-28 15:45:12 -060038
Eric Blakece140b12016-04-28 15:45:18 -060039 /* Root of visit at visitor creation. */
40 QObject *root;
41
42 /* Stack of objects being visited (all entries will be either
43 * QDict or QList). */
Paolo Bonzini3d344c22016-07-07 17:53:18 +020044 QSLIST_HEAD(, StackObject) stack;
Eric Blakeb471d012016-04-28 15:45:12 -060045
46 /* True to reject parse in visit_end_struct() if unvisited keys remain. */
Paolo Bonzinie38ac962012-03-22 12:51:10 +010047 bool strict;
Markus Armbrustera9fc37f2017-03-03 13:32:34 +010048
49 GString *errname; /* Accumulator for full_name() */
Michael Rothc40cc0a2011-07-19 14:50:33 -050050};
51
Daniel P. Berrange09e68362016-09-30 15:45:27 +010052static QObjectInputVisitor *to_qiv(Visitor *v)
Michael Rothc40cc0a2011-07-19 14:50:33 -050053{
Daniel P. Berrange09e68362016-09-30 15:45:27 +010054 return container_of(v, QObjectInputVisitor, visitor);
Michael Rothc40cc0a2011-07-19 14:50:33 -050055}
56
Markus Armbrustera9fc37f2017-03-03 13:32:34 +010057static const char *full_name(QObjectInputVisitor *qiv, const char *name)
58{
59 StackObject *so;
60 char buf[32];
61
62 if (qiv->errname) {
63 g_string_truncate(qiv->errname, 0);
64 } else {
65 qiv->errname = g_string_new("");
66 }
67
68 QSLIST_FOREACH(so , &qiv->stack, node) {
69 if (qobject_type(so->obj) == QTYPE_QDICT) {
70 g_string_prepend(qiv->errname, name);
71 g_string_prepend_c(qiv->errname, '.');
72 } else {
73 snprintf(buf, sizeof(buf), "[%u]", so->index);
74 g_string_prepend(qiv->errname, buf);
75 }
76 name = so->name;
77 }
78
79 if (name) {
80 g_string_prepend(qiv->errname, name);
81 } else if (qiv->errname->str[0] == '.') {
82 g_string_erase(qiv->errname, 0, 1);
83 } else {
84 return "<anonymous>";
85 }
86
87 return qiv->errname->str;
88}
89
90static QObject *qobject_input_try_get_object(QObjectInputVisitor *qiv,
91 const char *name,
92 bool consume)
Michael Rothc40cc0a2011-07-19 14:50:33 -050093{
Eric Blakece140b12016-04-28 15:45:18 -060094 StackObject *tos;
95 QObject *qobj;
Eric Blakee5826a22016-04-28 15:45:15 -060096 QObject *ret;
Michael Rothc40cc0a2011-07-19 14:50:33 -050097
Paolo Bonzini3d344c22016-07-07 17:53:18 +020098 if (QSLIST_EMPTY(&qiv->stack)) {
Eric Blakece140b12016-04-28 15:45:18 -060099 /* Starting at root, name is ignored. */
Marc-André Lureau5d0cbbc2016-09-30 13:59:46 +0400100 assert(qiv->root);
Eric Blakece140b12016-04-28 15:45:18 -0600101 return qiv->root;
102 }
103
104 /* We are in a container; find the next element. */
Paolo Bonzini3d344c22016-07-07 17:53:18 +0200105 tos = QSLIST_FIRST(&qiv->stack);
Eric Blakece140b12016-04-28 15:45:18 -0600106 qobj = tos->obj;
Eric Blakeb471d012016-04-28 15:45:12 -0600107 assert(qobj);
108
Eric Blakece140b12016-04-28 15:45:18 -0600109 if (qobject_type(qobj) == QTYPE_QDICT) {
110 assert(name);
Eric Blakee5826a22016-04-28 15:45:15 -0600111 ret = qdict_get(qobject_to_qdict(qobj), name);
112 if (tos->h && consume && ret) {
113 bool removed = g_hash_table_remove(tos->h, name);
114 assert(removed);
Paolo Bonzini47c6d3e2011-12-18 17:05:04 +0100115 }
Eric Blakece140b12016-04-28 15:45:18 -0600116 } else {
Eric Blakeb471d012016-04-28 15:45:12 -0600117 assert(qobject_type(qobj) == QTYPE_QLIST);
Eric Blakece140b12016-04-28 15:45:18 -0600118 assert(!name);
119 ret = qlist_entry_obj(tos->entry);
Marc-André Lureaueac8e792016-09-30 13:59:47 +0400120 assert(ret);
Eric Blakefcf3cb22016-04-28 15:45:19 -0600121 if (consume) {
122 tos->entry = qlist_next(tos->entry);
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100123 tos->index++;
Eric Blakefcf3cb22016-04-28 15:45:19 -0600124 }
Eric Blakeb471d012016-04-28 15:45:12 -0600125 }
126
Eric Blakece140b12016-04-28 15:45:18 -0600127 return ret;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500128}
129
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100130static QObject *qobject_input_get_object(QObjectInputVisitor *qiv,
131 const char *name,
132 bool consume, Error **errp)
133{
134 QObject *obj = qobject_input_try_get_object(qiv, name, consume);
135
136 if (!obj) {
137 error_setg(errp, QERR_MISSING_PARAMETER, full_name(qiv, name));
138 }
139 return obj;
140}
141
Paolo Bonzinie38ac962012-03-22 12:51:10 +0100142static void qdict_add_key(const char *key, QObject *obj, void *opaque)
143{
144 GHashTable *h = opaque;
145 g_hash_table_insert(h, (gpointer) key, NULL);
146}
147
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100148static const QListEntry *qobject_input_push(QObjectInputVisitor *qiv,
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100149 const char *name,
Markus Armbrusterb8874fb2017-03-03 13:32:32 +0100150 QObject *obj, void *qapi)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500151{
Paolo Bonzinie38ac962012-03-22 12:51:10 +0100152 GHashTable *h;
Paolo Bonzini3d344c22016-07-07 17:53:18 +0200153 StackObject *tos = g_new0(StackObject, 1);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500154
Eric Blakeb471d012016-04-28 15:45:12 -0600155 assert(obj);
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100156 tos->name = name;
Eric Blakeb471d012016-04-28 15:45:12 -0600157 tos->obj = obj;
Eric Blake1158bb22016-06-09 10:48:34 -0600158 tos->qapi = qapi;
Paolo Bonzinie38ac962012-03-22 12:51:10 +0100159
160 if (qiv->strict && qobject_type(obj) == QTYPE_QDICT) {
161 h = g_hash_table_new(g_str_hash, g_str_equal);
162 qdict_iter(qobject_to_qdict(obj), qdict_add_key, h);
Eric Blakeb471d012016-04-28 15:45:12 -0600163 tos->h = h;
Eric Blakefcf3cb22016-04-28 15:45:19 -0600164 } else if (qobject_type(obj) == QTYPE_QLIST) {
165 tos->entry = qlist_first(qobject_to_qlist(obj));
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100166 tos->index = -1;
Paolo Bonzinie38ac962012-03-22 12:51:10 +0100167 }
168
Paolo Bonzini3d344c22016-07-07 17:53:18 +0200169 QSLIST_INSERT_HEAD(&qiv->stack, tos, node);
Eric Blaked9f62dd2016-04-28 15:45:31 -0600170 return tos->entry;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500171}
172
NODA, Kai57a33d82012-04-21 22:41:27 +0900173
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100174static void qobject_input_check_struct(Visitor *v, Error **errp)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500175{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100176 QObjectInputVisitor *qiv = to_qiv(v);
Paolo Bonzini3d344c22016-07-07 17:53:18 +0200177 StackObject *tos = QSLIST_FIRST(&qiv->stack);
Eric Blake15c2f662016-04-28 15:45:27 -0600178
Paolo Bonzini3d344c22016-07-07 17:53:18 +0200179 assert(tos && !tos->entry);
NODA, Kai57a33d82012-04-21 22:41:27 +0900180 if (qiv->strict) {
Eric Blakefcf3cb22016-04-28 15:45:19 -0600181 GHashTable *const top_ht = tos->h;
NODA, Kai57a33d82012-04-21 22:41:27 +0900182 if (top_ht) {
Eric Blakef96493b2016-02-17 23:48:15 -0700183 GHashTableIter iter;
184 const char *key;
185
186 g_hash_table_iter_init(&iter, top_ht);
187 if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) {
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100188 error_setg(errp, "Parameter '%s' is unexpected",
189 full_name(qiv, key));
NODA, Kai57a33d82012-04-21 22:41:27 +0900190 }
Eric Blake15c2f662016-04-28 15:45:27 -0600191 }
192 }
193}
194
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100195static void qobject_input_stack_object_free(StackObject *tos)
Paolo Bonzini3d344c22016-07-07 17:53:18 +0200196{
197 if (tos->h) {
198 g_hash_table_unref(tos->h);
199 }
200
201 g_free(tos);
202}
203
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100204static void qobject_input_pop(Visitor *v, void **obj)
Eric Blake15c2f662016-04-28 15:45:27 -0600205{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100206 QObjectInputVisitor *qiv = to_qiv(v);
Paolo Bonzini3d344c22016-07-07 17:53:18 +0200207 StackObject *tos = QSLIST_FIRST(&qiv->stack);
Eric Blake15c2f662016-04-28 15:45:27 -0600208
Paolo Bonzini3d344c22016-07-07 17:53:18 +0200209 assert(tos && tos->qapi == obj);
210 QSLIST_REMOVE_HEAD(&qiv->stack, node);
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100211 qobject_input_stack_object_free(tos);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500212}
213
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100214static void qobject_input_start_struct(Visitor *v, const char *name, void **obj,
215 size_t size, Error **errp)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500216{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100217 QObjectInputVisitor *qiv = to_qiv(v);
218 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500219
Eric Blakee58d6952016-04-28 15:45:10 -0600220 if (obj) {
221 *obj = NULL;
222 }
Marc-André Lureau1382d4a2016-09-30 13:59:48 +0400223 if (!qobj) {
224 return;
225 }
226 if (qobject_type(qobj) != QTYPE_QDICT) {
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100227 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
228 full_name(qiv, name), "object");
Michael Rothc40cc0a2011-07-19 14:50:33 -0500229 return;
230 }
231
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100232 qobject_input_push(qiv, name, qobj, obj);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500233
234 if (obj) {
Anthony Liguori7267c092011-08-20 22:09:37 -0500235 *obj = g_malloc0(size);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500236 }
237}
238
Michael Rothc40cc0a2011-07-19 14:50:33 -0500239
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100240static void qobject_input_start_list(Visitor *v, const char *name,
241 GenericList **list, size_t size,
242 Error **errp)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500243{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100244 QObjectInputVisitor *qiv = to_qiv(v);
245 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
Eric Blaked9f62dd2016-04-28 15:45:31 -0600246 const QListEntry *entry;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500247
Markus Armbruster58561c22017-03-03 13:32:33 +0100248 if (list) {
249 *list = NULL;
250 }
Marc-André Lureau1382d4a2016-09-30 13:59:48 +0400251 if (!qobj) {
252 return;
253 }
254 if (qobject_type(qobj) != QTYPE_QLIST) {
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100255 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
256 full_name(qiv, name), "array");
Michael Rothc40cc0a2011-07-19 14:50:33 -0500257 return;
258 }
259
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100260 entry = qobject_input_push(qiv, name, qobj, list);
Markus Armbruster58561c22017-03-03 13:32:33 +0100261 if (entry && list) {
262 *list = g_malloc0(size);
Eric Blaked9f62dd2016-04-28 15:45:31 -0600263 }
Michael Rothc40cc0a2011-07-19 14:50:33 -0500264}
265
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100266static GenericList *qobject_input_next_list(Visitor *v, GenericList *tail,
267 size_t size)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500268{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100269 QObjectInputVisitor *qiv = to_qiv(v);
Paolo Bonzini3d344c22016-07-07 17:53:18 +0200270 StackObject *so = QSLIST_FIRST(&qiv->stack);
Paolo Bonzini3a86a0f2012-03-22 22:38:40 +0100271
Eric Blakefcf3cb22016-04-28 15:45:19 -0600272 if (!so->entry) {
Michael Rothc40cc0a2011-07-19 14:50:33 -0500273 return NULL;
274 }
Eric Blaked9f62dd2016-04-28 15:45:31 -0600275 tail->next = g_malloc0(size);
276 return tail->next;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500277}
278
Michael Rothc40cc0a2011-07-19 14:50:33 -0500279
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100280static void qobject_input_start_alternate(Visitor *v, const char *name,
281 GenericAlternate **obj, size_t size,
282 bool promote_int, Error **errp)
Kevin Wolf69dd62d2013-07-08 16:14:21 +0200283{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100284 QObjectInputVisitor *qiv = to_qiv(v);
285 QObject *qobj = qobject_input_get_object(qiv, name, false, errp);
Kevin Wolf69dd62d2013-07-08 16:14:21 +0200286
287 if (!qobj) {
Eric Blakedbf11922016-02-17 23:48:29 -0700288 *obj = NULL;
Kevin Wolf69dd62d2013-07-08 16:14:21 +0200289 return;
290 }
Eric Blakedbf11922016-02-17 23:48:29 -0700291 *obj = g_malloc0(size);
292 (*obj)->type = qobject_type(qobj);
293 if (promote_int && (*obj)->type == QTYPE_QINT) {
294 (*obj)->type = QTYPE_QFLOAT;
Eric Blaked00341a2015-12-01 22:20:51 -0700295 }
Kevin Wolf69dd62d2013-07-08 16:14:21 +0200296}
297
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100298static void qobject_input_type_int64(Visitor *v, const char *name, int64_t *obj,
299 Error **errp)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500300{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100301 QObjectInputVisitor *qiv = to_qiv(v);
302 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
Marc-André Lureau1382d4a2016-09-30 13:59:48 +0400303 QInt *qint;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500304
Marc-André Lureau1382d4a2016-09-30 13:59:48 +0400305 if (!qobj) {
306 return;
307 }
308 qint = qobject_to_qint(qobj);
Markus Armbrusterfcf73f62015-10-15 16:15:35 +0200309 if (!qint) {
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100310 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
311 full_name(qiv, name), "integer");
Michael Rothc40cc0a2011-07-19 14:50:33 -0500312 return;
313 }
314
Markus Armbrusterfcf73f62015-10-15 16:15:35 +0200315 *obj = qint_get_int(qint);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500316}
317
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100318static void qobject_input_type_uint64(Visitor *v, const char *name,
319 uint64_t *obj, Error **errp)
Eric Blakef755dea2016-01-29 06:48:50 -0700320{
321 /* FIXME: qobject_to_qint mishandles values over INT64_MAX */
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100322 QObjectInputVisitor *qiv = to_qiv(v);
323 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
Marc-André Lureau1382d4a2016-09-30 13:59:48 +0400324 QInt *qint;
Eric Blakef755dea2016-01-29 06:48:50 -0700325
Marc-André Lureau1382d4a2016-09-30 13:59:48 +0400326 if (!qobj) {
327 return;
328 }
329 qint = qobject_to_qint(qobj);
Eric Blakef755dea2016-01-29 06:48:50 -0700330 if (!qint) {
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100331 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
332 full_name(qiv, name), "integer");
Eric Blakef755dea2016-01-29 06:48:50 -0700333 return;
334 }
335
336 *obj = qint_get_int(qint);
337}
338
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100339static void qobject_input_type_bool(Visitor *v, const char *name, bool *obj,
340 Error **errp)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500341{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100342 QObjectInputVisitor *qiv = to_qiv(v);
343 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
Marc-André Lureau1382d4a2016-09-30 13:59:48 +0400344 QBool *qbool;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500345
Marc-André Lureau1382d4a2016-09-30 13:59:48 +0400346 if (!qobj) {
347 return;
348 }
349 qbool = qobject_to_qbool(qobj);
Markus Armbruster14b61602015-10-15 16:15:33 +0200350 if (!qbool) {
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100351 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
352 full_name(qiv, name), "boolean");
Michael Rothc40cc0a2011-07-19 14:50:33 -0500353 return;
354 }
355
Markus Armbruster14b61602015-10-15 16:15:33 +0200356 *obj = qbool_get_bool(qbool);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500357}
358
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100359static void qobject_input_type_str(Visitor *v, const char *name, char **obj,
360 Error **errp)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500361{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100362 QObjectInputVisitor *qiv = to_qiv(v);
363 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
Marc-André Lureau1382d4a2016-09-30 13:59:48 +0400364 QString *qstr;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500365
Marc-André Lureau1382d4a2016-09-30 13:59:48 +0400366 *obj = NULL;
367 if (!qobj) {
368 return;
369 }
370 qstr = qobject_to_qstring(qobj);
Markus Armbruster7f027842015-10-15 16:15:37 +0200371 if (!qstr) {
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100372 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
373 full_name(qiv, name), "string");
Michael Rothc40cc0a2011-07-19 14:50:33 -0500374 return;
375 }
376
Markus Armbruster7f027842015-10-15 16:15:37 +0200377 *obj = g_strdup(qstring_get_str(qstr));
Michael Rothc40cc0a2011-07-19 14:50:33 -0500378}
379
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100380static void qobject_input_type_number(Visitor *v, const char *name, double *obj,
381 Error **errp)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500382{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100383 QObjectInputVisitor *qiv = to_qiv(v);
384 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
Markus Armbrusterfcf73f62015-10-15 16:15:35 +0200385 QInt *qint;
386 QFloat *qfloat;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500387
Marc-André Lureau1382d4a2016-09-30 13:59:48 +0400388 if (!qobj) {
389 return;
390 }
Markus Armbrusterfcf73f62015-10-15 16:15:35 +0200391 qint = qobject_to_qint(qobj);
392 if (qint) {
393 *obj = qint_get_int(qobject_to_qint(qobj));
Michael Rothc40cc0a2011-07-19 14:50:33 -0500394 return;
395 }
396
Markus Armbrusterfcf73f62015-10-15 16:15:35 +0200397 qfloat = qobject_to_qfloat(qobj);
398 if (qfloat) {
Michael Roth1ee51872012-05-11 12:43:24 -0500399 *obj = qfloat_get_double(qobject_to_qfloat(qobj));
Markus Armbrusterfcf73f62015-10-15 16:15:35 +0200400 return;
Michael Roth1ee51872012-05-11 12:43:24 -0500401 }
Markus Armbrusterfcf73f62015-10-15 16:15:35 +0200402
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100403 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
404 full_name(qiv, name), "number");
Michael Rothc40cc0a2011-07-19 14:50:33 -0500405}
406
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100407static void qobject_input_type_any(Visitor *v, const char *name, QObject **obj,
408 Error **errp)
Markus Armbruster28770e02015-09-16 13:06:24 +0200409{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100410 QObjectInputVisitor *qiv = to_qiv(v);
411 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
Markus Armbruster28770e02015-09-16 13:06:24 +0200412
Marc-André Lureau1382d4a2016-09-30 13:59:48 +0400413 *obj = NULL;
Marc-André Lureauc4897802016-09-23 00:39:26 +0400414 if (!qobj) {
Marc-André Lureauc4897802016-09-23 00:39:26 +0400415 return;
416 }
417
Markus Armbruster28770e02015-09-16 13:06:24 +0200418 qobject_incref(qobj);
419 *obj = qobj;
420}
421
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100422static void qobject_input_type_null(Visitor *v, const char *name, Error **errp)
Eric Blake3bc97fd2016-04-28 15:45:22 -0600423{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100424 QObjectInputVisitor *qiv = to_qiv(v);
425 QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
Eric Blake3df016f2016-04-28 15:45:23 -0600426
Marc-André Lureauc4897802016-09-23 00:39:26 +0400427 if (!qobj) {
Marc-André Lureauc4897802016-09-23 00:39:26 +0400428 return;
429 }
430
Eric Blake3df016f2016-04-28 15:45:23 -0600431 if (qobject_type(qobj) != QTYPE_QNULL) {
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100432 error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
433 full_name(qiv, name), "null");
Eric Blake3df016f2016-04-28 15:45:23 -0600434 }
Eric Blake3bc97fd2016-04-28 15:45:22 -0600435}
436
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100437static void qobject_input_optional(Visitor *v, const char *name, bool *present)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500438{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100439 QObjectInputVisitor *qiv = to_qiv(v);
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100440 QObject *qobj = qobject_input_try_get_object(qiv, name, false);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500441
442 if (!qobj) {
443 *present = false;
444 return;
445 }
446
447 *present = true;
448}
449
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100450static void qobject_input_free(Visitor *v)
Eric Blake2c0ef9f2016-06-09 10:48:35 -0600451{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100452 QObjectInputVisitor *qiv = to_qiv(v);
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100453
Paolo Bonzini3d344c22016-07-07 17:53:18 +0200454 while (!QSLIST_EMPTY(&qiv->stack)) {
455 StackObject *tos = QSLIST_FIRST(&qiv->stack);
456
457 QSLIST_REMOVE_HEAD(&qiv->stack, node);
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100458 qobject_input_stack_object_free(tos);
Paolo Bonzini3d344c22016-07-07 17:53:18 +0200459 }
Eric Blake2c0ef9f2016-06-09 10:48:35 -0600460
Eric Blakeb70ce1012016-06-09 10:48:38 -0600461 qobject_decref(qiv->root);
Markus Armbrustera9fc37f2017-03-03 13:32:34 +0100462 if (qiv->errname) {
463 g_string_free(qiv->errname, TRUE);
464 }
Eric Blakeb70ce1012016-06-09 10:48:38 -0600465 g_free(qiv);
Eric Blake2c0ef9f2016-06-09 10:48:35 -0600466}
467
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100468Visitor *qobject_input_visitor_new(QObject *obj, bool strict)
Michael Rothc40cc0a2011-07-19 14:50:33 -0500469{
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100470 QObjectInputVisitor *v;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500471
Marc-André Lureau5d0cbbc2016-09-30 13:59:46 +0400472 assert(obj);
Anthony Liguori7267c092011-08-20 22:09:37 -0500473 v = g_malloc0(sizeof(*v));
Michael Rothc40cc0a2011-07-19 14:50:33 -0500474
Eric Blake983f52d2016-04-28 15:45:09 -0600475 v->visitor.type = VISITOR_INPUT;
Daniel P. Berrange09e68362016-09-30 15:45:27 +0100476 v->visitor.start_struct = qobject_input_start_struct;
477 v->visitor.check_struct = qobject_input_check_struct;
478 v->visitor.end_struct = qobject_input_pop;
479 v->visitor.start_list = qobject_input_start_list;
480 v->visitor.next_list = qobject_input_next_list;
481 v->visitor.end_list = qobject_input_pop;
482 v->visitor.start_alternate = qobject_input_start_alternate;
483 v->visitor.type_int64 = qobject_input_type_int64;
484 v->visitor.type_uint64 = qobject_input_type_uint64;
485 v->visitor.type_bool = qobject_input_type_bool;
486 v->visitor.type_str = qobject_input_type_str;
487 v->visitor.type_number = qobject_input_type_number;
488 v->visitor.type_any = qobject_input_type_any;
489 v->visitor.type_null = qobject_input_type_null;
490 v->visitor.optional = qobject_input_optional;
491 v->visitor.free = qobject_input_free;
Eric Blakefc471c12016-04-28 15:45:13 -0600492 v->strict = strict;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500493
Eric Blakece140b12016-04-28 15:45:18 -0600494 v->root = obj;
Paolo Bonzini4faaec62012-03-22 12:51:09 +0100495 qobject_incref(obj);
Michael Rothc40cc0a2011-07-19 14:50:33 -0500496
Eric Blakeb70ce1012016-06-09 10:48:38 -0600497 return &v->visitor;
Michael Rothc40cc0a2011-07-19 14:50:33 -0500498}