Get rid of string type and replace with a bool type
[fidl.git] / xml-reader.c
blob200c04eb4a8eb51c08a7555439ad66f825ab9387
1 /*
2 * QEMU Marshalling Framework
3 * XML unmarshaller
5 * Copyright IBM, Corp. 2010
7 * Authors:
8 * Anthony Liguori <aliguori@us.ibm.com>
10 * This work is licensed under the terms of the GNU GPL, version 2. See
11 * the COPYING file in the top-level directory.
14 #include <string.h>
15 #include <inttypes.h>
16 #include <malloc.h>
18 #include <libxml/parser.h>
19 #include <libxml/tree.h>
21 #include "xml-reader.h"
23 #define container_of(obj, type, member) \
24 ((type *)(((char *)obj) - offsetof(type, member)))
26 #define MAX_FEATURES 100
28 typedef struct XMLReader
30 Marshaller m;
31 xmlDoc *doc;
33 /* we use these three values to transverse the XML tree. last_node points
34 * to the last node we visited. We really use this as a backlink to the
35 * parent in the event node == NULL.
37 * There's a special case though where the children of a node is NULL. We
38 * don't have a node that we can point to who's parent is us so we use
39 * no_kids as a hack. We can probably simplify by just storing the parent.
41 xmlNode *last_node;
42 xmlNode *node;
43 int no_kids;
45 int feature;
46 bool features[MAX_FEATURES];
47 } XMLReader;
49 #define CSTR(a) ((const char*)(a))
51 static XMLReader *to_xm(Marshaller *m)
53 return container_of(m, XMLReader, m);
56 static bool strequals(const char *lhs, const char *rhs)
58 return !!(strcmp(lhs, rhs) == 0);
61 static xmlNode *next_node(xmlNode *n)
63 do {
64 n = n->next;
65 } while (n && n->type != XML_ELEMENT_NODE);
66 return n;
69 static xmlNode *first_node(xmlNode *n)
71 while (n && n->type != XML_ELEMENT_NODE) {
72 n = n->next;
74 return n;
77 static bool check_disabled(Marshaller *m)
79 XMLReader *xm = to_xm(m);
80 return !xm->features[xm->feature - 1];
83 static void xml_m_uint(Marshaller *m, uint64_t *v, const char *t, const char *n, Error **errp)
85 XMLReader *xm = to_xm(m);
86 xmlChar *content;
87 int ret;
89 if (xm->node == NULL) {
90 error_set(errp, "xml-reader", 0,
91 "Unexpected end of section looking for `%s' node `%s' on line %d",
92 t, n, xm->last_node->line);
93 return;
95 if (!strequals(CSTR(xm->node->name), t)) {
96 error_set(errp, "xml-reader", 0,
97 "Expecting node type `%s', got `%s' while parsing `%s' on line %d",
98 t, CSTR(xm->node->name), n, xm->node->line);
99 return;
101 content = xmlNodeGetContent(xm->node);
102 if (content) {
103 ret = sscanf(CSTR(content), "%" PRIu64, v);
104 xmlFree(content);
106 if (!content || ret != 1) {
107 error_set(errp, "xml-reader", 0,
108 "Failed to parse type `%s' node `%s' on line %d",
109 t, n, xm->node->line);
110 return;
113 xm->last_node = xm->node;
114 xm->node = next_node(xm->node);
117 static void xml_m_int(Marshaller *m, int64_t *v, const char *t, const char *n, Error **errp)
119 XMLReader *xm = to_xm(m);
120 xmlChar *content;
121 int ret;
123 if (xm->node == NULL) {
124 error_set(errp, "xml-reader", 0,
125 "Unexpected end of section looking for `%s' node `%s' on line %d",
126 t, n, xm->last_node->line);
127 return;
129 if (!strequals(CSTR(xm->node->name), t)) {
130 error_set(errp, "xml-reader", 0,
131 "Expecting node type `%s', got `%s' while parsing `%s' on line %d",
132 t, CSTR(xm->node->name), n, xm->node->line);
133 return;
135 content = xmlNodeGetContent(xm->node);
136 if (content) {
137 ret = sscanf(CSTR(content), "%" PRId64, v);
138 xmlFree(content);
140 if (!content || ret != 1) {
141 error_set(errp, "xml-reader", 0,
142 "Failed to parse type `%s' node `%s' on line %d",
143 t, n, xm->node->line);
144 return;
147 xm->last_node = xm->node;
148 xm->node = next_node(xm->node);
151 static void xml_m_uint8(Marshaller *m, uint8_t *v, const char *n, Error **errp)
153 uint64_t value;
155 if (check_disabled(m)) {
156 return;
159 xml_m_uint(m, &value, "uint8", n, errp);
160 if (!error_is_set(errp)) {
161 *v = value;
165 static void xml_m_uint16(Marshaller *m, uint16_t *v, const char *n, Error **errp)
167 uint64_t value;
169 if (check_disabled(m)) {
170 return;
173 xml_m_uint(m, &value, "uint16", n, errp);
174 if (!error_is_set(errp)) {
175 *v = value;
179 static void xml_m_uint32(Marshaller *m, uint32_t *v, const char *n, Error **errp)
181 uint64_t value;
183 if (check_disabled(m)) {
184 return;
187 xml_m_uint(m, &value, "uint32", n, errp);
188 if (!error_is_set(errp)) {
189 *v = value;
193 static void xml_m_uint64(Marshaller *m, uint64_t *v, const char *n, Error **errp)
195 if (check_disabled(m)) {
196 return;
199 xml_m_uint(m, v, "uint64", n, errp);
202 static void xml_m_int8(Marshaller *m, int8_t *v, const char *n, Error **errp)
204 int64_t value;
206 if (check_disabled(m)) {
207 return;
210 xml_m_int(m, &value, "int8", n, errp);
211 if (!error_is_set(errp)) {
212 *v = value;
216 static void xml_m_int16(Marshaller *m, int16_t *v, const char *n, Error **errp)
218 int64_t value;
220 if (check_disabled(m)) {
221 return;
224 xml_m_int(m, &value, "int16", n, errp);
225 if (!error_is_set(errp)) {
226 *v = value;
230 static void xml_m_int32(Marshaller *m, int32_t *v, const char *n, Error **errp)
232 int64_t value;
234 if (check_disabled(m)) {
235 return;
238 xml_m_int(m, &value, "int32", n, errp);
239 if (!error_is_set(errp)) {
240 *v = value;
244 static void xml_m_int64(Marshaller *m, int64_t *v, const char *n, Error **errp)
246 if (check_disabled(m)) {
247 return;
250 xml_m_int(m, v, "int64", n, errp);
253 static void xml_m_double(Marshaller *m, double *v, const char *n, Error **errp)
255 XMLReader *xm = to_xm(m);
256 xmlChar *content;
257 int ret;
259 if (check_disabled(m)) {
260 return;
263 if (xm->node == NULL) {
264 error_set(errp, "xml-reader", 0,
265 "Unexpected end of section looking for `%s' node `%s' on line %d",
266 "double", n, xm->last_node->line);
267 return;
269 if (!strequals(CSTR(xm->node->name), "double")) {
270 error_set(errp, "xml-reader", 0,
271 "Expecting node type `%s', got `%s' while parsing `%s' on line %d",
272 "double", CSTR(xm->node->name), n, xm->node->line);
273 return;
275 content = xmlNodeGetContent(xm->node);
276 if (content) {
277 ret = sscanf(CSTR(content), "%lf", v);
278 xmlFree(content);
280 if (!content || ret != 1) {
281 error_set(errp, "xml-reader", 0,
282 "Failed to parse type `%s' node `%s' on line %d",
283 "double", n, xm->node->line);
284 return;
287 xm->last_node = xm->node;
288 xm->node = next_node(xm->node);
291 static void xml_m_bool(Marshaller *m, bool *v, const char *n, Error **errp)
293 XMLReader *xm = to_xm(m);
294 xmlChar *content;
296 if (check_disabled(m)) {
297 return;
300 if (xm->node == NULL) {
301 error_set(errp, "xml-reader", 0,
302 "Unexpected end of section looking for `%s' node `%s' on line %d",
303 "double", n, xm->last_node->line);
304 return;
306 if (!strequals(CSTR(xm->node->name), "bool")) {
307 error_set(errp, "xml-reader", 0,
308 "Expecting node type `%s', got `%s' while parsing `%s' on line %d",
309 "bool", CSTR(xm->node->name), n, xm->node->line);
310 return;
312 content = xmlNodeGetContent(xm->node);
313 if (content) {
314 if (strequals(CSTR(content), "true")) {
315 *v = true;
316 } else if (strequals(CSTR(content), "false")) {
317 *v = false;
318 } else {
319 error_set(errp, "xml-reader", 0,
320 "Invalid value for node type `%s', got `%s', expecting `true' or 'false' on line %d",
321 "bool", content, xm->node->line);
322 xmlFree(content);
323 return;
325 xmlFree(content);
327 if (!content) {
328 error_set(errp, "xml-reader", 0,
329 "Failed to parse type `%s' node `%s' on line %d",
330 "bool", n, xm->node->line);
331 return;
334 xm->last_node = xm->node;
335 xm->node = next_node(xm->node);
338 static void confirm_prop(xmlNode *node, const char *t, const char *n, const char *p, Error **errp)
340 xmlChar *v;
342 if (t) {
343 v = xmlGetProp(node, (xmlChar *)p);
344 if (!v) {
345 error_set(errp, "xml-reader", 0,
346 "Missing attribute `%s' in `%s' node `%s' on line %d",
347 p, CSTR(node->name), n, node->line);
348 return;
350 if (!strequals(CSTR(v), t)) {
351 error_set(errp, "xml-reader", 0,
352 "Expecting attribute `%s' value of `%s' for `%s' node `%s', got `%s' on line %d",
353 p, t, CSTR(node->name), n, CSTR(v), node->line);
354 xmlFree(v);
355 return;
357 xmlFree(v);
361 static void xml_start_struct(Marshaller *m, const char *t, const char *n, Error **errp)
363 XMLReader *xm = to_xm(m);
365 if (check_disabled(m)) {
366 return;
369 if (!strequals(CSTR(xm->node->name), "struct")) {
370 error_set(errp, "xml-reader", 0, "Expecting node `%s', got `%s' on line %d",
371 CSTR(xm->node->name), n, xm->node->line);
372 return;
375 confirm_prop(xm->node, t, n, "type", errp);
376 if (error_is_set(errp)) {
377 return;
380 confirm_prop(xm->node, n, n, "name", errp);
381 if (error_is_set(errp)) {
382 return;
385 xm->last_node = xm->node;
386 xm->node = first_node(xm->node->children);
387 xm->no_kids = !!(xm->node == NULL);
390 static void xml_end_struct(Marshaller *m, Error **errp)
392 XMLReader *xm = to_xm(m);
394 if (check_disabled(m)) {
395 return;
398 if (xm->node != NULL) {
399 error_set(errp, "xml-reader", 0, "Extra nodes at end of `%s' on line %d",
400 "struct", xm->node->line);
401 return;
404 if (xm->no_kids) {
405 xm->no_kids = 0;
406 } else {
407 xm->last_node = xm->last_node->parent;
409 xm->node = next_node(xm->last_node);
412 static void xml_start_array(Marshaller *m, const char *n, Error **errp)
414 XMLReader *xm = to_xm(m);
416 if (check_disabled(m)) {
417 return;
420 if (!strequals(CSTR(xm->node->name), "array")) {
421 error_set(errp, "xml-reader", 0, "Expecting node `%s', got `%s' on line %d",
422 CSTR(xm->node->name), n, xm->node->line);
423 return;
426 confirm_prop(xm->node, n, n, "name", errp);
427 if (error_is_set(errp)) {
428 return;
431 xm->last_node = xm->node;
432 xm->node = first_node(xm->node->children);
433 xm->no_kids = !!(xm->node == NULL);
436 static void xml_end_array(Marshaller *m, Error **errp)
438 XMLReader *xm = to_xm(m);
440 if (check_disabled(m)) {
441 return;
444 if (xm->node != NULL) {
445 error_set(errp, "xml-reader", 0, "Extra nodes at end of `%s' on line %d",
446 "array", xm->node->line);
447 return;
450 if (xm->no_kids) {
451 xm->no_kids = 0;
452 } else {
453 xm->last_node = xm->last_node->parent;
455 xm->node = next_node(xm->last_node);
458 static void xml_start_feature(Marshaller *m, bool *v, const char *n, Error **errp)
460 XMLReader *xm = to_xm(m);
461 bool previous_feature;
463 previous_feature = xm->features[xm->feature - 1];
464 xm->features[xm->feature++] = previous_feature && *v;
466 if (check_disabled(m)) {
467 return;
470 if (!strequals(CSTR(xm->node->name), "feature")) {
471 error_set(errp, "xml-reader", 0, "Expecting node `%s', got `%s' on line %d",
472 "feature", CSTR(xm->node->name), xm->node->line);
473 return;
476 confirm_prop(xm->node, n, n, "name", errp);
477 if (error_is_set(errp)) {
478 return;
481 xm->last_node = xm->node;
482 xm->node = first_node(xm->node->children);
485 static void xml_end_feature(Marshaller *m, Error **errp)
487 XMLReader *xm = to_xm(m);
489 if (!check_disabled(m)) {
490 if (xm->node != NULL) {
491 error_set(errp, "xml-reader", 0, "Extra nodes at end of `%s' on line %d",
492 "feature", xm->node->line);
493 return;
496 xm->last_node = xm->last_node->parent;
497 xm->node = next_node(xm->last_node);
499 xm->feature--;
502 static MarshallerOps xml_reader_ops = {
503 .m_uint8 = xml_m_uint8,
504 .m_uint16 = xml_m_uint16,
505 .m_uint32 = xml_m_uint32,
506 .m_uint64 = xml_m_uint64,
507 .m_int8 = xml_m_int8,
508 .m_int16 = xml_m_int16,
509 .m_int32 = xml_m_int32,
510 .m_int64 = xml_m_int64,
511 .m_double = xml_m_double,
512 .m_bool = xml_m_bool,
513 .start_struct = xml_start_struct,
514 .end_struct = xml_end_struct,
515 .start_array = xml_start_array,
516 .end_array = xml_end_array,
517 .start_feature = xml_start_feature,
518 .end_feature = xml_end_feature,
521 Marshaller *xml_reader_open(FILE *filep)
523 XMLReader *xm;
524 xmlNode *root;
526 xm = malloc(sizeof(*xm));
527 memset(xm, 0, sizeof(*xm));
529 xm->m.ops = &xml_reader_ops;
530 xm->features[xm->feature++] = true;
532 xm->doc = xmlReadFd(fileno(filep), "anonymous.xml", NULL, 0);
533 if (xm->doc == NULL) {
534 return NULL;
537 root = xmlDocGetRootElement(xm->doc);
539 xm->node = first_node(root->children);
540 xm->last_node = xm->node;
542 return &xm->m;
545 void xml_reader_close(Marshaller *m)
547 XMLReader *xm = to_xm(m);
549 xmlFreeDoc(xm->doc);
550 xmlCleanupParser();
551 free(xm);