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