2 * QEMU Marshalling Framework
5 * Copyright IBM, Corp. 2010
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.
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
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.
46 bool features
[MAX_FEATURES
];
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
)
65 } while (n
&& n
->type
!= XML_ELEMENT_NODE
);
69 static xmlNode
*first_node(xmlNode
*n
)
71 while (n
&& n
->type
!= XML_ELEMENT_NODE
) {
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
);
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
);
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
);
101 content
= xmlNodeGetContent(xm
->node
);
103 ret
= sscanf(CSTR(content
), "%" PRIu64
, v
);
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
);
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
);
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
);
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
);
135 content
= xmlNodeGetContent(xm
->node
);
137 ret
= sscanf(CSTR(content
), "%" PRId64
, v
);
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
);
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
)
155 if (check_disabled(m
)) {
159 xml_m_uint(m
, &value
, "uint8", n
, errp
);
160 if (!error_is_set(errp
)) {
165 static void xml_m_uint16(Marshaller
*m
, uint16_t *v
, const char *n
, Error
**errp
)
169 if (check_disabled(m
)) {
173 xml_m_uint(m
, &value
, "uint16", n
, errp
);
174 if (!error_is_set(errp
)) {
179 static void xml_m_uint32(Marshaller
*m
, uint32_t *v
, const char *n
, Error
**errp
)
183 if (check_disabled(m
)) {
187 xml_m_uint(m
, &value
, "uint32", n
, errp
);
188 if (!error_is_set(errp
)) {
193 static void xml_m_uint64(Marshaller
*m
, uint64_t *v
, const char *n
, Error
**errp
)
195 if (check_disabled(m
)) {
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
)
206 if (check_disabled(m
)) {
210 xml_m_int(m
, &value
, "int8", n
, errp
);
211 if (!error_is_set(errp
)) {
216 static void xml_m_int16(Marshaller
*m
, int16_t *v
, const char *n
, Error
**errp
)
220 if (check_disabled(m
)) {
224 xml_m_int(m
, &value
, "int16", n
, errp
);
225 if (!error_is_set(errp
)) {
230 static void xml_m_int32(Marshaller
*m
, int32_t *v
, const char *n
, Error
**errp
)
234 if (check_disabled(m
)) {
238 xml_m_int(m
, &value
, "int32", n
, errp
);
239 if (!error_is_set(errp
)) {
244 static void xml_m_int64(Marshaller
*m
, int64_t *v
, const char *n
, Error
**errp
)
246 if (check_disabled(m
)) {
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
);
259 if (check_disabled(m
)) {
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
);
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
);
275 content
= xmlNodeGetContent(xm
->node
);
277 ret
= sscanf(CSTR(content
), "%lf", v
);
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
);
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
);
296 if (check_disabled(m
)) {
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
);
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
);
312 content
= xmlNodeGetContent(xm
->node
);
314 if (strequals(CSTR(content
), "true")) {
316 } else if (strequals(CSTR(content
), "false")) {
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
);
328 error_set(errp
, "xml-reader", 0,
329 "Failed to parse type `%s' node `%s' on line %d",
330 "bool", n
, xm
->node
->line
);
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
)
343 v
= xmlGetProp(node
, (xmlChar
*)p
);
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
);
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
);
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
)) {
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
);
375 confirm_prop(xm
->node
, t
, n
, "type", errp
);
376 if (error_is_set(errp
)) {
380 confirm_prop(xm
->node
, n
, n
, "name", errp
);
381 if (error_is_set(errp
)) {
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
)) {
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
);
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
)) {
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
);
426 confirm_prop(xm
->node
, n
, n
, "name", errp
);
427 if (error_is_set(errp
)) {
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
)) {
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
);
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
)) {
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
);
476 confirm_prop(xm
->node
, n
, n
, "name", errp
);
477 if (error_is_set(errp
)) {
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
);
496 xm
->last_node
= xm
->last_node
->parent
;
497 xm
->node
= next_node(xm
->last_node
);
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
)
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
) {
537 root
= xmlDocGetRootElement(xm
->doc
);
539 xm
->node
= first_node(root
->children
);
540 xm
->last_node
= xm
->node
;
545 void xml_reader_close(Marshaller
*m
)
547 XMLReader
*xm
= to_xm(m
);