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