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/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
  33typedef 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
  45struct 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
  60static 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 */
  76static 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
 115static const char *full_name(QObjectInputVisitor *qiv, const char *name)
 116{
 117    return full_name_nth(qiv, name, 0);
 118}
 119
 120static 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
 165static 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
 177static 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
 208static 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
 242static 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
 260static 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
 269static 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
 279static 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
 305static 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
 315static 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
 342static 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
 357static 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
 372static 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
 381static 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
 397static 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
 416static 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
 435static 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
 461err:
 462    error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
 463               full_name(qiv, name), "uint64");
 464    return false;
 465}
 466
 467static 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
 486static 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
 507static 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
 525static 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
 547static 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
 557static 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
 578static 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
 600static 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
 615static 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
 635static 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
 654static 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
 667static 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
 685static 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
 703static 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
 727Visitor *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
 742void 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
 750Visitor *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
 767Visitor *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