1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-gparser.c parse DBus description files
3 *
4 * Copyright (C) 2003, 2005 Red Hat, Inc.
5 *
6 * SPDX-License-Identifier: AFL-2.1 OR GPL-2.0-or-later
7 *
8 * Licensed under the Academic Free License version 2.1
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 *
24 */
25
26 #include <config.h>
27
28 #include "dbus-gparser.h"
29 #include "dbus/dbus-glib-lowlevel.h"
30 #include "dbus-gidl.h"
31 #include "dbus-gobject.h"
32 #include "dbus/dbus-signature.h"
33 #include <string.h>
34
35 #include <gio/gio.h>
36
37 #define ELEMENT_IS(name) (strcmp (element_name, (name)) == 0)
38
39 typedef struct
40 {
41 const char *name;
42 const char **retloc;
43 } LocateAttr;
44
45 static gboolean
locate_attributes(const char * element_name,const char ** attribute_names,const char ** attribute_values,GError ** error,const char * first_attribute_name,const char ** first_attribute_retloc,...)46 locate_attributes (const char *element_name,
47 const char **attribute_names,
48 const char **attribute_values,
49 GError **error,
50 const char *first_attribute_name,
51 const char **first_attribute_retloc,
52 ...)
53 {
54 va_list args;
55 const char *name;
56 const char **retloc;
57 int n_attrs;
58 #define MAX_ATTRS 24
59 LocateAttr attrs[MAX_ATTRS];
60 gboolean retval;
61 int i;
62
63 g_return_val_if_fail (first_attribute_name != NULL, FALSE);
64 g_return_val_if_fail (first_attribute_retloc != NULL, FALSE);
65
66 retval = TRUE;
67
68 n_attrs = 1;
69 attrs[0].name = first_attribute_name;
70 attrs[0].retloc = first_attribute_retloc;
71 *first_attribute_retloc = NULL;
72
73 va_start (args, first_attribute_retloc);
74
75 name = va_arg (args, const char*);
76 retloc = va_arg (args, const char**);
77
78 while (name != NULL)
79 {
80 if (retloc == NULL)
81 {
82 va_end (args);
83 return FALSE;
84 }
85
86 g_assert (n_attrs < MAX_ATTRS);
87
88 attrs[n_attrs].name = name;
89 attrs[n_attrs].retloc = retloc;
90 n_attrs += 1;
91 *retloc = NULL;
92
93 name = va_arg (args, const char*);
94 retloc = va_arg (args, const char**);
95 }
96
97 va_end (args);
98
99 i = 0;
100 while (attribute_names[i])
101 {
102 int j;
103 gboolean found;
104
105 found = FALSE;
106 j = 0;
107 while (j < n_attrs)
108 {
109 if (strcmp (attrs[j].name, attribute_names[i]) == 0)
110 {
111 retloc = attrs[j].retloc;
112
113 if (*retloc != NULL)
114 {
115 g_set_error (error,
116 G_MARKUP_ERROR,
117 G_MARKUP_ERROR_PARSE,
118 "Attribute \"%s\" repeated twice on the same <%s> element",
119 attrs[j].name, element_name);
120 retval = FALSE;
121 goto out;
122 }
123
124 *retloc = attribute_values[i];
125 found = TRUE;
126 }
127
128 ++j;
129 }
130
131 if (!found)
132 {
133 /* We want to passthrough namespaced XML nodes that we don't know anything about. */
134 if (strchr (attribute_names[i], ':') == NULL)
135 {
136 g_set_error (error,
137 G_MARKUP_ERROR,
138 G_MARKUP_ERROR_PARSE,
139 "Attribute \"%s\" is invalid on <%s> element in this context",
140 attribute_names[i], element_name);
141 retval = FALSE;
142 goto out;
143 }
144 }
145
146 ++i;
147 }
148
149 out:
150 return retval;
151 }
152
153 #if 0
154 static gboolean
155 check_no_attributes (const char *element_name,
156 const char **attribute_names,
157 const char **attribute_values,
158 GError **error)
159 {
160 if (attribute_names[0] != NULL)
161 {
162 g_set_error (error,
163 G_MARKUP_ERROR,
164 G_MARKUP_ERROR_PARSE,
165 "Attribute \"%s\" is invalid on <%s> element in this context",
166 attribute_names[0], element_name);
167 return FALSE;
168 }
169
170 return TRUE;
171 }
172 #endif
173
174 struct Parser
175 {
176 int refcount;
177
178 NodeInfo *result; /* Filled in when we pop the last node */
179 GSList *node_stack;
180 InterfaceInfo *interface;
181 MethodInfo *method;
182 SignalInfo *signal;
183 PropertyInfo *property;
184 ArgInfo *arg;
185 gboolean in_annotation;
186 guint unknown_namespaced_depth;
187 };
188
189 Parser*
parser_new(void)190 parser_new (void)
191 {
192 Parser *parser;
193
194 parser = g_new0 (Parser, 1);
195
196 parser->refcount = 1;
197
198 return parser;
199 }
200
201 Parser *
parser_ref(Parser * parser)202 parser_ref (Parser *parser)
203 {
204 parser->refcount += 1;
205
206 return parser;
207 }
208
209 void
parser_unref(Parser * parser)210 parser_unref (Parser *parser)
211 {
212 parser->refcount -= 1;
213 if (parser->refcount == 0)
214 {
215 if (parser->result)
216 node_info_unref (parser->result);
217
218 g_free (parser);
219 }
220 }
221
222 gboolean
parser_check_doctype(Parser * parser,const char * doctype,GError ** error)223 parser_check_doctype (Parser *parser,
224 const char *doctype,
225 GError **error)
226 {
227 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
228
229 if (strcmp (doctype, "node") != 0)
230 {
231 g_set_error (error,
232 G_MARKUP_ERROR,
233 G_MARKUP_ERROR_PARSE,
234 "D-BUS description file has the wrong document type %s, use node or interface",
235 doctype);
236 return FALSE;
237 }
238 else
239 return TRUE;
240 }
241
242 static gboolean
parse_node(Parser * parser,const char * element_name,const char ** attribute_names,const char ** attribute_values,GError ** error)243 parse_node (Parser *parser,
244 const char *element_name,
245 const char **attribute_names,
246 const char **attribute_values,
247 GError **error)
248 {
249 const char *name;
250 NodeInfo *node;
251
252 if (parser->interface ||
253 parser->method ||
254 parser->signal ||
255 parser->property ||
256 parser->arg ||
257 parser->in_annotation)
258 {
259 g_set_error (error, G_MARKUP_ERROR,
260 G_MARKUP_ERROR_PARSE,
261 "Can't put <%s> element here",
262 element_name);
263 return FALSE;
264 }
265
266 name = NULL;
267 if (!locate_attributes (element_name, attribute_names,
268 attribute_values, error,
269 "name", &name,
270 NULL))
271 return FALSE;
272
273 /* Only the root node can have no name */
274 if (parser->node_stack != NULL && name == NULL)
275 {
276 g_set_error (error, G_MARKUP_ERROR,
277 G_MARKUP_ERROR_PARSE,
278 "\"%s\" attribute required on <%s> element ",
279 "name", element_name);
280 return FALSE;
281 }
282
283 /* Root element name must be absolute */
284 if (parser->node_stack == NULL && name && *name != '/')
285 {
286 g_set_error (error, G_MARKUP_ERROR,
287 G_MARKUP_ERROR_PARSE,
288 "\"%s\" attribute on <%s> element must be an absolute object path, \"%s\" not OK",
289 "name", element_name, name);
290 return FALSE;
291 }
292
293 /* Other element names must not be absolute */
294 if (parser->node_stack != NULL && name && *name == '/')
295 {
296 g_set_error (error, G_MARKUP_ERROR,
297 G_MARKUP_ERROR_PARSE,
298 "\"%s\" attribute on <%s> element must not be an absolute object path, \"%s\" starts with /",
299 "name", element_name, name);
300 return FALSE;
301 }
302
303 node = node_info_new (name);
304
305 if (parser->node_stack != NULL)
306 {
307 node_info_add_node (parser->node_stack->data,
308 node);
309 }
310
311 parser->node_stack = g_slist_prepend (parser->node_stack,
312 node);
313
314 return TRUE;
315 }
316
317 static gboolean
parse_interface(Parser * parser,const char * element_name,const char ** attribute_names,const char ** attribute_values,GError ** error)318 parse_interface (Parser *parser,
319 const char *element_name,
320 const char **attribute_names,
321 const char **attribute_values,
322 GError **error)
323 {
324 const char *name;
325 InterfaceInfo *iface;
326 NodeInfo *top;
327
328 if (parser->interface ||
329 parser->method ||
330 parser->signal ||
331 parser->property ||
332 parser->arg ||
333 parser->in_annotation ||
334 (parser->node_stack == NULL))
335 {
336 g_set_error (error, G_MARKUP_ERROR,
337 G_MARKUP_ERROR_PARSE,
338 "Can't put <%s> element here",
339 element_name);
340 return FALSE;
341 }
342
343 name = NULL;
344 if (!locate_attributes (element_name, attribute_names,
345 attribute_values, error,
346 "name", &name,
347 NULL))
348 return FALSE;
349
350 if (name == NULL)
351 {
352 g_set_error (error, G_MARKUP_ERROR,
353 G_MARKUP_ERROR_PARSE,
354 "\"%s\" attribute required on <%s> element ",
355 "name", element_name);
356 return FALSE;
357 }
358
359 if (!g_dbus_is_interface_name (name))
360 {
361 g_set_error (error, G_MARKUP_ERROR,
362 G_MARKUP_ERROR_PARSE,
363 "\"%s\" is not a valid D-Bus interface name", name);
364 return FALSE;
365 }
366
367 top = parser->node_stack->data;
368
369 iface = interface_info_new (name);
370 node_info_add_interface (top, iface);
371 interface_info_unref (iface);
372
373 parser->interface = iface;
374
375 return TRUE;
376 }
377
378 static gboolean
parse_method(Parser * parser,const char * element_name,const char ** attribute_names,const char ** attribute_values,GError ** error)379 parse_method (Parser *parser,
380 const char *element_name,
381 const char **attribute_names,
382 const char **attribute_values,
383 GError **error)
384 {
385 const char *name;
386 MethodInfo *method;
387
388 if (parser->interface == NULL ||
389 parser->node_stack == NULL ||
390 parser->method ||
391 parser->signal ||
392 parser->property ||
393 parser->in_annotation ||
394 parser->arg)
395 {
396 g_set_error (error, G_MARKUP_ERROR,
397 G_MARKUP_ERROR_PARSE,
398 "Can't put <%s> element here",
399 element_name);
400 return FALSE;
401 }
402
403 name = NULL;
404 if (!locate_attributes (element_name, attribute_names,
405 attribute_values, error,
406 "name", &name,
407 NULL))
408 return FALSE;
409
410 if (name == NULL)
411 {
412 g_set_error (error, G_MARKUP_ERROR,
413 G_MARKUP_ERROR_PARSE,
414 "\"%s\" attribute required on <%s> element ",
415 "name", element_name);
416 return FALSE;
417 }
418
419 if (!g_dbus_is_member_name (name))
420 {
421 g_set_error (error, G_MARKUP_ERROR,
422 G_MARKUP_ERROR_PARSE,
423 "\"%s\" is not a valid D-Bus member name", name);
424 return FALSE;
425 }
426
427 method = method_info_new (name);
428 interface_info_add_method (parser->interface, method);
429 method_info_unref (method);
430
431 parser->method = method;
432
433 return TRUE;
434 }
435
436 static gboolean
parse_signal(Parser * parser,const char * element_name,const char ** attribute_names,const char ** attribute_values,GError ** error)437 parse_signal (Parser *parser,
438 const char *element_name,
439 const char **attribute_names,
440 const char **attribute_values,
441 GError **error)
442 {
443 const char *name;
444 SignalInfo *signal;
445
446 if (parser->interface == NULL ||
447 parser->node_stack == NULL ||
448 parser->signal ||
449 parser->method ||
450 parser->property ||
451 parser->in_annotation ||
452 parser->arg)
453 {
454 g_set_error (error, G_MARKUP_ERROR,
455 G_MARKUP_ERROR_PARSE,
456 "Can't put <%s> element here",
457 element_name);
458 return FALSE;
459 }
460
461 name = NULL;
462 if (!locate_attributes (element_name, attribute_names,
463 attribute_values, error,
464 "name", &name,
465 NULL))
466 return FALSE;
467
468 if (name == NULL)
469 {
470 g_set_error (error, G_MARKUP_ERROR,
471 G_MARKUP_ERROR_PARSE,
472 "\"%s\" attribute required on <%s> element ",
473 "name", element_name);
474 return FALSE;
475 }
476
477 if (!g_dbus_is_member_name (name))
478 {
479 g_set_error (error, G_MARKUP_ERROR,
480 G_MARKUP_ERROR_PARSE,
481 "\"%s\" is not a valid D-Bus member name", name);
482 return FALSE;
483 }
484
485 signal = signal_info_new (name);
486 interface_info_add_signal (parser->interface, signal);
487 signal_info_unref (signal);
488
489 parser->signal = signal;
490
491 return TRUE;
492 }
493
494 static gboolean
validate_signature(const char * str,const char * element_name,GError ** error)495 validate_signature (const char *str,
496 const char *element_name,
497 GError **error)
498 {
499 DBusError derror;
500
501 dbus_error_init (&derror);
502
503 if (!dbus_signature_validate (str, &derror))
504 {
505 dbus_set_g_error (error, &derror);
506 return FALSE;
507 }
508 return TRUE;
509 }
510
511 static gboolean
parse_property(Parser * parser,const char * element_name,const char ** attribute_names,const char ** attribute_values,GError ** error)512 parse_property (Parser *parser,
513 const char *element_name,
514 const char **attribute_names,
515 const char **attribute_values,
516 GError **error)
517 {
518 const char *name;
519 const char *access;
520 const char *type;
521 PropertyInfo *property;
522 PropertyAccessFlags access_flags;
523
524 if (parser->interface == NULL ||
525 parser->node_stack == NULL ||
526 parser->signal ||
527 parser->method ||
528 parser->property ||
529 parser->in_annotation ||
530 parser->arg)
531 {
532 g_set_error (error, G_MARKUP_ERROR,
533 G_MARKUP_ERROR_PARSE,
534 "Can't put <%s> element here",
535 element_name);
536 return FALSE;
537 }
538
539 name = NULL;
540 if (!locate_attributes (element_name, attribute_names,
541 attribute_values, error,
542 "name", &name,
543 "access", &access,
544 "type", &type,
545 NULL))
546 return FALSE;
547
548 if (name == NULL)
549 {
550 g_set_error (error, G_MARKUP_ERROR,
551 G_MARKUP_ERROR_PARSE,
552 "\"%s\" attribute required on <%s> element ",
553 "name", element_name);
554 return FALSE;
555 }
556
557 if (access == NULL)
558 {
559 g_set_error (error, G_MARKUP_ERROR,
560 G_MARKUP_ERROR_PARSE,
561 "\"%s\" attribute required on <%s> element ",
562 "access", element_name);
563 return FALSE;
564 }
565
566 if (type == NULL)
567 {
568 g_set_error (error, G_MARKUP_ERROR,
569 G_MARKUP_ERROR_PARSE,
570 "\"%s\" attribute required on <%s> element ",
571 "type", element_name);
572 return FALSE;
573 }
574
575 if (!validate_signature (type, element_name, error))
576 return FALSE;
577
578 access_flags = 0;
579 if (strcmp (access, "readwrite") == 0)
580 access_flags = PROPERTY_READ | PROPERTY_WRITE;
581 else if (strcmp (access, "read") == 0)
582 access_flags = PROPERTY_READ;
583 else if (strcmp (access, "write") == 0)
584 access_flags = PROPERTY_WRITE;
585 else
586 {
587 g_set_error (error, G_MARKUP_ERROR,
588 G_MARKUP_ERROR_PARSE,
589 "access=\"%s\" must have value readwrite, read, or write on %s\n",
590 access, element_name);
591 return FALSE;
592 }
593
594 if (!g_utf8_validate (name, -1, NULL))
595 {
596 g_set_error (error, G_MARKUP_ERROR,
597 G_MARKUP_ERROR_PARSE,
598 "\"%s\" is not UTF-8", name);
599 return FALSE;
600 }
601
602 property = property_info_new (name, type, access_flags);
603 interface_info_add_property (parser->interface, property);
604 property_info_unref (property);
605
606 parser->property = property;
607
608 return TRUE;
609 }
610
611 static gboolean
parse_arg(Parser * parser,const char * element_name,const char ** attribute_names,const char ** attribute_values,GError ** error)612 parse_arg (Parser *parser,
613 const char *element_name,
614 const char **attribute_names,
615 const char **attribute_values,
616 GError **error)
617 {
618 const char *name;
619 const char *type;
620 const char *direction;
621 ArgDirection dir;
622 ArgInfo *arg;
623 char *generated_name;
624
625 if (!(parser->method || parser->signal) ||
626 parser->node_stack == NULL ||
627 parser->property ||
628 parser->in_annotation ||
629 parser->arg)
630 {
631 g_set_error (error, G_MARKUP_ERROR,
632 G_MARKUP_ERROR_PARSE,
633 "Can't put <%s> element here",
634 element_name);
635 return FALSE;
636 }
637
638 name = NULL;
639 if (!locate_attributes (element_name, attribute_names,
640 attribute_values, error,
641 "name", &name,
642 "type", &type,
643 "direction", &direction,
644 NULL))
645 return FALSE;
646
647 /* name can be null for args */
648
649 if (type == NULL)
650 {
651 g_set_error (error, G_MARKUP_ERROR,
652 G_MARKUP_ERROR_PARSE,
653 "\"%s\" attribute required on <%s> element ",
654 "type", element_name);
655 return FALSE;
656 }
657
658 if (direction == NULL)
659 {
660 /* methods default to in, signal to out */
661 if (parser->method)
662 direction = "in";
663 else if (parser->signal)
664 direction = "out";
665 else
666 g_assert_not_reached ();
667 }
668
669 dir = ARG_INVALID;
670
671 if (strcmp (direction, "in") == 0)
672 dir = ARG_IN;
673 else if (strcmp (direction, "out") == 0)
674 dir = ARG_OUT;
675
676 if (dir == ARG_INVALID ||
677 (parser->signal && dir == ARG_IN))
678 {
679 if (parser->signal)
680 g_set_error (error, G_MARKUP_ERROR,
681 G_MARKUP_ERROR_PARSE,
682 "Signals must have direction=\"out\" (just omit the direction attribute)");
683 else
684 g_set_error (error, G_MARKUP_ERROR,
685 G_MARKUP_ERROR_PARSE,
686 "\"%s\" attribute on <%s> has value \"in\" or \"out\"",
687 "direction", element_name);
688 return FALSE;
689 }
690
691 if (!validate_signature (type, element_name, error))
692 return FALSE;
693
694 generated_name = NULL;
695 if (name == NULL)
696 generated_name = g_strdup_printf ("arg%d",
697 parser->method ?
698 method_info_get_n_args (parser->method) :
699 signal_info_get_n_args (parser->signal));
700
701 arg = arg_info_new (name ? name : generated_name, dir, type);
702 if (parser->method)
703 method_info_add_arg (parser->method, arg);
704 else if (parser->signal)
705 signal_info_add_arg (parser->signal, arg);
706 else
707 g_assert_not_reached ();
708
709 g_free (generated_name);
710
711 arg_info_unref (arg);
712
713 parser->arg = arg;
714
715 return TRUE;
716 }
717
718 static gboolean
parse_annotation(Parser * parser,const char * element_name,const char ** attribute_names,const char ** attribute_values,GError ** error)719 parse_annotation (Parser *parser,
720 const char *element_name,
721 const char **attribute_names,
722 const char **attribute_values,
723 GError **error)
724 {
725 const char *name;
726 const char *value;
727
728 if (!(parser->method || parser->interface || parser->arg ||
729 parser->property || parser->signal) ||
730 parser->node_stack == NULL ||
731 parser->in_annotation)
732 {
733 g_set_error (error, G_MARKUP_ERROR,
734 G_MARKUP_ERROR_PARSE,
735 "Can't put <%s> element here",
736 element_name);
737 return FALSE;
738 }
739
740 name = NULL;
741 if (!locate_attributes (element_name, attribute_names,
742 attribute_values, error,
743 "name", &name,
744 "value", &value,
745 NULL))
746 return FALSE;
747
748 if (name == NULL)
749 {
750 g_set_error (error, G_MARKUP_ERROR,
751 G_MARKUP_ERROR_PARSE,
752 "\"%s\" attribute required on <%s> element ",
753 "name", element_name);
754 return FALSE;
755 }
756 if (value == NULL)
757 {
758 g_set_error (error, G_MARKUP_ERROR,
759 G_MARKUP_ERROR_PARSE,
760 "\"%s\" attribute required on <%s> element ",
761 "value", element_name);
762 return FALSE;
763 }
764
765 if (parser->arg)
766 arg_info_add_annotation (parser->arg, name, value);
767 else if (parser->method)
768 method_info_add_annotation (parser->method, name, value);
769 else if (parser->interface)
770 interface_info_add_annotation (parser->interface, name, value);
771 else
772 g_assert_not_reached ();
773
774 parser->in_annotation = TRUE;
775
776 return TRUE;
777 }
778
779 gboolean
parser_start_element(Parser * parser,const char * element_name,const char ** attribute_names,const char ** attribute_values,GError ** error)780 parser_start_element (Parser *parser,
781 const char *element_name,
782 const char **attribute_names,
783 const char **attribute_values,
784 GError **error)
785 {
786 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
787
788 if (ELEMENT_IS ("node"))
789 {
790 if (!parse_node (parser, element_name, attribute_names,
791 attribute_values, error))
792 return FALSE;
793 }
794 else if (ELEMENT_IS ("interface"))
795 {
796 if (!parse_interface (parser, element_name, attribute_names,
797 attribute_values, error))
798 return FALSE;
799 }
800 else if (ELEMENT_IS ("method"))
801 {
802 if (!parse_method (parser, element_name, attribute_names,
803 attribute_values, error))
804 return FALSE;
805 }
806 else if (ELEMENT_IS ("signal"))
807 {
808 if (!parse_signal (parser, element_name, attribute_names,
809 attribute_values, error))
810 return FALSE;
811 }
812 else if (ELEMENT_IS ("property"))
813 {
814 if (!parse_property (parser, element_name, attribute_names,
815 attribute_values, error))
816 return FALSE;
817 }
818 else if (ELEMENT_IS ("arg"))
819 {
820 if (!parse_arg (parser, element_name, attribute_names,
821 attribute_values, error))
822 return FALSE;
823 }
824 else if (ELEMENT_IS ("annotation"))
825 {
826 if (!parse_annotation (parser, element_name, attribute_names,
827 attribute_values, error))
828 return FALSE;
829 }
830 else
831 {
832 if (strchr (element_name, ':') != NULL)
833 /* Passthrough XML-namespaced nodes */
834 parser->unknown_namespaced_depth += 1;
835 else if (parser->unknown_namespaced_depth == 0)
836 {
837 g_set_error (error, G_MARKUP_ERROR,
838 G_MARKUP_ERROR_PARSE,
839 "Element <%s> not recognized",
840 element_name);
841 return FALSE;
842 }
843 }
844
845 return TRUE;
846 }
847
848 gboolean
parser_end_element(Parser * parser,const char * element_name,GError ** error)849 parser_end_element (Parser *parser,
850 const char *element_name,
851 GError **error)
852 {
853 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
854
855 if (ELEMENT_IS ("interface"))
856 {
857 parser->interface = NULL;
858 }
859 else if (ELEMENT_IS ("method"))
860 {
861 parser->method = NULL;
862 }
863 else if (ELEMENT_IS ("signal"))
864 {
865 parser->signal = NULL;
866 }
867 else if (ELEMENT_IS ("property"))
868 {
869 parser->property = NULL;
870 }
871 else if (ELEMENT_IS ("arg"))
872 {
873 parser->arg = NULL;
874 }
875 else if (ELEMENT_IS ("annotation"))
876 {
877 parser->in_annotation = FALSE;
878 }
879 else if (ELEMENT_IS ("node"))
880 {
881 NodeInfo *top;
882
883 g_assert (parser->node_stack != NULL);
884 top = parser->node_stack->data;
885
886 parser->node_stack = g_slist_remove (parser->node_stack,
887 top);
888
889 if (parser->node_stack == NULL)
890 parser->result = top; /* We are done, store the result */
891 }
892 else if (strchr (element_name, ':') != NULL)
893 {
894 /* Passthrough XML-namespaced nodes */
895 parser->unknown_namespaced_depth -= 1;
896 }
897 else if (parser->unknown_namespaced_depth > 0)
898 {
899 /* pass through unknown elements underneath a namespace */
900 }
901 else
902 g_assert_not_reached (); /* should have had an error on start_element */
903
904 return TRUE;
905 }
906
907 gboolean
parser_content(Parser * parser,const char * content,int len,GError ** error)908 parser_content (Parser *parser,
909 const char *content,
910 int len,
911 GError **error)
912 {
913 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
914
915 /* FIXME check that it's all whitespace */
916
917 return TRUE;
918 }
919
920 gboolean
parser_finished(Parser * parser,GError ** error)921 parser_finished (Parser *parser,
922 GError **error)
923 {
924 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
925
926 return TRUE;
927 }
928
929 NodeInfo*
parser_get_nodes(Parser * parser)930 parser_get_nodes (Parser *parser)
931 {
932 return parser->result;
933 }
934