|
|
1.1 root 1: /*
2: * Input Visitor
3: *
4: * Copyright IBM, Corp. 2011
5: *
6: * Authors:
7: * Anthony Liguori <[email protected]>
8: *
9: * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10: * See the COPYING.LIB file in the top-level directory.
11: *
12: */
13:
14: #include "qmp-input-visitor.h"
15: #include "qemu-queue.h"
16: #include "qemu-common.h"
17: #include "qemu-objects.h"
18: #include "qerror.h"
19:
20: #define QIV_STACK_SIZE 1024
21:
22: typedef struct StackObject
23: {
24: const QObject *obj;
25: const QListEntry *entry;
26: } StackObject;
27:
28: struct QmpInputVisitor
29: {
30: Visitor visitor;
31: QObject *obj;
32: StackObject stack[QIV_STACK_SIZE];
33: int nb_stack;
34: };
35:
36: static QmpInputVisitor *to_qiv(Visitor *v)
37: {
38: return container_of(v, QmpInputVisitor, visitor);
39: }
40:
41: static const QObject *qmp_input_get_object(QmpInputVisitor *qiv,
42: const char *name)
43: {
44: const QObject *qobj;
45:
46: if (qiv->nb_stack == 0) {
47: qobj = qiv->obj;
48: } else {
49: qobj = qiv->stack[qiv->nb_stack - 1].obj;
50: }
51:
52: if (name && qobject_type(qobj) == QTYPE_QDICT) {
53: return qdict_get(qobject_to_qdict(qobj), name);
54: } else if (qiv->nb_stack > 0 && qobject_type(qobj) == QTYPE_QLIST) {
55: return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry);
56: }
57:
58: return qobj;
59: }
60:
61: static void qmp_input_push(QmpInputVisitor *qiv, const QObject *obj, Error **errp)
62: {
63: qiv->stack[qiv->nb_stack].obj = obj;
64: if (qobject_type(obj) == QTYPE_QLIST) {
65: qiv->stack[qiv->nb_stack].entry = qlist_first(qobject_to_qlist(obj));
66: }
67: qiv->nb_stack++;
68:
69: if (qiv->nb_stack >= QIV_STACK_SIZE) {
70: error_set(errp, QERR_BUFFER_OVERRUN);
71: return;
72: }
73: }
74:
75: static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
76: {
77: qiv->nb_stack--;
78: if (qiv->nb_stack < 0) {
79: error_set(errp, QERR_BUFFER_OVERRUN);
80: return;
81: }
82: }
83:
84: static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind,
85: const char *name, size_t size, Error **errp)
86: {
87: QmpInputVisitor *qiv = to_qiv(v);
88: const QObject *qobj = qmp_input_get_object(qiv, name);
89:
90: if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
91: error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
92: "QDict");
93: return;
94: }
95:
96: qmp_input_push(qiv, qobj, errp);
97: if (error_is_set(errp)) {
98: return;
99: }
100:
101: if (obj) {
102: *obj = qemu_mallocz(size);
103: }
104: }
105:
106: static void qmp_input_end_struct(Visitor *v, Error **errp)
107: {
108: QmpInputVisitor *qiv = to_qiv(v);
109:
110: qmp_input_pop(qiv, errp);
111: }
112:
113: static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
114: {
115: QmpInputVisitor *qiv = to_qiv(v);
116: const QObject *qobj = qmp_input_get_object(qiv, name);
117:
118: if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
119: error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
120: "list");
121: return;
122: }
123:
124: qmp_input_push(qiv, qobj, errp);
125: }
126:
127: static GenericList *qmp_input_next_list(Visitor *v, GenericList **list,
128: Error **errp)
129: {
130: QmpInputVisitor *qiv = to_qiv(v);
131: GenericList *entry;
132: StackObject *so = &qiv->stack[qiv->nb_stack - 1];
133:
134: if (so->entry == NULL) {
135: return NULL;
136: }
137:
138: entry = qemu_mallocz(sizeof(*entry));
139: if (*list) {
140: so->entry = qlist_next(so->entry);
141: if (so->entry == NULL) {
142: qemu_free(entry);
143: return NULL;
144: }
145: (*list)->next = entry;
146: }
147: *list = entry;
148:
149:
150: return entry;
151: }
152:
153: static void qmp_input_end_list(Visitor *v, Error **errp)
154: {
155: QmpInputVisitor *qiv = to_qiv(v);
156:
157: qmp_input_pop(qiv, errp);
158: }
159:
160: static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name,
161: Error **errp)
162: {
163: QmpInputVisitor *qiv = to_qiv(v);
164: const QObject *qobj = qmp_input_get_object(qiv, name);
165:
166: if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
167: error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
168: "integer");
169: return;
170: }
171:
172: *obj = qint_get_int(qobject_to_qint(qobj));
173: }
174:
175: static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name,
176: Error **errp)
177: {
178: QmpInputVisitor *qiv = to_qiv(v);
179: const QObject *qobj = qmp_input_get_object(qiv, name);
180:
181: if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
182: error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
183: "boolean");
184: return;
185: }
186:
187: *obj = qbool_get_int(qobject_to_qbool(qobj));
188: }
189:
190: static void qmp_input_type_str(Visitor *v, char **obj, const char *name,
191: Error **errp)
192: {
193: QmpInputVisitor *qiv = to_qiv(v);
194: const QObject *qobj = qmp_input_get_object(qiv, name);
195:
196: if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
197: error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
198: "string");
199: return;
200: }
201:
202: *obj = qemu_strdup(qstring_get_str(qobject_to_qstring(qobj)));
203: }
204:
205: static void qmp_input_type_number(Visitor *v, double *obj, const char *name,
206: Error **errp)
207: {
208: QmpInputVisitor *qiv = to_qiv(v);
209: const QObject *qobj = qmp_input_get_object(qiv, name);
210:
211: if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
212: error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
213: "double");
214: return;
215: }
216:
217: *obj = qfloat_get_double(qobject_to_qfloat(qobj));
218: }
219:
220: static void qmp_input_type_enum(Visitor *v, int *obj, const char *strings[],
221: const char *kind, const char *name,
222: Error **errp)
223: {
224: int64_t value = 0;
225: char *enum_str;
226:
227: assert(strings);
228:
229: qmp_input_type_str(v, &enum_str, name, errp);
230: if (error_is_set(errp)) {
231: return;
232: }
233:
234: while (strings[value] != NULL) {
235: if (strcmp(strings[value], enum_str) == 0) {
236: break;
237: }
238: value++;
239: }
240:
241: if (strings[value] == NULL) {
242: error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null");
243: return;
244: }
245:
246: *obj = value;
247: }
248:
249: static void qmp_input_start_optional(Visitor *v, bool *present,
250: const char *name, Error **errp)
251: {
252: QmpInputVisitor *qiv = to_qiv(v);
253: const QObject *qobj = qmp_input_get_object(qiv, name);
254:
255: if (!qobj) {
256: *present = false;
257: return;
258: }
259:
260: *present = true;
261: }
262:
263: static void qmp_input_end_optional(Visitor *v, Error **errp)
264: {
265: }
266:
267: Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
268: {
269: return &v->visitor;
270: }
271:
272: void qmp_input_visitor_cleanup(QmpInputVisitor *v)
273: {
274: qobject_decref(v->obj);
275: qemu_free(v);
276: }
277:
278: QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
279: {
280: QmpInputVisitor *v;
281:
282: v = qemu_mallocz(sizeof(*v));
283:
284: v->visitor.start_struct = qmp_input_start_struct;
285: v->visitor.end_struct = qmp_input_end_struct;
286: v->visitor.start_list = qmp_input_start_list;
287: v->visitor.next_list = qmp_input_next_list;
288: v->visitor.end_list = qmp_input_end_list;
289: v->visitor.type_enum = qmp_input_type_enum;
290: v->visitor.type_int = qmp_input_type_int;
291: v->visitor.type_bool = qmp_input_type_bool;
292: v->visitor.type_str = qmp_input_type_str;
293: v->visitor.type_number = qmp_input_type_number;
294: v->visitor.start_optional = qmp_input_start_optional;
295: v->visitor.end_optional = qmp_input_end_optional;
296:
297: v->obj = obj;
298: qobject_incref(v->obj);
299:
300: return v;
301: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.