|
|
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) {
1.1.1.2 ! root 102: *obj = g_malloc0(size);
1.1 root 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:
1.1.1.2 ! root 138: entry = g_malloc0(sizeof(*entry));
1.1 root 139: if (*list) {
140: so->entry = qlist_next(so->entry);
141: if (so->entry == NULL) {
1.1.1.2 ! root 142: g_free(entry);
1.1 root 143: return NULL;
144: }
145: (*list)->next = entry;
146: }
147:
148: return entry;
149: }
150:
151: static void qmp_input_end_list(Visitor *v, Error **errp)
152: {
153: QmpInputVisitor *qiv = to_qiv(v);
154:
155: qmp_input_pop(qiv, errp);
156: }
157:
158: static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name,
159: Error **errp)
160: {
161: QmpInputVisitor *qiv = to_qiv(v);
162: const QObject *qobj = qmp_input_get_object(qiv, name);
163:
164: if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
165: error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
166: "integer");
167: return;
168: }
169:
170: *obj = qint_get_int(qobject_to_qint(qobj));
171: }
172:
173: static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name,
174: Error **errp)
175: {
176: QmpInputVisitor *qiv = to_qiv(v);
177: const QObject *qobj = qmp_input_get_object(qiv, name);
178:
179: if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
180: error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
181: "boolean");
182: return;
183: }
184:
185: *obj = qbool_get_int(qobject_to_qbool(qobj));
186: }
187:
188: static void qmp_input_type_str(Visitor *v, char **obj, const char *name,
189: Error **errp)
190: {
191: QmpInputVisitor *qiv = to_qiv(v);
192: const QObject *qobj = qmp_input_get_object(qiv, name);
193:
194: if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
195: error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
196: "string");
197: return;
198: }
199:
1.1.1.2 ! root 200: *obj = g_strdup(qstring_get_str(qobject_to_qstring(qobj)));
1.1 root 201: }
202:
203: static void qmp_input_type_number(Visitor *v, double *obj, const char *name,
204: Error **errp)
205: {
206: QmpInputVisitor *qiv = to_qiv(v);
207: const QObject *qobj = qmp_input_get_object(qiv, name);
208:
209: if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
210: error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
211: "double");
212: return;
213: }
214:
215: *obj = qfloat_get_double(qobject_to_qfloat(qobj));
216: }
217:
218: static void qmp_input_type_enum(Visitor *v, int *obj, const char *strings[],
219: const char *kind, const char *name,
220: Error **errp)
221: {
222: int64_t value = 0;
223: char *enum_str;
224:
225: assert(strings);
226:
227: qmp_input_type_str(v, &enum_str, name, errp);
228: if (error_is_set(errp)) {
229: return;
230: }
231:
232: while (strings[value] != NULL) {
233: if (strcmp(strings[value], enum_str) == 0) {
234: break;
235: }
236: value++;
237: }
238:
239: if (strings[value] == NULL) {
240: error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null");
1.1.1.2 ! root 241: g_free(enum_str);
1.1 root 242: return;
243: }
244:
1.1.1.2 ! root 245: g_free(enum_str);
1.1 root 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);
1.1.1.2 ! root 275: g_free(v);
1.1 root 276: }
277:
278: QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
279: {
280: QmpInputVisitor *v;
281:
1.1.1.2 ! root 282: v = g_malloc0(sizeof(*v));
1.1 root 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.