qobject-input-visitor.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. /*
  2. * Input Visitor
  3. *
  4. * Copyright (C) 2012-2016 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 "qapi/error.h"
  16. #include "qapi/qobject-input-visitor.h"
  17. #include "qapi/visitor-impl.h"
  18. #include "qemu/queue.h"
  19. #include "qemu-common.h"
  20. #include "qapi/qmp/types.h"
  21. #include "qapi/qmp/qerror.h"
  22. #define QIV_STACK_SIZE 1024
  23. typedef struct StackObject
  24. {
  25. QObject *obj; /* Object being visited */
  26. void *qapi; /* sanity check that caller uses same pointer */
  27. GHashTable *h; /* If obj is dict: unvisited keys */
  28. const QListEntry *entry; /* If obj is list: unvisited tail */
  29. QSLIST_ENTRY(StackObject) node;
  30. } StackObject;
  31. struct QObjectInputVisitor
  32. {
  33. Visitor visitor;
  34. /* Root of visit at visitor creation. */
  35. QObject *root;
  36. /* Stack of objects being visited (all entries will be either
  37. * QDict or QList). */
  38. QSLIST_HEAD(, StackObject) stack;
  39. /* True to reject parse in visit_end_struct() if unvisited keys remain. */
  40. bool strict;
  41. };
  42. static QObjectInputVisitor *to_qiv(Visitor *v)
  43. {
  44. return container_of(v, QObjectInputVisitor, visitor);
  45. }
  46. static QObject *qobject_input_get_object(QObjectInputVisitor *qiv,
  47. const char *name,
  48. bool consume, Error **errp)
  49. {
  50. StackObject *tos;
  51. QObject *qobj;
  52. QObject *ret;
  53. if (QSLIST_EMPTY(&qiv->stack)) {
  54. /* Starting at root, name is ignored. */
  55. assert(qiv->root);
  56. return qiv->root;
  57. }
  58. /* We are in a container; find the next element. */
  59. tos = QSLIST_FIRST(&qiv->stack);
  60. qobj = tos->obj;
  61. assert(qobj);
  62. if (qobject_type(qobj) == QTYPE_QDICT) {
  63. assert(name);
  64. ret = qdict_get(qobject_to_qdict(qobj), name);
  65. if (tos->h && consume && ret) {
  66. bool removed = g_hash_table_remove(tos->h, name);
  67. assert(removed);
  68. }
  69. if (!ret) {
  70. error_setg(errp, QERR_MISSING_PARAMETER, name);
  71. }
  72. } else {
  73. assert(qobject_type(qobj) == QTYPE_QLIST);
  74. assert(!name);
  75. ret = qlist_entry_obj(tos->entry);
  76. assert(ret);
  77. if (consume) {
  78. tos->entry = qlist_next(tos->entry);
  79. }
  80. }
  81. return ret;
  82. }
  83. static void qdict_add_key(const char *key, QObject *obj, void *opaque)
  84. {
  85. GHashTable *h = opaque;
  86. g_hash_table_insert(h, (gpointer) key, NULL);
  87. }
  88. static const QListEntry *qobject_input_push(QObjectInputVisitor *qiv,
  89. QObject *obj, void *qapi,
  90. Error **errp)
  91. {
  92. GHashTable *h;
  93. StackObject *tos = g_new0(StackObject, 1);
  94. assert(obj);
  95. tos->obj = obj;
  96. tos->qapi = qapi;
  97. if (qiv->strict && qobject_type(obj) == QTYPE_QDICT) {
  98. h = g_hash_table_new(g_str_hash, g_str_equal);
  99. qdict_iter(qobject_to_qdict(obj), qdict_add_key, h);
  100. tos->h = h;
  101. } else if (qobject_type(obj) == QTYPE_QLIST) {
  102. tos->entry = qlist_first(qobject_to_qlist(obj));
  103. }
  104. QSLIST_INSERT_HEAD(&qiv->stack, tos, node);
  105. return tos->entry;
  106. }
  107. static void qobject_input_check_struct(Visitor *v, Error **errp)
  108. {
  109. QObjectInputVisitor *qiv = to_qiv(v);
  110. StackObject *tos = QSLIST_FIRST(&qiv->stack);
  111. assert(tos && !tos->entry);
  112. if (qiv->strict) {
  113. GHashTable *const top_ht = tos->h;
  114. if (top_ht) {
  115. GHashTableIter iter;
  116. const char *key;
  117. g_hash_table_iter_init(&iter, top_ht);
  118. if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) {
  119. error_setg(errp, QERR_QMP_EXTRA_MEMBER, key);
  120. }
  121. }
  122. }
  123. }
  124. static void qobject_input_stack_object_free(StackObject *tos)
  125. {
  126. if (tos->h) {
  127. g_hash_table_unref(tos->h);
  128. }
  129. g_free(tos);
  130. }
  131. static void qobject_input_pop(Visitor *v, void **obj)
  132. {
  133. QObjectInputVisitor *qiv = to_qiv(v);
  134. StackObject *tos = QSLIST_FIRST(&qiv->stack);
  135. assert(tos && tos->qapi == obj);
  136. QSLIST_REMOVE_HEAD(&qiv->stack, node);
  137. qobject_input_stack_object_free(tos);
  138. }
  139. static void qobject_input_start_struct(Visitor *v, const char *name, void **obj,
  140. size_t size, Error **errp)
  141. {
  142. QObjectInputVisitor *qiv = to_qiv(v);
  143. QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
  144. Error *err = NULL;
  145. if (obj) {
  146. *obj = NULL;
  147. }
  148. if (!qobj) {
  149. return;
  150. }
  151. if (qobject_type(qobj) != QTYPE_QDICT) {
  152. error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
  153. "QDict");
  154. return;
  155. }
  156. qobject_input_push(qiv, qobj, obj, &err);
  157. if (err) {
  158. error_propagate(errp, err);
  159. return;
  160. }
  161. if (obj) {
  162. *obj = g_malloc0(size);
  163. }
  164. }
  165. static void qobject_input_start_list(Visitor *v, const char *name,
  166. GenericList **list, size_t size,
  167. Error **errp)
  168. {
  169. QObjectInputVisitor *qiv = to_qiv(v);
  170. QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
  171. const QListEntry *entry;
  172. if (!qobj) {
  173. return;
  174. }
  175. if (qobject_type(qobj) != QTYPE_QLIST) {
  176. if (list) {
  177. *list = NULL;
  178. }
  179. error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
  180. "list");
  181. return;
  182. }
  183. entry = qobject_input_push(qiv, qobj, list, errp);
  184. if (list) {
  185. if (entry) {
  186. *list = g_malloc0(size);
  187. } else {
  188. *list = NULL;
  189. }
  190. }
  191. }
  192. static GenericList *qobject_input_next_list(Visitor *v, GenericList *tail,
  193. size_t size)
  194. {
  195. QObjectInputVisitor *qiv = to_qiv(v);
  196. StackObject *so = QSLIST_FIRST(&qiv->stack);
  197. if (!so->entry) {
  198. return NULL;
  199. }
  200. tail->next = g_malloc0(size);
  201. return tail->next;
  202. }
  203. static void qobject_input_start_alternate(Visitor *v, const char *name,
  204. GenericAlternate **obj, size_t size,
  205. bool promote_int, Error **errp)
  206. {
  207. QObjectInputVisitor *qiv = to_qiv(v);
  208. QObject *qobj = qobject_input_get_object(qiv, name, false, errp);
  209. if (!qobj) {
  210. *obj = NULL;
  211. return;
  212. }
  213. *obj = g_malloc0(size);
  214. (*obj)->type = qobject_type(qobj);
  215. if (promote_int && (*obj)->type == QTYPE_QINT) {
  216. (*obj)->type = QTYPE_QFLOAT;
  217. }
  218. }
  219. static void qobject_input_type_int64(Visitor *v, const char *name, int64_t *obj,
  220. Error **errp)
  221. {
  222. QObjectInputVisitor *qiv = to_qiv(v);
  223. QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
  224. QInt *qint;
  225. if (!qobj) {
  226. return;
  227. }
  228. qint = qobject_to_qint(qobj);
  229. if (!qint) {
  230. error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
  231. "integer");
  232. return;
  233. }
  234. *obj = qint_get_int(qint);
  235. }
  236. static void qobject_input_type_uint64(Visitor *v, const char *name,
  237. uint64_t *obj, Error **errp)
  238. {
  239. /* FIXME: qobject_to_qint mishandles values over INT64_MAX */
  240. QObjectInputVisitor *qiv = to_qiv(v);
  241. QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
  242. QInt *qint;
  243. if (!qobj) {
  244. return;
  245. }
  246. qint = qobject_to_qint(qobj);
  247. if (!qint) {
  248. error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
  249. "integer");
  250. return;
  251. }
  252. *obj = qint_get_int(qint);
  253. }
  254. static void qobject_input_type_bool(Visitor *v, const char *name, bool *obj,
  255. Error **errp)
  256. {
  257. QObjectInputVisitor *qiv = to_qiv(v);
  258. QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
  259. QBool *qbool;
  260. if (!qobj) {
  261. return;
  262. }
  263. qbool = qobject_to_qbool(qobj);
  264. if (!qbool) {
  265. error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
  266. "boolean");
  267. return;
  268. }
  269. *obj = qbool_get_bool(qbool);
  270. }
  271. static void qobject_input_type_str(Visitor *v, const char *name, char **obj,
  272. Error **errp)
  273. {
  274. QObjectInputVisitor *qiv = to_qiv(v);
  275. QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
  276. QString *qstr;
  277. *obj = NULL;
  278. if (!qobj) {
  279. return;
  280. }
  281. qstr = qobject_to_qstring(qobj);
  282. if (!qstr) {
  283. error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
  284. "string");
  285. return;
  286. }
  287. *obj = g_strdup(qstring_get_str(qstr));
  288. }
  289. static void qobject_input_type_number(Visitor *v, const char *name, double *obj,
  290. Error **errp)
  291. {
  292. QObjectInputVisitor *qiv = to_qiv(v);
  293. QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
  294. QInt *qint;
  295. QFloat *qfloat;
  296. if (!qobj) {
  297. return;
  298. }
  299. qint = qobject_to_qint(qobj);
  300. if (qint) {
  301. *obj = qint_get_int(qobject_to_qint(qobj));
  302. return;
  303. }
  304. qfloat = qobject_to_qfloat(qobj);
  305. if (qfloat) {
  306. *obj = qfloat_get_double(qobject_to_qfloat(qobj));
  307. return;
  308. }
  309. error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
  310. "number");
  311. }
  312. static void qobject_input_type_any(Visitor *v, const char *name, QObject **obj,
  313. Error **errp)
  314. {
  315. QObjectInputVisitor *qiv = to_qiv(v);
  316. QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
  317. *obj = NULL;
  318. if (!qobj) {
  319. return;
  320. }
  321. qobject_incref(qobj);
  322. *obj = qobj;
  323. }
  324. static void qobject_input_type_null(Visitor *v, const char *name, Error **errp)
  325. {
  326. QObjectInputVisitor *qiv = to_qiv(v);
  327. QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
  328. if (!qobj) {
  329. return;
  330. }
  331. if (qobject_type(qobj) != QTYPE_QNULL) {
  332. error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
  333. "null");
  334. }
  335. }
  336. static void qobject_input_optional(Visitor *v, const char *name, bool *present)
  337. {
  338. QObjectInputVisitor *qiv = to_qiv(v);
  339. QObject *qobj = qobject_input_get_object(qiv, name, false, NULL);
  340. if (!qobj) {
  341. *present = false;
  342. return;
  343. }
  344. *present = true;
  345. }
  346. static void qobject_input_free(Visitor *v)
  347. {
  348. QObjectInputVisitor *qiv = to_qiv(v);
  349. while (!QSLIST_EMPTY(&qiv->stack)) {
  350. StackObject *tos = QSLIST_FIRST(&qiv->stack);
  351. QSLIST_REMOVE_HEAD(&qiv->stack, node);
  352. qobject_input_stack_object_free(tos);
  353. }
  354. qobject_decref(qiv->root);
  355. g_free(qiv);
  356. }
  357. Visitor *qobject_input_visitor_new(QObject *obj, bool strict)
  358. {
  359. QObjectInputVisitor *v;
  360. assert(obj);
  361. v = g_malloc0(sizeof(*v));
  362. v->visitor.type = VISITOR_INPUT;
  363. v->visitor.start_struct = qobject_input_start_struct;
  364. v->visitor.check_struct = qobject_input_check_struct;
  365. v->visitor.end_struct = qobject_input_pop;
  366. v->visitor.start_list = qobject_input_start_list;
  367. v->visitor.next_list = qobject_input_next_list;
  368. v->visitor.end_list = qobject_input_pop;
  369. v->visitor.start_alternate = qobject_input_start_alternate;
  370. v->visitor.type_int64 = qobject_input_type_int64;
  371. v->visitor.type_uint64 = qobject_input_type_uint64;
  372. v->visitor.type_bool = qobject_input_type_bool;
  373. v->visitor.type_str = qobject_input_type_str;
  374. v->visitor.type_number = qobject_input_type_number;
  375. v->visitor.type_any = qobject_input_type_any;
  376. v->visitor.type_null = qobject_input_type_null;
  377. v->visitor.optional = qobject_input_optional;
  378. v->visitor.free = qobject_input_free;
  379. v->strict = strict;
  380. v->root = obj;
  381. qobject_incref(obj);
  382. return &v->visitor;
  383. }