xref: /openbmc/qemu/qapi/qobject-input-visitor.c (revision 835fde4a)
1 /*
2  * Input Visitor
3  *
4  * Copyright (C) 2012-2017 Red Hat, Inc.
5  * 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 
15 #include "qemu/osdep.h"
16 #include <math.h>
17 #include "qapi/compat-policy.h"
18 #include "qapi/error.h"
19 #include "qapi/qobject-input-visitor.h"
20 #include "qapi/visitor-impl.h"
21 #include "qemu/queue.h"
22 #include "qapi/qmp/qjson.h"
23 #include "qapi/qmp/qbool.h"
24 #include "qapi/qmp/qdict.h"
25 #include "qapi/qmp/qerror.h"
26 #include "qapi/qmp/qlist.h"
27 #include "qapi/qmp/qnull.h"
28 #include "qapi/qmp/qnum.h"
29 #include "qapi/qmp/qstring.h"
30 #include "qemu/cutils.h"
31 #include "qemu/option.h"
32 
33 typedef struct StackObject {
34     const char *name;            /* Name of @obj in its parent, if any */
35     QObject *obj;                /* QDict or QList being visited */
36     void *qapi; /* sanity check that caller uses same pointer */
37 
38     GHashTable *h;              /* If @obj is QDict: unvisited keys */
39     const QListEntry *entry;    /* If @obj is QList: unvisited tail */
40     unsigned index;             /* If @obj is QList: list index of @entry */
41 
42     QSLIST_ENTRY(StackObject) node; /* parent */
43 } StackObject;
44 
45 struct QObjectInputVisitor {
46     Visitor visitor;
47     CompatPolicyInput deprecated_policy;
48 
49     /* Root of visit at visitor creation. */
50     QObject *root;
51     bool keyval;                /* Assume @root made with keyval_parse() */
52 
53     /* Stack of objects being visited (all entries will be either
54      * QDict or QList). */
55     QSLIST_HEAD(, StackObject) stack;
56 
57     GString *errname;           /* Accumulator for full_name() */
58 };
59 
60 static QObjectInputVisitor *to_qiv(Visitor *v)
61 {
62     return container_of(v, QObjectInputVisitor, visitor);
63 }
64 
65 /*
66  * Find the full name of something @qiv is currently visiting.
67  * @qiv is visiting something named @name in the stack of containers
68  * @qiv->stack.
69  * If @n is zero, return its full name.
70  * If @n is positive, return the full name of the @n-th container
71  * counting from the top.  The stack of containers must have at least
72  * @n elements.
73  * The returned string is valid until the next full_name_nth(@v) or
74  * destruction of @v.
75  */
76 static const char *full_name_nth(QObjectInputVisitor *qiv, const char *name,
77                                  int n)
78 {
79     StackObject *so;
80     char buf[32];
81 
82     if (qiv->errname) {
83         g_string_truncate(qiv->errname, 0);
84     } else {
85         qiv->errname = g_string_new("");
86     }
87 
88     QSLIST_FOREACH(so , &qiv->stack, node) {
89         if (n) {
90             n--;
91         } else if (qobject_type(so->obj) == QTYPE_QDICT) {
92             g_string_prepend(qiv->errname, name ?: "<anonymous>");
93             g_string_prepend_c(qiv->errname, '.');
94         } else {
95             snprintf(buf, sizeof(buf),
96                      qiv->keyval ? ".%u" : "[%u]",
97                      so->index);
98             g_string_prepend(qiv->errname, buf);
99         }
100         name = so->name;
101     }
102     assert(!n);
103 
104     if (name) {
105         g_string_prepend(qiv->errname, name);
106     } else if (qiv->errname->str[0] == '.') {
107         g_string_erase(qiv->errname, 0, 1);
108     } else if (!qiv->errname->str[0]) {
109         return "<anonymous>";
110     }
111 
112     return qiv->errname->str;
113 }
114 
115 static const char *full_name(QObjectInputVisitor *qiv, const char *name)
116 {
117     return full_name_nth(qiv, name, 0);
118 }
119 
120 static QObject *qobject_input_try_get_object(QObjectInputVisitor *qiv,
121                                              const char *name,
122                                              bool consume)
123 {
124     StackObject *tos;
125     QObject *qobj;
126     QObject *ret;
127 
128     if (QSLIST_EMPTY(&qiv->stack)) {
129         /* Starting at root, name is ignored. */
130         assert(qiv->root);
131         return qiv->root;
132     }
133 
134     /* We are in a container; find the next element. */
135     tos = QSLIST_FIRST(&qiv->stack);
136     qobj = tos->obj;
137     assert(qobj);
138 
139     if (qobject_type(qobj) == QTYPE_QDICT) {
140         assert(name);
141         ret = qdict_get(qobject_to(QDict, qobj), name);
142         if (tos->h && consume && ret) {
143             bool removed = g_hash_table_remove(tos->h, name);
144             assert(removed);
145         }
146     } else {
147         assert(qobject_type(qobj) == QTYPE_QLIST);
148         assert(!name);
149         if (tos->entry) {
150             ret = qlist_entry_obj(tos->entry);
151             if (consume) {
152                 tos->entry = qlist_next(tos->entry);
153             }
154         } else {
155             ret = NULL;
156         }
157         if (consume) {
158             tos->index++;
159         }
160     }
161 
162     return ret;
163 }
164 
165 static QObject *qobject_input_get_object(QObjectInputVisitor *qiv,
166                                          const char *name,
167                                          bool consume, Error **errp)
168 {
169     QObject *obj = qobject_input_try_get_object(qiv, name, consume);
170 
171     if (!obj) {
172         error_setg(errp, QERR_MISSING_PARAMETER, full_name(qiv, name));
173     }
174     return obj;
175 }
176 
177 static const char *qobject_input_get_keyval(QObjectInputVisitor *qiv,
178                                             const char *name,
179                                             Error **errp)
180 {
181     QObject *qobj;
182     QString *qstr;
183 
184     qobj = qobject_input_get_object(qiv, name, true, errp);
185     if (!qobj) {
186         return NULL;
187     }
188 
189     qstr = qobject_to(QString, qobj);
190     if (!qstr) {
191         switch (qobject_type(qobj)) {
192         case QTYPE_QDICT:
193         case QTYPE_QLIST:
194             error_setg(errp, "Parameters '%s.*' are unexpected",
195                        full_name(qiv, name));
196             return NULL;
197         default:
198             /* Non-string scalar (should this be an assertion?) */
199             error_setg(errp, "Internal error: parameter %s invalid",
200                        full_name(qiv, name));
201             return NULL;
202         }
203     }
204 
205     return qstring_get_str(qstr);
206 }
207 
208 static const QListEntry *qobject_input_push(QObjectInputVisitor *qiv,
209                                             const char *name,
210                                             QObject *obj, void *qapi)
211 {
212     GHashTable *h;
213     StackObject *tos = g_new0(StackObject, 1);
214     QDict *qdict = qobject_to(QDict, obj);
215     QList *qlist = qobject_to(QList, obj);
216     const QDictEntry *entry;
217 
218     assert(obj);
219     tos->name = name;
220     tos->obj = obj;
221     tos->qapi = qapi;
222 
223     if (qdict) {
224         h = g_hash_table_new(g_str_hash, g_str_equal);
225         for (entry = qdict_first(qdict);
226              entry;
227              entry = qdict_next(qdict, entry)) {
228             g_hash_table_insert(h, (void *)qdict_entry_key(entry), NULL);
229         }
230         tos->h = h;
231     } else {
232         assert(qlist);
233         tos->entry = qlist_first(qlist);
234         tos->index = -1;
235     }
236 
237     QSLIST_INSERT_HEAD(&qiv->stack, tos, node);
238     return tos->entry;
239 }
240 
241 
242 static bool qobject_input_check_struct(Visitor *v, Error **errp)
243 {
244     QObjectInputVisitor *qiv = to_qiv(v);
245     StackObject *tos = QSLIST_FIRST(&qiv->stack);
246     GHashTableIter iter;
247     const char *key;
248 
249     assert(tos && !tos->entry);
250 
251     g_hash_table_iter_init(&iter, tos->h);
252     if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) {
253         error_setg(errp, "Parameter '%s' is unexpected",
254                    full_name(qiv, key));
255         return false;
256     }
257     return true;
258 }
259 
260 static void qobject_input_stack_object_free(StackObject *tos)
261 {
262     if (tos->h) {
263         g_hash_table_unref(tos->h);
264     }
265 
266     g_free(tos);
267 }
268 
269 static void qobject_input_pop(Visitor *v, void **obj)
270 {
271     QObjectInputVisitor *qiv = to_qiv(v);
272     StackObject *tos = QSLIST_FIRST(&qiv->stack);
273 
274     assert(tos && tos->qapi == obj);
275     QSLIST_REMOVE_HEAD(&qiv->stack, node);
276     qobject_input_stack_object_free(tos);
277 }
278 
279 static bool qobject_input_start_struct(Visitor *v, const char *name, void **obj,
280                                        size_t size, Error **errp)
281 {
282     QObjectInputVisitor *qiv = to_qiv(v);
283     QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
284 
285     if (obj) {
286         *obj = NULL;
287     }
288     if (!qobj) {
289         return false;
290     }
291     if (qobject_type(qobj) != QTYPE_QDICT) {
292         error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
293                    full_name(qiv, name), "object");
294         return false;
295     }
296 
297     qobject_input_push(qiv, name, qobj, obj);
298 
299     if (obj) {
300         *obj = g_malloc0(size);
301     }
302     return true;
303 }
304 
305 static void qobject_input_end_struct(Visitor *v, void **obj)
306 {
307     QObjectInputVisitor *qiv = to_qiv(v);
308     StackObject *tos = QSLIST_FIRST(&qiv->stack);
309 
310     assert(qobject_type(tos->obj) == QTYPE_QDICT && tos->h);
311     qobject_input_pop(v, obj);
312 }
313 
314 
315 static bool qobject_input_start_list(Visitor *v, const char *name,
316                                      GenericList **list, size_t size,
317                                      Error **errp)
318 {
319     QObjectInputVisitor *qiv = to_qiv(v);
320     QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
321     const QListEntry *entry;
322 
323     if (list) {
324         *list = NULL;
325     }
326     if (!qobj) {
327         return false;
328     }
329     if (qobject_type(qobj) != QTYPE_QLIST) {
330         error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
331                    full_name(qiv, name), "array");
332         return false;
333     }
334 
335     entry = qobject_input_push(qiv, name, qobj, list);
336     if (entry && list) {
337         *list = g_malloc0(size);
338     }
339     return true;
340 }
341 
342 static GenericList *qobject_input_next_list(Visitor *v, GenericList *tail,
343                                             size_t size)
344 {
345     QObjectInputVisitor *qiv = to_qiv(v);
346     StackObject *tos = QSLIST_FIRST(&qiv->stack);
347 
348     assert(tos && qobject_to(QList, tos->obj));
349 
350     if (!tos->entry) {
351         return NULL;
352     }
353     tail->next = g_malloc0(size);
354     return tail->next;
355 }
356 
357 static bool qobject_input_check_list(Visitor *v, Error **errp)
358 {
359     QObjectInputVisitor *qiv = to_qiv(v);
360     StackObject *tos = QSLIST_FIRST(&qiv->stack);
361 
362     assert(tos && qobject_to(QList, tos->obj));
363 
364     if (tos->entry) {
365         error_setg(errp, "Only %u list elements expected in %s",
366                    tos->index + 1, full_name_nth(qiv, NULL, 1));
367         return false;
368     }
369     return true;
370 }
371 
372 static void qobject_input_end_list(Visitor *v, void **obj)
373 {
374     QObjectInputVisitor *qiv = to_qiv(v);
375     StackObject *tos = QSLIST_FIRST(&qiv->stack);
376 
377     assert(qobject_type(tos->obj) == QTYPE_QLIST && !tos->h);
378     qobject_input_pop(v, obj);
379 }
380 
381 static bool qobject_input_start_alternate(Visitor *v, const char *name,
382                                           GenericAlternate **obj, size_t size,
383                                           Error **errp)
384 {
385     QObjectInputVisitor *qiv = to_qiv(v);
386     QObject *qobj = qobject_input_get_object(qiv, name, false, errp);
387 
388     if (!qobj) {
389         *obj = NULL;
390         return false;
391     }
392     *obj = g_malloc0(size);
393     (*obj)->type = qobject_type(qobj);
394     return true;
395 }
396 
397 static bool qobject_input_type_int64(Visitor *v, const char *name, int64_t *obj,
398                                      Error **errp)
399 {
400     QObjectInputVisitor *qiv = to_qiv(v);
401     QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
402     QNum *qnum;
403 
404     if (!qobj) {
405         return false;
406     }
407     qnum = qobject_to(QNum, qobj);
408     if (!qnum || !qnum_get_try_int(qnum, obj)) {
409         error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
410                    full_name(qiv, name), "integer");
411         return false;
412     }
413     return true;
414 }
415 
416 static bool qobject_input_type_int64_keyval(Visitor *v, const char *name,
417                                             int64_t *obj, Error **errp)
418 {
419     QObjectInputVisitor *qiv = to_qiv(v);
420     const char *str = qobject_input_get_keyval(qiv, name, errp);
421 
422     if (!str) {
423         return false;
424     }
425 
426     if (qemu_strtoi64(str, NULL, 0, obj) < 0) {
427         /* TODO report -ERANGE more nicely */
428         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
429                    full_name(qiv, name), "integer");
430         return false;
431     }
432     return true;
433 }
434 
435 static bool qobject_input_type_uint64(Visitor *v, const char *name,
436                                       uint64_t *obj, Error **errp)
437 {
438     QObjectInputVisitor *qiv = to_qiv(v);
439     QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
440     QNum *qnum;
441     int64_t val;
442 
443     if (!qobj) {
444         return false;
445     }
446     qnum = qobject_to(QNum, qobj);
447     if (!qnum) {
448         goto err;
449     }
450 
451     if (qnum_get_try_uint(qnum, obj)) {
452         return true;
453     }
454 
455     /* Need to accept negative values for backward compatibility */
456     if (qnum_get_try_int(qnum, &val)) {
457         *obj = val;
458         return true;
459     }
460 
461 err:
462     error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
463                full_name(qiv, name), "uint64");
464     return false;
465 }
466 
467 static bool qobject_input_type_uint64_keyval(Visitor *v, const char *name,
468                                              uint64_t *obj, Error **errp)
469 {
470     QObjectInputVisitor *qiv = to_qiv(v);
471     const char *str = qobject_input_get_keyval(qiv, name, errp);
472 
473     if (!str) {
474         return false;
475     }
476 
477     if (qemu_strtou64(str, NULL, 0, obj) < 0) {
478         /* TODO report -ERANGE more nicely */
479         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
480                    full_name(qiv, name), "integer");
481         return false;
482     }
483     return true;
484 }
485 
486 static bool qobject_input_type_bool(Visitor *v, const char *name, bool *obj,
487                                     Error **errp)
488 {
489     QObjectInputVisitor *qiv = to_qiv(v);
490     QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
491     QBool *qbool;
492 
493     if (!qobj) {
494         return false;
495     }
496     qbool = qobject_to(QBool, qobj);
497     if (!qbool) {
498         error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
499                    full_name(qiv, name), "boolean");
500         return false;
501     }
502 
503     *obj = qbool_get_bool(qbool);
504     return true;
505 }
506 
507 static bool qobject_input_type_bool_keyval(Visitor *v, const char *name,
508                                            bool *obj, Error **errp)
509 {
510     QObjectInputVisitor *qiv = to_qiv(v);
511     const char *str = qobject_input_get_keyval(qiv, name, errp);
512 
513     if (!str) {
514         return false;
515     }
516 
517     if (!qapi_bool_parse(name, str, obj, NULL)) {
518         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
519                    full_name(qiv, name), "'on' or 'off'");
520         return false;
521     }
522     return true;
523 }
524 
525 static bool qobject_input_type_str(Visitor *v, const char *name, char **obj,
526                                    Error **errp)
527 {
528     QObjectInputVisitor *qiv = to_qiv(v);
529     QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
530     QString *qstr;
531 
532     *obj = NULL;
533     if (!qobj) {
534         return false;
535     }
536     qstr = qobject_to(QString, qobj);
537     if (!qstr) {
538         error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
539                    full_name(qiv, name), "string");
540         return false;
541     }
542 
543     *obj = g_strdup(qstring_get_str(qstr));
544     return true;
545 }
546 
547 static bool qobject_input_type_str_keyval(Visitor *v, const char *name,
548                                           char **obj, Error **errp)
549 {
550     QObjectInputVisitor *qiv = to_qiv(v);
551     const char *str = qobject_input_get_keyval(qiv, name, errp);
552 
553     *obj = g_strdup(str);
554     return !!str;
555 }
556 
557 static bool qobject_input_type_number(Visitor *v, const char *name, double *obj,
558                                       Error **errp)
559 {
560     QObjectInputVisitor *qiv = to_qiv(v);
561     QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
562     QNum *qnum;
563 
564     if (!qobj) {
565         return false;
566     }
567     qnum = qobject_to(QNum, qobj);
568     if (!qnum) {
569         error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
570                    full_name(qiv, name), "number");
571         return false;
572     }
573 
574     *obj = qnum_get_double(qnum);
575     return true;
576 }
577 
578 static bool qobject_input_type_number_keyval(Visitor *v, const char *name,
579                                              double *obj, Error **errp)
580 {
581     QObjectInputVisitor *qiv = to_qiv(v);
582     const char *str = qobject_input_get_keyval(qiv, name, errp);
583     double val;
584 
585     if (!str) {
586         return false;
587     }
588 
589     if (qemu_strtod_finite(str, NULL, &val)) {
590         /* TODO report -ERANGE more nicely */
591         error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
592                    full_name(qiv, name), "number");
593         return false;
594     }
595 
596     *obj = val;
597     return true;
598 }
599 
600 static bool qobject_input_type_any(Visitor *v, const char *name, QObject **obj,
601                                    Error **errp)
602 {
603     QObjectInputVisitor *qiv = to_qiv(v);
604     QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
605 
606     *obj = NULL;
607     if (!qobj) {
608         return false;
609     }
610 
611     *obj = qobject_ref(qobj);
612     return true;
613 }
614 
615 static bool qobject_input_type_null(Visitor *v, const char *name,
616                                     QNull **obj, Error **errp)
617 {
618     QObjectInputVisitor *qiv = to_qiv(v);
619     QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
620 
621     *obj = NULL;
622     if (!qobj) {
623         return false;
624     }
625 
626     if (qobject_type(qobj) != QTYPE_QNULL) {
627         error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
628                    full_name(qiv, name), "null");
629         return false;
630     }
631     *obj = qnull();
632     return true;
633 }
634 
635 static bool qobject_input_type_size_keyval(Visitor *v, const char *name,
636                                            uint64_t *obj, Error **errp)
637 {
638     QObjectInputVisitor *qiv = to_qiv(v);
639     const char *str = qobject_input_get_keyval(qiv, name, errp);
640 
641     if (!str) {
642         return false;
643     }
644 
645     if (qemu_strtosz(str, NULL, obj) < 0) {
646         /* TODO report -ERANGE more nicely */
647         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
648                    full_name(qiv, name), "size");
649         return false;
650     }
651     return true;
652 }
653 
654 static void qobject_input_optional(Visitor *v, const char *name, bool *present)
655 {
656     QObjectInputVisitor *qiv = to_qiv(v);
657     QObject *qobj = qobject_input_try_get_object(qiv, name, false);
658 
659     if (!qobj) {
660         *present = false;
661         return;
662     }
663 
664     *present = true;
665 }
666 
667 static bool qobject_input_deprecated_accept(Visitor *v, const char *name,
668                                             Error **errp)
669 {
670     QObjectInputVisitor *qiv = to_qiv(v);
671 
672     switch (qiv->deprecated_policy) {
673     case COMPAT_POLICY_INPUT_ACCEPT:
674         return true;
675     case COMPAT_POLICY_INPUT_REJECT:
676         error_setg(errp, "Deprecated parameter '%s' disabled by policy",
677                    name);
678         return false;
679     case COMPAT_POLICY_INPUT_CRASH:
680     default:
681         abort();
682     }
683 }
684 
685 static void qobject_input_free(Visitor *v)
686 {
687     QObjectInputVisitor *qiv = to_qiv(v);
688 
689     while (!QSLIST_EMPTY(&qiv->stack)) {
690         StackObject *tos = QSLIST_FIRST(&qiv->stack);
691 
692         QSLIST_REMOVE_HEAD(&qiv->stack, node);
693         qobject_input_stack_object_free(tos);
694     }
695 
696     qobject_unref(qiv->root);
697     if (qiv->errname) {
698         g_string_free(qiv->errname, TRUE);
699     }
700     g_free(qiv);
701 }
702 
703 static QObjectInputVisitor *qobject_input_visitor_base_new(QObject *obj)
704 {
705     QObjectInputVisitor *v = g_malloc0(sizeof(*v));
706 
707     assert(obj);
708 
709     v->visitor.type = VISITOR_INPUT;
710     v->visitor.start_struct = qobject_input_start_struct;
711     v->visitor.check_struct = qobject_input_check_struct;
712     v->visitor.end_struct = qobject_input_end_struct;
713     v->visitor.start_list = qobject_input_start_list;
714     v->visitor.next_list = qobject_input_next_list;
715     v->visitor.check_list = qobject_input_check_list;
716     v->visitor.end_list = qobject_input_end_list;
717     v->visitor.start_alternate = qobject_input_start_alternate;
718     v->visitor.optional = qobject_input_optional;
719     v->visitor.deprecated_accept = qobject_input_deprecated_accept;
720     v->visitor.free = qobject_input_free;
721 
722     v->root = qobject_ref(obj);
723 
724     return v;
725 }
726 
727 Visitor *qobject_input_visitor_new(QObject *obj)
728 {
729     QObjectInputVisitor *v = qobject_input_visitor_base_new(obj);
730 
731     v->visitor.type_int64 = qobject_input_type_int64;
732     v->visitor.type_uint64 = qobject_input_type_uint64;
733     v->visitor.type_bool = qobject_input_type_bool;
734     v->visitor.type_str = qobject_input_type_str;
735     v->visitor.type_number = qobject_input_type_number;
736     v->visitor.type_any = qobject_input_type_any;
737     v->visitor.type_null = qobject_input_type_null;
738 
739     return &v->visitor;
740 }
741 
742 void qobject_input_visitor_set_policy(Visitor *v,
743                                        CompatPolicyInput deprecated)
744 {
745     QObjectInputVisitor *qiv = to_qiv(v);
746 
747     qiv->deprecated_policy = deprecated;
748 }
749 
750 Visitor *qobject_input_visitor_new_keyval(QObject *obj)
751 {
752     QObjectInputVisitor *v = qobject_input_visitor_base_new(obj);
753 
754     v->visitor.type_int64 = qobject_input_type_int64_keyval;
755     v->visitor.type_uint64 = qobject_input_type_uint64_keyval;
756     v->visitor.type_bool = qobject_input_type_bool_keyval;
757     v->visitor.type_str = qobject_input_type_str_keyval;
758     v->visitor.type_number = qobject_input_type_number_keyval;
759     v->visitor.type_any = qobject_input_type_any;
760     v->visitor.type_null = qobject_input_type_null;
761     v->visitor.type_size = qobject_input_type_size_keyval;
762     v->keyval = true;
763 
764     return &v->visitor;
765 }
766 
767 Visitor *qobject_input_visitor_new_str(const char *str,
768                                        const char *implied_key,
769                                        Error **errp)
770 {
771     bool is_json = str[0] == '{';
772     QObject *obj;
773     QDict *args;
774     Visitor *v;
775 
776     if (is_json) {
777         obj = qobject_from_json(str, errp);
778         if (!obj) {
779             return NULL;
780         }
781         args = qobject_to(QDict, obj);
782         assert(args);
783         v = qobject_input_visitor_new(QOBJECT(args));
784     } else {
785         args = keyval_parse(str, implied_key, NULL, errp);
786         if (!args) {
787             return NULL;
788         }
789         v = qobject_input_visitor_new_keyval(QOBJECT(args));
790     }
791     qobject_unref(args);
792 
793     return v;
794 }
795