2
0

qobject-input-visitor.c 21 KB

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