cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

qobject-input-visitor.c (21924B)


      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}