gkdbus: Fix underflow and unreachable code bug
[platform/upstream/glib.git] / gio / gdbusintrospection.c
1 /* GDBus - GLib D-Bus Library
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
5  * SPDX-License-Identifier: LGPL-2.1-or-later
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General
18  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  *
20  * Author: David Zeuthen <davidz@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "gdbusintrospection.h"
29
30 #include "glibintl.h"
31
32 /**
33  * SECTION:gdbusintrospection
34  * @title: D-Bus Introspection Data
35  * @short_description: Node and interface description data structures
36  * @include: gio/gio.h
37  *
38  * Various data structures and convenience routines to parse and
39  * generate D-Bus introspection XML. Introspection information is
40  * used when registering objects with g_dbus_connection_register_object().
41  *
42  * The format of D-Bus introspection XML is specified in the
43  * [D-Bus specification](http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format)
44  */
45
46 /* ---------------------------------------------------------------------------------------------------- */
47
48 #define _MY_DEFINE_BOXED_TYPE(TypeName, type_name) \
49   G_DEFINE_BOXED_TYPE (TypeName, type_name, type_name##_ref, type_name##_unref)
50
51 _MY_DEFINE_BOXED_TYPE (GDBusNodeInfo,       g_dbus_node_info)
52 _MY_DEFINE_BOXED_TYPE (GDBusInterfaceInfo,  g_dbus_interface_info)
53 _MY_DEFINE_BOXED_TYPE (GDBusMethodInfo,     g_dbus_method_info)
54 _MY_DEFINE_BOXED_TYPE (GDBusSignalInfo,     g_dbus_signal_info)
55 _MY_DEFINE_BOXED_TYPE (GDBusPropertyInfo,   g_dbus_property_info)
56 _MY_DEFINE_BOXED_TYPE (GDBusArgInfo,        g_dbus_arg_info)
57 _MY_DEFINE_BOXED_TYPE (GDBusAnnotationInfo, g_dbus_annotation_info)
58
59 #undef _MY_DEFINE_BOXED_TYPE
60
61 /* ---------------------------------------------------------------------------------------------------- */
62
63 typedef struct
64 {
65   /* stuff we are currently collecting */
66   GPtrArray *args;
67   GPtrArray *out_args;
68   GPtrArray *methods;
69   GPtrArray *signals;
70   GPtrArray *properties;
71   GPtrArray *interfaces;
72   GPtrArray *nodes;
73   GPtrArray *annotations;
74
75   /* A list of GPtrArray's containing annotations */
76   GSList *annotations_stack;
77
78   /* A list of GPtrArray's containing interfaces */
79   GSList *interfaces_stack;
80
81   /* A list of GPtrArray's containing nodes */
82   GSList *nodes_stack;
83
84   /* Whether the direction was "in" for last parsed arg */
85   gboolean last_arg_was_in;
86
87   /* Number of args currently being collected; used for assigning
88    * names to args without a "name" attribute
89    */
90   guint num_args;
91
92 } ParseData;
93
94 /* ---------------------------------------------------------------------------------------------------- */
95
96 /**
97  * g_dbus_node_info_ref:
98  * @info: A #GDBusNodeInfo
99  *
100  * If @info is statically allocated does nothing. Otherwise increases
101  * the reference count.
102  *
103  * Returns: (not nullable): The same @info.
104  *
105  * Since: 2.26
106  */
107 GDBusNodeInfo *
108 g_dbus_node_info_ref (GDBusNodeInfo *info)
109 {
110   if (g_atomic_int_get (&info->ref_count) == -1)
111     return info;
112   g_atomic_int_inc (&info->ref_count);
113   return info;
114 }
115
116 /**
117  * g_dbus_interface_info_ref:
118  * @info: A #GDBusInterfaceInfo
119  *
120  * If @info is statically allocated does nothing. Otherwise increases
121  * the reference count.
122  *
123  * Returns: (not nullable): The same @info.
124  *
125  * Since: 2.26
126  */
127 GDBusInterfaceInfo *
128 g_dbus_interface_info_ref (GDBusInterfaceInfo *info)
129 {
130   if (g_atomic_int_get (&info->ref_count) == -1)
131     return info;
132   g_atomic_int_inc (&info->ref_count);
133   return info;
134 }
135
136 /**
137  * g_dbus_method_info_ref:
138  * @info: A #GDBusMethodInfo
139  *
140  * If @info is statically allocated does nothing. Otherwise increases
141  * the reference count.
142  *
143  * Returns: (not nullable): The same @info.
144  *
145  * Since: 2.26
146  */
147 GDBusMethodInfo *
148 g_dbus_method_info_ref (GDBusMethodInfo *info)
149 {
150   if (g_atomic_int_get (&info->ref_count) == -1)
151     return info;
152   g_atomic_int_inc (&info->ref_count);
153   return info;
154 }
155
156 /**
157  * g_dbus_signal_info_ref:
158  * @info: A #GDBusSignalInfo
159  *
160  * If @info is statically allocated does nothing. Otherwise increases
161  * the reference count.
162  *
163  * Returns: (not nullable): The same @info.
164  *
165  * Since: 2.26
166  */
167 GDBusSignalInfo *
168 g_dbus_signal_info_ref (GDBusSignalInfo *info)
169 {
170   if (g_atomic_int_get (&info->ref_count) == -1)
171     return info;
172   g_atomic_int_inc (&info->ref_count);
173   return info;
174 }
175
176 /**
177  * g_dbus_property_info_ref:
178  * @info: A #GDBusPropertyInfo
179  *
180  * If @info is statically allocated does nothing. Otherwise increases
181  * the reference count.
182  *
183  * Returns: (not nullable): The same @info.
184  *
185  * Since: 2.26
186  */
187 GDBusPropertyInfo *
188 g_dbus_property_info_ref (GDBusPropertyInfo *info)
189 {
190   if (g_atomic_int_get (&info->ref_count) == -1)
191     return info;
192   g_atomic_int_inc (&info->ref_count);
193   return info;
194 }
195
196 /**
197  * g_dbus_arg_info_ref:
198  * @info: A #GDBusArgInfo
199  *
200  * If @info is statically allocated does nothing. Otherwise increases
201  * the reference count.
202  *
203  * Returns: (not nullable): The same @info.
204  *
205  * Since: 2.26
206  */
207 GDBusArgInfo *
208 g_dbus_arg_info_ref (GDBusArgInfo *info)
209 {
210   if (g_atomic_int_get (&info->ref_count) == -1)
211     return info;
212   g_atomic_int_inc (&info->ref_count);
213   return info;
214 }
215
216 /**
217  * g_dbus_annotation_info_ref:
218  * @info: A #GDBusNodeInfo
219  *
220  * If @info is statically allocated does nothing. Otherwise increases
221  * the reference count.
222  *
223  * Returns: (not nullable): The same @info.
224  *
225  * Since: 2.26
226  */
227 GDBusAnnotationInfo *
228 g_dbus_annotation_info_ref (GDBusAnnotationInfo *info)
229 {
230   if (g_atomic_int_get (&info->ref_count) == -1)
231     return info;
232   g_atomic_int_inc (&info->ref_count);
233   return info;
234 }
235
236 /* ---------------------------------------------------------------------------------------------------- */
237
238 static void
239 free_null_terminated_array (gpointer array, GDestroyNotify unref_func)
240 {
241   guint n;
242   gpointer *p = array;
243   if (p == NULL)
244     return;
245   for (n = 0; p[n] != NULL; n++)
246     unref_func (p[n]);
247   g_free (p);
248 }
249
250 /**
251  * g_dbus_annotation_info_unref:
252  * @info: A #GDBusAnnotationInfo.
253  *
254  * If @info is statically allocated, does nothing. Otherwise decreases
255  * the reference count of @info. When its reference count drops to 0,
256  * the memory used is freed.
257  *
258  * Since: 2.26
259  */
260 void
261 g_dbus_annotation_info_unref (GDBusAnnotationInfo *info)
262 {
263   if (g_atomic_int_get (&info->ref_count) == -1)
264     return;
265   if (g_atomic_int_dec_and_test (&info->ref_count))
266     {
267       g_free (info->key);
268       g_free (info->value);
269       free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
270       g_free (info);
271     }
272 }
273
274 /**
275  * g_dbus_arg_info_unref:
276  * @info: A #GDBusArgInfo.
277  *
278  * If @info is statically allocated, does nothing. Otherwise decreases
279  * the reference count of @info. When its reference count drops to 0,
280  * the memory used is freed.
281  *
282  * Since: 2.26
283  */
284 void
285 g_dbus_arg_info_unref (GDBusArgInfo *info)
286 {
287   if (g_atomic_int_get (&info->ref_count) == -1)
288     return;
289   if (g_atomic_int_dec_and_test (&info->ref_count))
290     {
291       g_free (info->name);
292       g_free (info->signature);
293       free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
294       g_free (info);
295     }
296 }
297
298 /**
299  * g_dbus_method_info_unref:
300  * @info: A #GDBusMethodInfo.
301  *
302  * If @info is statically allocated, does nothing. Otherwise decreases
303  * the reference count of @info. When its reference count drops to 0,
304  * the memory used is freed.
305  *
306  * Since: 2.26
307  */
308 void
309 g_dbus_method_info_unref (GDBusMethodInfo *info)
310 {
311   if (g_atomic_int_get (&info->ref_count) == -1)
312     return;
313   if (g_atomic_int_dec_and_test (&info->ref_count))
314     {
315       g_free (info->name);
316       free_null_terminated_array (info->in_args, (GDestroyNotify) g_dbus_arg_info_unref);
317       free_null_terminated_array (info->out_args, (GDestroyNotify) g_dbus_arg_info_unref);
318       free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
319       g_free (info);
320     }
321 }
322
323 /**
324  * g_dbus_signal_info_unref:
325  * @info: A #GDBusSignalInfo.
326  *
327  * If @info is statically allocated, does nothing. Otherwise decreases
328  * the reference count of @info. When its reference count drops to 0,
329  * the memory used is freed.
330  *
331  * Since: 2.26
332  */
333 void
334 g_dbus_signal_info_unref (GDBusSignalInfo *info)
335 {
336   if (g_atomic_int_get (&info->ref_count) == -1)
337     return;
338   if (g_atomic_int_dec_and_test (&info->ref_count))
339     {
340       g_free (info->name);
341       free_null_terminated_array (info->args, (GDestroyNotify) g_dbus_arg_info_unref);
342       free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
343       g_free (info);
344     }
345 }
346
347 /**
348  * g_dbus_property_info_unref:
349  * @info: A #GDBusPropertyInfo.
350  *
351  * If @info is statically allocated, does nothing. Otherwise decreases
352  * the reference count of @info. When its reference count drops to 0,
353  * the memory used is freed.
354  *
355  * Since: 2.26
356  */
357 void
358 g_dbus_property_info_unref (GDBusPropertyInfo *info)
359 {
360   if (g_atomic_int_get (&info->ref_count) == -1)
361     return;
362   if (g_atomic_int_dec_and_test (&info->ref_count))
363     {
364       g_free (info->name);
365       g_free (info->signature);
366       free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
367       g_free (info);
368     }
369 }
370
371 /**
372  * g_dbus_interface_info_unref:
373  * @info: A #GDBusInterfaceInfo.
374  *
375  * If @info is statically allocated, does nothing. Otherwise decreases
376  * the reference count of @info. When its reference count drops to 0,
377  * the memory used is freed.
378  *
379  * Since: 2.26
380  */
381 void
382 g_dbus_interface_info_unref (GDBusInterfaceInfo *info)
383 {
384   if (g_atomic_int_get (&info->ref_count) == -1)
385     return;
386   if (g_atomic_int_dec_and_test (&info->ref_count))
387     {
388       g_free (info->name);
389       free_null_terminated_array (info->methods, (GDestroyNotify) g_dbus_method_info_unref);
390       free_null_terminated_array (info->signals, (GDestroyNotify) g_dbus_signal_info_unref);
391       free_null_terminated_array (info->properties, (GDestroyNotify) g_dbus_property_info_unref);
392       free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
393       g_free (info);
394     }
395 }
396
397 /**
398  * g_dbus_node_info_unref:
399  * @info: A #GDBusNodeInfo.
400  *
401  * If @info is statically allocated, does nothing. Otherwise decreases
402  * the reference count of @info. When its reference count drops to 0,
403  * the memory used is freed.
404  *
405  * Since: 2.26
406  */
407 void
408 g_dbus_node_info_unref (GDBusNodeInfo *info)
409 {
410   if (g_atomic_int_get (&info->ref_count) == -1)
411     return;
412   if (g_atomic_int_dec_and_test (&info->ref_count))
413     {
414       g_free (info->path);
415       free_null_terminated_array (info->interfaces, (GDestroyNotify) g_dbus_interface_info_unref);
416       free_null_terminated_array (info->nodes, (GDestroyNotify) g_dbus_node_info_unref);
417       free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
418       g_free (info);
419     }
420 }
421
422 /* ---------------------------------------------------------------------------------------------------- */
423
424 static void
425 g_dbus_annotation_info_set (ParseData            *data,
426                             GDBusAnnotationInfo  *info,
427                             const gchar          *key,
428                             const gchar          *value,
429                             GDBusAnnotationInfo **embedded_annotations)
430 {
431   info->ref_count = 1;
432
433   if (key != NULL)
434     info->key = g_strdup (key);
435
436   if (value != NULL)
437     info->value = g_strdup (value);
438
439   if (embedded_annotations != NULL)
440     info->annotations = embedded_annotations;
441 }
442
443 static void
444 g_dbus_arg_info_set (ParseData            *data,
445                      GDBusArgInfo         *info,
446                      const gchar          *name,
447                      const gchar          *signature,
448                      GDBusAnnotationInfo **annotations)
449 {
450   info->ref_count = 1;
451
452   /* name may be NULL - TODO: compute name? */
453   if (name != NULL)
454     info->name = g_strdup (name);
455
456   if (signature != NULL)
457     info->signature = g_strdup (signature);
458
459   if (annotations != NULL)
460     info->annotations = annotations;
461 }
462
463 static void
464 g_dbus_method_info_set (ParseData            *data,
465                         GDBusMethodInfo      *info,
466                         const gchar          *name,
467                         GDBusArgInfo        **in_args,
468                         GDBusArgInfo        **out_args,
469                         GDBusAnnotationInfo **annotations)
470 {
471   info->ref_count = 1;
472
473   if (name != NULL)
474     info->name = g_strdup (name);
475
476   if (in_args != NULL)
477     info->in_args = in_args;
478
479   if (out_args != NULL)
480     info->out_args = out_args;
481
482   if (annotations != NULL)
483     info->annotations = annotations;
484 }
485
486 static void
487 g_dbus_signal_info_set (ParseData            *data,
488                         GDBusSignalInfo      *info,
489                         const gchar          *name,
490                         GDBusArgInfo        **args,
491                         GDBusAnnotationInfo **annotations)
492 {
493   info->ref_count = 1;
494
495   if (name != NULL)
496     info->name = g_strdup (name);
497
498   if (args != NULL)
499     info->args = args;
500
501   if (annotations != NULL)
502     info->annotations = annotations;
503 }
504
505 static void
506 g_dbus_property_info_set (ParseData               *data,
507                           GDBusPropertyInfo       *info,
508                           const gchar             *name,
509                           const gchar             *signature,
510                           GDBusPropertyInfoFlags   flags,
511                           GDBusAnnotationInfo    **annotations)
512 {
513   info->ref_count = 1;
514
515   if (name != NULL)
516     info->name = g_strdup (name);
517
518   if (flags != G_DBUS_PROPERTY_INFO_FLAGS_NONE)
519     info->flags = flags;
520
521   if (signature != NULL)
522     info->signature = g_strdup (signature);
523
524   if (annotations != NULL)
525     info->annotations = annotations;
526 }
527
528 static void
529 g_dbus_interface_info_set (ParseData            *data,
530                            GDBusInterfaceInfo   *info,
531                            const gchar          *name,
532                            GDBusMethodInfo     **methods,
533                            GDBusSignalInfo     **signals,
534                            GDBusPropertyInfo   **properties,
535                            GDBusAnnotationInfo **annotations)
536 {
537   info->ref_count = 1;
538
539   if (name != NULL)
540     info->name = g_strdup (name);
541
542   if (methods != NULL)
543     info->methods = methods;
544
545   if (signals != NULL)
546     info->signals = signals;
547
548   if (properties != NULL)
549     info->properties = properties;
550
551   if (annotations != NULL)
552     info->annotations = annotations;
553 }
554
555 static void
556 g_dbus_node_info_set (ParseData            *data,
557                       GDBusNodeInfo        *info,
558                       const gchar          *path,
559                       GDBusInterfaceInfo  **interfaces,
560                       GDBusNodeInfo       **nodes,
561                       GDBusAnnotationInfo **annotations)
562 {
563   info->ref_count = 1;
564
565   if (path != NULL)
566     {
567       info->path = g_strdup (path);
568       /* TODO: relative / absolute path snafu */
569     }
570
571   if (interfaces != NULL)
572     info->interfaces = interfaces;
573
574   if (nodes != NULL)
575     info->nodes = nodes;
576
577   if (annotations != NULL)
578     info->annotations = annotations;
579 }
580
581 /* ---------------------------------------------------------------------------------------------------- */
582
583 static void
584 g_dbus_annotation_info_generate_xml (GDBusAnnotationInfo *info,
585                                      guint                indent,
586                                      GString             *string_builder)
587 {
588   gchar *tmp;
589   guint n;
590
591   tmp = g_markup_printf_escaped ("%*s<annotation name=\"%s\" value=\"%s\"",
592                                  indent, "",
593                                  info->key,
594                                  info->value);
595   g_string_append (string_builder, tmp);
596   g_free (tmp);
597
598   if (info->annotations == NULL)
599     {
600       g_string_append (string_builder, "/>\n");
601     }
602   else
603     {
604       g_string_append (string_builder, ">\n");
605
606       for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
607         g_dbus_annotation_info_generate_xml (info->annotations[n],
608                                              indent + 2,
609                                              string_builder);
610
611       g_string_append_printf (string_builder, "%*s</annotation>\n",
612                               indent, "");
613     }
614
615 }
616
617 static void
618 g_dbus_arg_info_generate_xml (GDBusArgInfo *info,
619                               guint         indent,
620                               const gchar  *extra_attributes,
621                               GString      *string_builder)
622 {
623   guint n;
624
625   g_string_append_printf (string_builder, "%*s<arg type=\"%s\"",
626                           indent, "",
627                           info->signature);
628
629   if (info->name != NULL)
630     g_string_append_printf (string_builder, " name=\"%s\"", info->name);
631
632   if (extra_attributes != NULL)
633     g_string_append_printf (string_builder, " %s", extra_attributes);
634
635   if (info->annotations == NULL)
636     {
637       g_string_append (string_builder, "/>\n");
638     }
639   else
640     {
641       g_string_append (string_builder, ">\n");
642
643       for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
644         g_dbus_annotation_info_generate_xml (info->annotations[n],
645                                              indent + 2,
646                                              string_builder);
647
648       g_string_append_printf (string_builder, "%*s</arg>\n", indent, "");
649     }
650
651 }
652
653 static void
654 g_dbus_method_info_generate_xml (GDBusMethodInfo *info,
655                                  guint            indent,
656                                  GString         *string_builder)
657 {
658   guint n;
659
660   g_string_append_printf (string_builder, "%*s<method name=\"%s\"",
661                           indent, "",
662                           info->name);
663
664   if (info->annotations == NULL && info->in_args == NULL && info->out_args == NULL)
665     {
666       g_string_append (string_builder, "/>\n");
667     }
668   else
669     {
670       g_string_append (string_builder, ">\n");
671
672       for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
673         g_dbus_annotation_info_generate_xml (info->annotations[n],
674                                              indent + 2,
675                                              string_builder);
676
677       for (n = 0; info->in_args != NULL && info->in_args[n] != NULL; n++)
678         g_dbus_arg_info_generate_xml (info->in_args[n],
679                                       indent + 2,
680                                       "direction=\"in\"",
681                                       string_builder);
682
683       for (n = 0; info->out_args != NULL && info->out_args[n] != NULL; n++)
684         g_dbus_arg_info_generate_xml (info->out_args[n],
685                                       indent + 2,
686                                       "direction=\"out\"",
687                                       string_builder);
688
689       g_string_append_printf (string_builder, "%*s</method>\n", indent, "");
690     }
691 }
692
693 static void
694 g_dbus_signal_info_generate_xml (GDBusSignalInfo *info,
695                                  guint            indent,
696                                  GString         *string_builder)
697 {
698   guint n;
699
700   g_string_append_printf (string_builder, "%*s<signal name=\"%s\"",
701                           indent, "",
702                           info->name);
703
704   if (info->annotations == NULL && info->args == NULL)
705     {
706       g_string_append (string_builder, "/>\n");
707     }
708   else
709     {
710       g_string_append (string_builder, ">\n");
711
712       for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
713         g_dbus_annotation_info_generate_xml (info->annotations[n],
714                                              indent + 2,
715                                              string_builder);
716
717       for (n = 0; info->args != NULL && info->args[n] != NULL; n++)
718         g_dbus_arg_info_generate_xml (info->args[n],
719                                       indent + 2,
720                                       NULL,
721                                       string_builder);
722
723       g_string_append_printf (string_builder, "%*s</signal>\n", indent, "");
724     }
725 }
726
727 static void
728 g_dbus_property_info_generate_xml (GDBusPropertyInfo *info,
729                                    guint              indent,
730                                    GString           *string_builder)
731 {
732   guint n;
733   const gchar *access_string;
734
735   if ((info->flags & G_DBUS_PROPERTY_INFO_FLAGS_READABLE) &&
736       (info->flags & G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE))
737     {
738       access_string = "readwrite";
739     }
740   else if (info->flags & G_DBUS_PROPERTY_INFO_FLAGS_READABLE)
741     {
742       access_string = "read";
743     }
744   else if (info->flags & G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE)
745     {
746       access_string = "write";
747     }
748   else
749     {
750       g_assert_not_reached ();
751     }
752
753   g_string_append_printf (string_builder, "%*s<property type=\"%s\" name=\"%s\" access=\"%s\"",
754                           indent, "",
755                           info->signature,
756                           info->name,
757                           access_string);
758
759   if (info->annotations == NULL)
760     {
761       g_string_append (string_builder, "/>\n");
762     }
763   else
764     {
765       g_string_append (string_builder, ">\n");
766
767       for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
768         g_dbus_annotation_info_generate_xml (info->annotations[n],
769                                                indent + 2,
770                                                string_builder);
771
772       g_string_append_printf (string_builder, "%*s</property>\n", indent, "");
773     }
774
775 }
776
777 /**
778  * g_dbus_interface_info_generate_xml:
779  * @info: A #GDBusNodeInfo
780  * @indent: Indentation level.
781  * @string_builder: A #GString to to append XML data to.
782  *
783  * Appends an XML representation of @info (and its children) to @string_builder.
784  *
785  * This function is typically used for generating introspection XML
786  * documents at run-time for handling the
787  * `org.freedesktop.DBus.Introspectable.Introspect`
788  * method.
789  *
790  * Since: 2.26
791  */
792 void
793 g_dbus_interface_info_generate_xml (GDBusInterfaceInfo *info,
794                                     guint               indent,
795                                     GString            *string_builder)
796 {
797   guint n;
798
799   g_string_append_printf (string_builder, "%*s<interface name=\"%s\">\n",
800                           indent, "",
801                           info->name);
802
803   for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
804     g_dbus_annotation_info_generate_xml (info->annotations[n],
805                                          indent + 2,
806                                          string_builder);
807
808   for (n = 0; info->methods != NULL && info->methods[n] != NULL; n++)
809     g_dbus_method_info_generate_xml (info->methods[n],
810                                      indent + 2,
811                                      string_builder);
812
813   for (n = 0; info->signals != NULL && info->signals[n] != NULL; n++)
814     g_dbus_signal_info_generate_xml (info->signals[n],
815                                      indent + 2,
816                                      string_builder);
817
818   for (n = 0; info->properties != NULL && info->properties[n] != NULL; n++)
819     g_dbus_property_info_generate_xml (info->properties[n],
820                                        indent + 2,
821                                        string_builder);
822
823   g_string_append_printf (string_builder, "%*s</interface>\n", indent, "");
824 }
825
826 /**
827  * g_dbus_node_info_generate_xml:
828  * @info: A #GDBusNodeInfo.
829  * @indent: Indentation level.
830  * @string_builder: A #GString to to append XML data to.
831  *
832  * Appends an XML representation of @info (and its children) to @string_builder.
833  *
834  * This function is typically used for generating introspection XML documents at run-time for
835  * handling the `org.freedesktop.DBus.Introspectable.Introspect`  method.
836  *
837  * Since: 2.26
838  */
839 void
840 g_dbus_node_info_generate_xml (GDBusNodeInfo *info,
841                                guint          indent,
842                                GString       *string_builder)
843 {
844   guint n;
845
846   g_string_append_printf (string_builder, "%*s<node", indent, "");
847   if (info->path != NULL)
848     g_string_append_printf (string_builder, " name=\"%s\"", info->path);
849
850   if (info->interfaces == NULL && info->nodes == NULL && info->annotations == NULL)
851     {
852       g_string_append (string_builder, "/>\n");
853     }
854   else
855     {
856       g_string_append (string_builder, ">\n");
857
858       for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
859         g_dbus_annotation_info_generate_xml (info->annotations[n],
860                                              indent + 2,
861                                              string_builder);
862
863       for (n = 0; info->interfaces != NULL && info->interfaces[n] != NULL; n++)
864         g_dbus_interface_info_generate_xml (info->interfaces[n],
865                                             indent + 2,
866                                             string_builder);
867
868       for (n = 0; info->nodes != NULL && info->nodes[n] != NULL; n++)
869         g_dbus_node_info_generate_xml (info->nodes[n],
870                                        indent + 2,
871                                        string_builder);
872
873       g_string_append_printf (string_builder, "%*s</node>\n", indent, "");
874     }
875 }
876
877 /* ---------------------------------------------------------------------------------------------------- */
878
879 static GDBusAnnotationInfo **
880 parse_data_steal_annotations (ParseData *data,
881                               guint     *out_num_elements)
882 {
883   GDBusAnnotationInfo **ret;
884   if (out_num_elements != NULL)
885     *out_num_elements = data->annotations->len;
886   if (data->annotations == NULL)
887     ret = NULL;
888   else
889     {
890       g_ptr_array_add (data->annotations, NULL);
891       ret = (GDBusAnnotationInfo **) g_ptr_array_free (data->annotations, FALSE);
892     }
893   data->annotations = g_ptr_array_new ();
894   return ret;
895 }
896
897 static GDBusArgInfo **
898 parse_data_steal_args (ParseData *data,
899                        guint     *out_num_elements)
900 {
901   GDBusArgInfo **ret;
902   if (out_num_elements != NULL)
903     *out_num_elements = data->args->len;
904   if (data->args == NULL)
905     ret = NULL;
906   else
907     {
908       g_ptr_array_add (data->args, NULL);
909       ret = (GDBusArgInfo **) g_ptr_array_free (data->args, FALSE);
910     }
911   data->args = g_ptr_array_new ();
912   return ret;
913 }
914
915 static GDBusArgInfo **
916 parse_data_steal_out_args (ParseData *data,
917                            guint     *out_num_elements)
918 {
919   GDBusArgInfo **ret;
920   if (out_num_elements != NULL)
921     *out_num_elements = data->out_args->len;
922   if (data->out_args == NULL)
923     ret = NULL;
924   else
925     {
926       g_ptr_array_add (data->out_args, NULL);
927       ret = (GDBusArgInfo **) g_ptr_array_free (data->out_args, FALSE);
928     }
929   data->out_args = g_ptr_array_new ();
930   return ret;
931 }
932
933 static GDBusMethodInfo **
934 parse_data_steal_methods (ParseData *data,
935                           guint     *out_num_elements)
936 {
937   GDBusMethodInfo **ret;
938   if (out_num_elements != NULL)
939     *out_num_elements = data->methods->len;
940   if (data->methods == NULL)
941     ret = NULL;
942   else
943     {
944       g_ptr_array_add (data->methods, NULL);
945       ret = (GDBusMethodInfo **) g_ptr_array_free (data->methods, FALSE);
946     }
947   data->methods = g_ptr_array_new ();
948   return ret;
949 }
950
951 static GDBusSignalInfo **
952 parse_data_steal_signals (ParseData *data,
953                           guint     *out_num_elements)
954 {
955   GDBusSignalInfo **ret;
956   if (out_num_elements != NULL)
957     *out_num_elements = data->signals->len;
958   if (data->signals == NULL)
959     ret = NULL;
960   else
961     {
962       g_ptr_array_add (data->signals, NULL);
963       ret = (GDBusSignalInfo **) g_ptr_array_free (data->signals, FALSE);
964     }
965   data->signals = g_ptr_array_new ();
966   return ret;
967 }
968
969 static GDBusPropertyInfo **
970 parse_data_steal_properties (ParseData *data,
971                              guint     *out_num_elements)
972 {
973   GDBusPropertyInfo **ret;
974   if (out_num_elements != NULL)
975     *out_num_elements = data->properties->len;
976   if (data->properties == NULL)
977     ret = NULL;
978   else
979     {
980       g_ptr_array_add (data->properties, NULL);
981       ret = (GDBusPropertyInfo **) g_ptr_array_free (data->properties, FALSE);
982     }
983   data->properties = g_ptr_array_new ();
984   return ret;
985 }
986
987 static GDBusInterfaceInfo **
988 parse_data_steal_interfaces (ParseData *data,
989                              guint     *out_num_elements)
990 {
991   GDBusInterfaceInfo **ret;
992   if (out_num_elements != NULL)
993     *out_num_elements = data->interfaces->len;
994   if (data->interfaces == NULL)
995     ret = NULL;
996   else
997     {
998       g_ptr_array_add (data->interfaces, NULL);
999       ret = (GDBusInterfaceInfo **) g_ptr_array_free (data->interfaces, FALSE);
1000     }
1001   data->interfaces = g_ptr_array_new ();
1002   return ret;
1003 }
1004
1005 static GDBusNodeInfo **
1006 parse_data_steal_nodes (ParseData *data,
1007                         guint     *out_num_elements)
1008 {
1009   GDBusNodeInfo **ret;
1010   if (out_num_elements != NULL)
1011     *out_num_elements = data->nodes->len;
1012   if (data->nodes == NULL)
1013     ret = NULL;
1014   else
1015     {
1016       g_ptr_array_add (data->nodes, NULL);
1017       ret = (GDBusNodeInfo **) g_ptr_array_free (data->nodes, FALSE);
1018     }
1019   data->nodes = g_ptr_array_new ();
1020   return ret;
1021 }
1022
1023 /* ---------------------------------------------------------------------------------------------------- */
1024
1025 static void
1026 parse_data_free_annotations (ParseData *data)
1027 {
1028   if (data->annotations == NULL)
1029     return;
1030   g_ptr_array_foreach (data->annotations, (GFunc) g_dbus_annotation_info_unref, NULL);
1031   g_ptr_array_free (data->annotations, TRUE);
1032   data->annotations = NULL;
1033 }
1034
1035 static void
1036 parse_data_free_args (ParseData *data)
1037 {
1038   if (data->args == NULL)
1039     return;
1040   g_ptr_array_foreach (data->args, (GFunc) g_dbus_arg_info_unref, NULL);
1041   g_ptr_array_free (data->args, TRUE);
1042   data->args = NULL;
1043 }
1044
1045 static void
1046 parse_data_free_out_args (ParseData *data)
1047 {
1048   if (data->out_args == NULL)
1049     return;
1050   g_ptr_array_foreach (data->out_args, (GFunc) g_dbus_arg_info_unref, NULL);
1051   g_ptr_array_free (data->out_args, TRUE);
1052   data->out_args = NULL;
1053 }
1054
1055 static void
1056 parse_data_free_methods (ParseData *data)
1057 {
1058   if (data->methods == NULL)
1059     return;
1060   g_ptr_array_foreach (data->methods, (GFunc) g_dbus_method_info_unref, NULL);
1061   g_ptr_array_free (data->methods, TRUE);
1062   data->methods = NULL;
1063 }
1064
1065 static void
1066 parse_data_free_signals (ParseData *data)
1067 {
1068   if (data->signals == NULL)
1069     return;
1070   g_ptr_array_foreach (data->signals, (GFunc) g_dbus_signal_info_unref, NULL);
1071   g_ptr_array_free (data->signals, TRUE);
1072   data->signals = NULL;
1073 }
1074
1075 static void
1076 parse_data_free_properties (ParseData *data)
1077 {
1078   if (data->properties == NULL)
1079     return;
1080   g_ptr_array_foreach (data->properties, (GFunc) g_dbus_property_info_unref, NULL);
1081   g_ptr_array_free (data->properties, TRUE);
1082   data->properties = NULL;
1083 }
1084
1085 static void
1086 parse_data_free_interfaces (ParseData *data)
1087 {
1088   if (data->interfaces == NULL)
1089     return;
1090   g_ptr_array_foreach (data->interfaces, (GFunc) g_dbus_interface_info_unref, NULL);
1091   g_ptr_array_free (data->interfaces, TRUE);
1092   data->interfaces = NULL;
1093 }
1094
1095 static void
1096 parse_data_free_nodes (ParseData *data)
1097 {
1098   if (data->nodes == NULL)
1099     return;
1100   g_ptr_array_foreach (data->nodes, (GFunc) g_dbus_node_info_unref, NULL);
1101   g_ptr_array_free (data->nodes, TRUE);
1102   data->nodes = NULL;
1103 }
1104
1105 /* ---------------------------------------------------------------------------------------------------- */
1106
1107 static GDBusAnnotationInfo *
1108 parse_data_get_annotation (ParseData *data,
1109                            gboolean   create_new)
1110 {
1111   if (create_new)
1112     g_ptr_array_add (data->annotations, g_new0 (GDBusAnnotationInfo, 1));
1113   return data->annotations->pdata[data->annotations->len - 1];
1114 }
1115
1116 static GDBusArgInfo *
1117 parse_data_get_arg (ParseData *data,
1118                     gboolean   create_new)
1119 {
1120   if (create_new)
1121     g_ptr_array_add (data->args, g_new0 (GDBusArgInfo, 1));
1122   return data->args->pdata[data->args->len - 1];
1123 }
1124
1125 static GDBusArgInfo *
1126 parse_data_get_out_arg (ParseData *data,
1127                         gboolean   create_new)
1128 {
1129   if (create_new)
1130     g_ptr_array_add (data->out_args, g_new0 (GDBusArgInfo, 1));
1131   return data->out_args->pdata[data->out_args->len - 1];
1132 }
1133
1134 static GDBusMethodInfo *
1135 parse_data_get_method (ParseData *data,
1136                        gboolean   create_new)
1137 {
1138   if (create_new)
1139     g_ptr_array_add (data->methods, g_new0 (GDBusMethodInfo, 1));
1140   return data->methods->pdata[data->methods->len - 1];
1141 }
1142
1143 static GDBusSignalInfo *
1144 parse_data_get_signal (ParseData *data,
1145                        gboolean   create_new)
1146 {
1147   if (create_new)
1148     g_ptr_array_add (data->signals, g_new0 (GDBusSignalInfo, 1));
1149   return data->signals->pdata[data->signals->len - 1];
1150 }
1151
1152 static GDBusPropertyInfo *
1153 parse_data_get_property (ParseData *data,
1154                          gboolean   create_new)
1155 {
1156   if (create_new)
1157     g_ptr_array_add (data->properties, g_new0 (GDBusPropertyInfo, 1));
1158   return data->properties->pdata[data->properties->len - 1];
1159 }
1160
1161 static GDBusInterfaceInfo *
1162 parse_data_get_interface (ParseData *data,
1163                           gboolean   create_new)
1164 {
1165   if (create_new)
1166     g_ptr_array_add (data->interfaces, g_new0 (GDBusInterfaceInfo, 1));
1167   return data->interfaces->pdata[data->interfaces->len - 1];
1168 }
1169
1170 static GDBusNodeInfo *
1171 parse_data_get_node (ParseData *data,
1172                      gboolean   create_new)
1173 {
1174   if (create_new)
1175     g_ptr_array_add (data->nodes, g_new0 (GDBusNodeInfo, 1));
1176   return data->nodes->pdata[data->nodes->len - 1];
1177 }
1178
1179 /* ---------------------------------------------------------------------------------------------------- */
1180
1181 static ParseData *
1182 parse_data_new (void)
1183 {
1184   ParseData *data;
1185
1186   data = g_new0 (ParseData, 1);
1187
1188   /* initialize arrays */
1189   parse_data_steal_annotations (data, NULL);
1190   parse_data_steal_args (data, NULL);
1191   parse_data_steal_out_args (data, NULL);
1192   parse_data_steal_methods (data, NULL);
1193   parse_data_steal_signals (data, NULL);
1194   parse_data_steal_properties (data, NULL);
1195   parse_data_steal_interfaces (data, NULL);
1196   parse_data_steal_nodes (data, NULL);
1197
1198   return data;
1199 }
1200
1201 static void
1202 parse_data_free (ParseData *data)
1203 {
1204   GSList *l;
1205
1206   /* free stack of annotation arrays */
1207   for (l = data->annotations_stack; l != NULL; l = l->next)
1208     {
1209       GPtrArray *annotations = l->data;
1210       g_ptr_array_foreach (annotations, (GFunc) g_dbus_annotation_info_unref, NULL);
1211       g_ptr_array_free (annotations, TRUE);
1212     }
1213   g_slist_free (data->annotations_stack);
1214
1215   /* free stack of interface arrays */
1216   for (l = data->interfaces_stack; l != NULL; l = l->next)
1217     {
1218       GPtrArray *interfaces = l->data;
1219       g_ptr_array_foreach (interfaces, (GFunc) g_dbus_interface_info_unref, NULL);
1220       g_ptr_array_free (interfaces, TRUE);
1221     }
1222   g_slist_free (data->interfaces_stack);
1223
1224   /* free stack of node arrays */
1225   for (l = data->nodes_stack; l != NULL; l = l->next)
1226     {
1227       GPtrArray *nodes = l->data;
1228       g_ptr_array_foreach (nodes, (GFunc) g_dbus_node_info_unref, NULL);
1229       g_ptr_array_free (nodes, TRUE);
1230     }
1231   g_slist_free (data->nodes_stack);
1232
1233   /* free arrays (data->annotations, data->interfaces and data->nodes have been freed above) */
1234   parse_data_free_args (data);
1235   parse_data_free_out_args (data);
1236   parse_data_free_methods (data);
1237   parse_data_free_signals (data);
1238   parse_data_free_properties (data);
1239   parse_data_free_interfaces (data);
1240   parse_data_free_annotations (data);
1241   parse_data_free_nodes (data);
1242
1243   g_free (data);
1244 }
1245
1246 /* ---------------------------------------------------------------------------------------------------- */
1247
1248 static void
1249 parser_start_element (GMarkupParseContext  *context,
1250                       const gchar          *element_name,
1251                       const gchar         **attribute_names,
1252                       const gchar         **attribute_values,
1253                       gpointer              user_data,
1254                       GError              **error)
1255 {
1256   ParseData *data = user_data;
1257   GSList *stack;
1258   const gchar *name;
1259   const gchar *type;
1260   const gchar *access;
1261   const gchar *direction;
1262   const gchar *value;
1263
1264   name = NULL;
1265   type = NULL;
1266   access = NULL;
1267   direction = NULL;
1268   value = NULL;
1269
1270   stack = (GSList *) g_markup_parse_context_get_element_stack (context);
1271
1272   /* ---------------------------------------------------------------------------------------------------- */
1273   if (strcmp (element_name, "node") == 0)
1274     {
1275       if (!(g_slist_length (stack) >= 1 || strcmp (stack->next->data, "node") != 0))
1276         {
1277           g_set_error_literal (error,
1278                                G_MARKUP_ERROR,
1279                                G_MARKUP_ERROR_INVALID_CONTENT,
1280                                "<node> elements can only be top-level or embedded in other <node> elements");
1281           goto out;
1282         }
1283
1284       if (!g_markup_collect_attributes (element_name,
1285                                         attribute_names,
1286                                         attribute_values,
1287                                         error,
1288                                         G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "name", &name,
1289                                         /* some hand-written introspection XML documents use this */
1290                                         G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "xmlns:doc", NULL,
1291                                         G_MARKUP_COLLECT_INVALID))
1292         goto out;
1293
1294       g_dbus_node_info_set (data,
1295                             parse_data_get_node (data, TRUE),
1296                             name,
1297                             NULL,
1298                             NULL,
1299                             NULL);
1300
1301       /* push the currently retrieved interfaces and nodes on the stack and prepare new arrays */
1302       data->interfaces_stack = g_slist_prepend (data->interfaces_stack, data->interfaces);
1303       data->interfaces = NULL;
1304       parse_data_steal_interfaces (data, NULL);
1305
1306       data->nodes_stack = g_slist_prepend (data->nodes_stack, data->nodes);
1307       data->nodes = NULL;
1308       parse_data_steal_nodes (data, NULL);
1309
1310     }
1311   /* ---------------------------------------------------------------------------------------------------- */
1312   else if (strcmp (element_name, "interface") == 0)
1313     {
1314       if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "node") != 0)
1315         {
1316           g_set_error_literal (error,
1317                                G_MARKUP_ERROR,
1318                                G_MARKUP_ERROR_INVALID_CONTENT,
1319                                "<interface> elements can only be embedded in <node> elements");
1320           goto out;
1321         }
1322
1323       if (!g_markup_collect_attributes (element_name,
1324                                         attribute_names,
1325                                         attribute_values,
1326                                         error,
1327                                         G_MARKUP_COLLECT_STRING, "name", &name,
1328                                         /* seen in the wild */
1329                                         G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "version", NULL,
1330                                         G_MARKUP_COLLECT_INVALID))
1331         goto out;
1332
1333       g_dbus_interface_info_set (data,
1334                                  parse_data_get_interface (data, TRUE),
1335                                  name,
1336                                  NULL,
1337                                  NULL,
1338                                  NULL,
1339                                  NULL);
1340
1341     }
1342   /* ---------------------------------------------------------------------------------------------------- */
1343   else if (strcmp (element_name, "method") == 0)
1344     {
1345       if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "interface") != 0)
1346         {
1347           g_set_error_literal (error,
1348                                G_MARKUP_ERROR,
1349                                G_MARKUP_ERROR_INVALID_CONTENT,
1350                                "<method> elements can only be embedded in <interface> elements");
1351           goto out;
1352         }
1353
1354       if (!g_markup_collect_attributes (element_name,
1355                                         attribute_names,
1356                                         attribute_values,
1357                                         error,
1358                                         G_MARKUP_COLLECT_STRING, "name", &name,
1359                                         /* seen in the wild */
1360                                         G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "version", NULL,
1361                                         G_MARKUP_COLLECT_INVALID))
1362         goto out;
1363
1364       g_dbus_method_info_set (data,
1365                               parse_data_get_method (data, TRUE),
1366                               name,
1367                               NULL,
1368                               NULL,
1369                               NULL);
1370
1371       data->num_args = 0;
1372
1373     }
1374   /* ---------------------------------------------------------------------------------------------------- */
1375   else if (strcmp (element_name, "signal") == 0)
1376     {
1377       if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "interface") != 0)
1378         {
1379           g_set_error_literal (error,
1380                                G_MARKUP_ERROR,
1381                                G_MARKUP_ERROR_INVALID_CONTENT,
1382                                "<signal> elements can only be embedded in <interface> elements");
1383           goto out;
1384         }
1385
1386       if (!g_markup_collect_attributes (element_name,
1387                                         attribute_names,
1388                                         attribute_values,
1389                                         error,
1390                                         G_MARKUP_COLLECT_STRING, "name", &name,
1391                                         G_MARKUP_COLLECT_INVALID))
1392         goto out;
1393
1394       g_dbus_signal_info_set (data,
1395                               parse_data_get_signal (data, TRUE),
1396                               name,
1397                               NULL,
1398                               NULL);
1399
1400       data->num_args = 0;
1401
1402     }
1403   /* ---------------------------------------------------------------------------------------------------- */
1404   else if (strcmp (element_name, "property") == 0)
1405     {
1406       GDBusPropertyInfoFlags flags;
1407
1408       if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "interface") != 0)
1409         {
1410           g_set_error_literal (error,
1411                                G_MARKUP_ERROR,
1412                                G_MARKUP_ERROR_INVALID_CONTENT,
1413                                "<property> elements can only be embedded in <interface> elements");
1414           goto out;
1415         }
1416
1417       if (!g_markup_collect_attributes (element_name,
1418                                         attribute_names,
1419                                         attribute_values,
1420                                         error,
1421                                         G_MARKUP_COLLECT_STRING, "name", &name,
1422                                         G_MARKUP_COLLECT_STRING, "type", &type,
1423                                         G_MARKUP_COLLECT_STRING, "access", &access,
1424                                         G_MARKUP_COLLECT_INVALID))
1425         goto out;
1426
1427       if (strcmp (access, "read") == 0)
1428         flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE;
1429       else if (strcmp (access, "write") == 0)
1430         flags = G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE;
1431       else if (strcmp (access, "readwrite") == 0)
1432         flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE;
1433       else
1434         {
1435           g_set_error (error,
1436                        G_MARKUP_ERROR,
1437                        G_MARKUP_ERROR_INVALID_CONTENT,
1438                        "Unknown value '%s' of access attribute for element <property>",
1439                        access);
1440           goto out;
1441         }
1442
1443       g_dbus_property_info_set (data,
1444                                 parse_data_get_property (data, TRUE),
1445                                 name,
1446                                 type,
1447                                 flags,
1448                                 NULL);
1449
1450     }
1451   /* ---------------------------------------------------------------------------------------------------- */
1452   else if (strcmp (element_name, "arg") == 0)
1453     {
1454       gboolean is_in;
1455       gchar *name_to_use;
1456
1457       if (g_slist_length (stack) < 2 ||
1458           (strcmp (stack->next->data, "method") != 0 &&
1459            strcmp (stack->next->data, "signal") != 0))
1460         {
1461           g_set_error_literal (error,
1462                                G_MARKUP_ERROR,
1463                                G_MARKUP_ERROR_INVALID_CONTENT,
1464                                "<arg> elements can only be embedded in <method> or <signal> elements");
1465           goto out;
1466         }
1467
1468       if (!g_markup_collect_attributes (element_name,
1469                                         attribute_names,
1470                                         attribute_values,
1471                                         error,
1472                                         G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "name", &name,
1473                                         G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "direction", &direction,
1474                                         G_MARKUP_COLLECT_STRING, "type", &type,
1475                                         G_MARKUP_COLLECT_INVALID))
1476         goto out;
1477
1478       if (strcmp (stack->next->data, "method") == 0)
1479         is_in = TRUE;
1480       else
1481         is_in = FALSE;
1482       if (direction != NULL)
1483         {
1484           if (strcmp (direction, "in") == 0)
1485             is_in = TRUE;
1486           else if (strcmp (direction, "out") == 0)
1487             is_in = FALSE;
1488           else
1489             {
1490               g_set_error (error,
1491                            G_MARKUP_ERROR,
1492                            G_MARKUP_ERROR_INVALID_CONTENT,
1493                            "Unknown value '%s' of direction attribute",
1494                            direction);
1495               goto out;
1496             }
1497         }
1498
1499       if (is_in && strcmp (stack->next->data, "signal") == 0)
1500         {
1501           g_set_error_literal (error,
1502                                G_MARKUP_ERROR,
1503                                G_MARKUP_ERROR_INVALID_CONTENT,
1504                                "Only direction 'out' is allowed for <arg> elements embedded in <signal>");
1505           goto out;
1506         }
1507
1508       if (name == NULL)
1509         name_to_use = g_strdup_printf ("arg_%d", data->num_args);
1510       else
1511         name_to_use = g_strdup (name);
1512       data->num_args++;
1513
1514       if (is_in)
1515         {
1516           g_dbus_arg_info_set (data,
1517                                parse_data_get_arg (data, TRUE),
1518                                name_to_use,
1519                                type,
1520                                NULL);
1521           data->last_arg_was_in = TRUE;
1522         }
1523       else
1524         {
1525           g_dbus_arg_info_set (data,
1526                                parse_data_get_out_arg (data, TRUE),
1527                                name_to_use,
1528                                type,
1529                                NULL);
1530           data->last_arg_was_in = FALSE;
1531
1532         }
1533
1534       g_free (name_to_use);
1535     }
1536   /* ---------------------------------------------------------------------------------------------------- */
1537   else if (strcmp (element_name, "annotation") == 0)
1538     {
1539       if (g_slist_length (stack) < 2 ||
1540           (strcmp (stack->next->data, "node") != 0 &&
1541            strcmp (stack->next->data, "interface") != 0 &&
1542            strcmp (stack->next->data, "signal") != 0 &&
1543            strcmp (stack->next->data, "method") != 0 &&
1544            strcmp (stack->next->data, "property") != 0 &&
1545            strcmp (stack->next->data, "arg") != 0 &&
1546            strcmp (stack->next->data, "annotation") != 0))
1547         {
1548           g_set_error_literal (error,
1549                                G_MARKUP_ERROR,
1550                                G_MARKUP_ERROR_INVALID_CONTENT,
1551                                "<annotation> elements can only be embedded in <node>, <interface>, <signal>, <method>, <property>, <arg> or <annotation> elements");
1552           goto out;
1553         }
1554
1555       if (!g_markup_collect_attributes (element_name,
1556                                         attribute_names,
1557                                         attribute_values,
1558                                         error,
1559                                         G_MARKUP_COLLECT_STRING, "name", &name,
1560                                         G_MARKUP_COLLECT_STRING, "value", &value,
1561                                         G_MARKUP_COLLECT_INVALID))
1562         goto out;
1563
1564       g_dbus_annotation_info_set (data,
1565                                   parse_data_get_annotation (data, TRUE),
1566                                   name,
1567                                   value,
1568                                   NULL);
1569     }
1570   /* ---------------------------------------------------------------------------------------------------- */
1571   else
1572     {
1573       /* don't bail on unknown elements; just ignore them */
1574     }
1575   /* ---------------------------------------------------------------------------------------------------- */
1576
1577   /* push the currently retrieved annotations on the stack and prepare a new one */
1578   data->annotations_stack = g_slist_prepend (data->annotations_stack, data->annotations);
1579   data->annotations = NULL;
1580   parse_data_steal_annotations (data, NULL);
1581
1582  out:
1583   ;
1584 }
1585
1586 /* ---------------------------------------------------------------------------------------------------- */
1587
1588 static GDBusAnnotationInfo **
1589 steal_annotations (ParseData *data)
1590 {
1591   return parse_data_steal_annotations (data, NULL);
1592 }
1593
1594
1595 static void
1596 parser_end_element (GMarkupParseContext  *context,
1597                     const gchar          *element_name,
1598                     gpointer              user_data,
1599                     GError              **error)
1600 {
1601   ParseData *data = user_data;
1602   gboolean have_popped_annotations;
1603
1604   have_popped_annotations = FALSE;
1605
1606   if (strcmp (element_name, "node") == 0)
1607     {
1608       guint num_nodes;
1609       guint num_interfaces;
1610       GDBusNodeInfo **nodes;
1611       GDBusInterfaceInfo **interfaces;
1612
1613       nodes = parse_data_steal_nodes (data, &num_nodes);
1614       interfaces = parse_data_steal_interfaces (data, &num_interfaces);
1615
1616       /* destroy the nodes, interfaces for scope we're exiting and pop the nodes, interfaces from the
1617        * scope we're reentering
1618        */
1619       parse_data_free_interfaces (data);
1620       data->interfaces = (GPtrArray *) data->interfaces_stack->data;
1621       data->interfaces_stack = g_slist_remove (data->interfaces_stack, data->interfaces_stack->data);
1622
1623       parse_data_free_nodes (data);
1624       data->nodes = (GPtrArray *) data->nodes_stack->data;
1625       data->nodes_stack = g_slist_remove (data->nodes_stack, data->nodes_stack->data);
1626
1627       g_dbus_node_info_set (data,
1628                             parse_data_get_node (data, FALSE),
1629                             NULL,
1630                             interfaces,
1631                             nodes,
1632                             steal_annotations (data));
1633
1634     }
1635   else if (strcmp (element_name, "interface") == 0)
1636     {
1637       guint num_methods;
1638       guint num_signals;
1639       guint num_properties;
1640       GDBusMethodInfo **methods;
1641       GDBusSignalInfo **signals;
1642       GDBusPropertyInfo **properties;
1643
1644       methods    = parse_data_steal_methods    (data, &num_methods);
1645       signals    = parse_data_steal_signals    (data, &num_signals);
1646       properties = parse_data_steal_properties (data, &num_properties);
1647
1648       g_dbus_interface_info_set (data,
1649                                  parse_data_get_interface (data, FALSE),
1650                                  NULL,
1651                                  methods,
1652                                  signals,
1653                                  properties,
1654                                  steal_annotations (data));
1655
1656     }
1657   else if (strcmp (element_name, "method") == 0)
1658     {
1659       guint in_num_args;
1660       guint out_num_args;
1661       GDBusArgInfo **in_args;
1662       GDBusArgInfo **out_args;
1663
1664       in_args  = parse_data_steal_args     (data, &in_num_args);
1665       out_args = parse_data_steal_out_args (data, &out_num_args);
1666
1667       g_dbus_method_info_set (data,
1668                               parse_data_get_method (data, FALSE),
1669                               NULL,
1670                               in_args,
1671                               out_args,
1672                               steal_annotations (data));
1673     }
1674   else if (strcmp (element_name, "signal") == 0)
1675     {
1676       guint num_args;
1677       GDBusArgInfo **args;
1678
1679       args = parse_data_steal_out_args (data, &num_args);
1680
1681       g_dbus_signal_info_set (data,
1682                               parse_data_get_signal (data, FALSE),
1683                               NULL,
1684                               args,
1685                               steal_annotations (data));
1686     }
1687   else if (strcmp (element_name, "property") == 0)
1688     {
1689       g_dbus_property_info_set (data,
1690                                 parse_data_get_property (data, FALSE),
1691                                 NULL,
1692                                 NULL,
1693                                 G_DBUS_PROPERTY_INFO_FLAGS_NONE,
1694                                 steal_annotations (data));
1695     }
1696   else if (strcmp (element_name, "arg") == 0)
1697     {
1698       g_dbus_arg_info_set (data,
1699                            data->last_arg_was_in ? parse_data_get_arg (data, FALSE) : parse_data_get_out_arg (data, FALSE),
1700                            NULL,
1701                            NULL,
1702                            steal_annotations (data));
1703     }
1704   else if (strcmp (element_name, "annotation") == 0)
1705     {
1706       GDBusAnnotationInfo **embedded_annotations;
1707
1708       embedded_annotations = steal_annotations (data);
1709
1710       /* destroy the annotations for scope we're exiting and pop the annotations from the scope we're reentering */
1711       parse_data_free_annotations (data);
1712       data->annotations = (GPtrArray *) data->annotations_stack->data;
1713       data->annotations_stack = g_slist_remove (data->annotations_stack, data->annotations_stack->data);
1714
1715       have_popped_annotations = TRUE;
1716
1717       g_dbus_annotation_info_set (data,
1718                                   parse_data_get_annotation (data, FALSE),
1719                                   NULL,
1720                                   NULL,
1721                                   embedded_annotations);
1722     }
1723   else
1724     {
1725       /* don't bail on unknown elements; just ignore them */
1726     }
1727
1728   if (!have_popped_annotations)
1729     {
1730       /* destroy the annotations for scope we're exiting and pop the annotations from the scope we're reentering */
1731       parse_data_free_annotations (data);
1732       data->annotations = (GPtrArray *) data->annotations_stack->data;
1733       data->annotations_stack = g_slist_remove (data->annotations_stack, data->annotations_stack->data);
1734     }
1735 }
1736
1737 /* ---------------------------------------------------------------------------------------------------- */
1738
1739 static void
1740 parser_error (GMarkupParseContext *context,
1741               GError              *error,
1742               gpointer             user_data)
1743 {
1744   gint line_number;
1745   gint char_number;
1746
1747   g_markup_parse_context_get_position (context, &line_number, &char_number);
1748
1749   g_prefix_error (&error, "%d:%d: ",
1750                   line_number,
1751                   char_number);
1752 }
1753
1754 /* ---------------------------------------------------------------------------------------------------- */
1755
1756 /**
1757  * g_dbus_node_info_new_for_xml:
1758  * @xml_data: Valid D-Bus introspection XML.
1759  * @error: Return location for error.
1760  *
1761  * Parses @xml_data and returns a #GDBusNodeInfo representing the data.
1762  *
1763  * The introspection XML must contain exactly one top-level
1764  * <node> element.
1765  *
1766  * Note that this routine is using a
1767  * [GMarkup][glib-Simple-XML-Subset-Parser.description]-based
1768  * parser that only accepts a subset of valid XML documents.
1769  *
1770  * Returns: A #GDBusNodeInfo structure or %NULL if @error is set. Free
1771  * with g_dbus_node_info_unref().
1772  *
1773  * Since: 2.26
1774  */
1775 GDBusNodeInfo *
1776 g_dbus_node_info_new_for_xml (const gchar  *xml_data,
1777                               GError      **error)
1778 {
1779   GDBusNodeInfo *ret;
1780   GMarkupParseContext *context;
1781   GMarkupParser *parser;
1782   guint num_nodes;
1783   ParseData *data;
1784   GDBusNodeInfo **ughret;
1785
1786   ret = NULL;
1787   parser = NULL;
1788   context = NULL;
1789
1790   parser = g_new0 (GMarkupParser, 1);
1791   parser->start_element = parser_start_element;
1792   parser->end_element   = parser_end_element;
1793   parser->error         = parser_error;
1794
1795   data = parse_data_new ();
1796   context = g_markup_parse_context_new (parser,
1797                                         G_MARKUP_IGNORE_QUALIFIED,
1798                                         data,
1799                                         (GDestroyNotify) parse_data_free);
1800
1801   if (!g_markup_parse_context_parse (context,
1802                                      xml_data,
1803                                      strlen (xml_data),
1804                                      error))
1805     goto out;
1806
1807   if (!g_markup_parse_context_end_parse (context, error))
1808     goto out;
1809
1810   ughret = parse_data_steal_nodes (data, &num_nodes);
1811
1812   if (num_nodes != 1)
1813     {
1814       guint n;
1815
1816       g_set_error (error,
1817                    G_MARKUP_ERROR,
1818                    G_MARKUP_ERROR_INVALID_CONTENT,
1819                    "Expected a single node in introspection XML, found %d",
1820                    num_nodes);
1821
1822       /* clean up */
1823       for (n = 0; n < num_nodes; n++)
1824         {
1825           g_dbus_node_info_unref (ughret[n]);
1826           ughret[n] = NULL;
1827         }
1828     }
1829
1830   ret = ughret[0];
1831   g_free (ughret);
1832
1833  out:
1834   g_free (parser);
1835   if (context != NULL)
1836     g_markup_parse_context_free (context);
1837
1838   return ret;
1839 }
1840
1841 /* ---------------------------------------------------------------------------------------------------- */
1842
1843 /**
1844  * g_dbus_annotation_info_lookup:
1845  * @annotations: (array zero-terminated=1) (nullable): A %NULL-terminated array of annotations or %NULL.
1846  * @name: The name of the annotation to look up.
1847  *
1848  * Looks up the value of an annotation.
1849  *
1850  * The cost of this function is O(n) in number of annotations.
1851  *
1852  * Returns: (nullable): The value or %NULL if not found. Do not free, it is owned by @annotations.
1853  *
1854  * Since: 2.26
1855  */
1856 const gchar *
1857 g_dbus_annotation_info_lookup (GDBusAnnotationInfo **annotations,
1858                                const gchar          *name)
1859 {
1860   guint n;
1861   const gchar *ret;
1862
1863   ret = NULL;
1864   for (n = 0; annotations != NULL && annotations[n] != NULL; n++)
1865     {
1866       if (g_strcmp0 (annotations[n]->key, name) == 0)
1867         {
1868           ret = annotations[n]->value;
1869           goto out;
1870         }
1871     }
1872
1873  out:
1874   return ret;
1875 }
1876
1877 /* ---------------------------------------------------------------------------------------------------- */
1878
1879 G_LOCK_DEFINE_STATIC (info_cache_lock);
1880
1881 typedef struct
1882 {
1883   gint use_count;
1884
1885   /* gchar* -> GDBusMethodInfo* */
1886   GHashTable *method_name_to_data;
1887
1888   /* gchar* -> GDBusMethodInfo* */
1889   GHashTable *signal_name_to_data;
1890
1891   /* gchar* -> GDBusMethodInfo* */
1892   GHashTable *property_name_to_data;
1893 } InfoCacheEntry;
1894
1895 static void
1896 info_cache_free (InfoCacheEntry *cache)
1897 {
1898   g_assert (cache->use_count == 0);
1899   g_hash_table_unref (cache->method_name_to_data);
1900   g_hash_table_unref (cache->signal_name_to_data);
1901   g_hash_table_unref (cache->property_name_to_data);
1902   g_slice_free (InfoCacheEntry, cache);
1903 }
1904
1905 /* maps from GDBusInterfaceInfo* to InfoCacheEntry* */
1906 static GHashTable *info_cache = NULL;
1907
1908 /* ---------------------------------------------------------------------------------------------------- */
1909
1910 /**
1911  * g_dbus_interface_info_lookup_method:
1912  * @info: A #GDBusInterfaceInfo.
1913  * @name: A D-Bus method name (typically in CamelCase)
1914  *
1915  * Looks up information about a method.
1916  *
1917  * The cost of this function is O(n) in number of methods unless
1918  * g_dbus_interface_info_cache_build() has been used on @info.
1919  *
1920  * Returns: (nullable) (transfer none): A #GDBusMethodInfo or %NULL if not found. Do not free, it is owned by @info.
1921  *
1922  * Since: 2.26
1923  */
1924 GDBusMethodInfo *
1925 g_dbus_interface_info_lookup_method (GDBusInterfaceInfo *info,
1926                                      const gchar        *name)
1927 {
1928   guint n;
1929   GDBusMethodInfo *result;
1930
1931   G_LOCK (info_cache_lock);
1932   if (G_LIKELY (info_cache != NULL))
1933     {
1934       InfoCacheEntry *cache;
1935       cache = g_hash_table_lookup (info_cache, info);
1936       if (G_LIKELY (cache != NULL))
1937         {
1938           result = g_hash_table_lookup (cache->method_name_to_data, name);
1939           G_UNLOCK (info_cache_lock);
1940           goto out;
1941         }
1942     }
1943   G_UNLOCK (info_cache_lock);
1944
1945   for (n = 0; info->methods != NULL && info->methods[n] != NULL; n++)
1946     {
1947       GDBusMethodInfo *i = info->methods[n];
1948
1949       if (g_strcmp0 (i->name, name) == 0)
1950         {
1951           result = i;
1952           goto out;
1953         }
1954     }
1955
1956   result = NULL;
1957
1958  out:
1959   return result;
1960 }
1961
1962 /* ---------------------------------------------------------------------------------------------------- */
1963
1964 /**
1965  * g_dbus_interface_info_lookup_signal:
1966  * @info: A #GDBusInterfaceInfo.
1967  * @name: A D-Bus signal name (typically in CamelCase)
1968  *
1969  * Looks up information about a signal.
1970  *
1971  * The cost of this function is O(n) in number of signals unless
1972  * g_dbus_interface_info_cache_build() has been used on @info.
1973  *
1974  * Returns: (nullable) (transfer none): A #GDBusSignalInfo or %NULL if not found. Do not free, it is owned by @info.
1975  *
1976  * Since: 2.26
1977  */
1978 GDBusSignalInfo *
1979 g_dbus_interface_info_lookup_signal (GDBusInterfaceInfo *info,
1980                                      const gchar        *name)
1981 {
1982   guint n;
1983   GDBusSignalInfo *result;
1984
1985   G_LOCK (info_cache_lock);
1986   if (G_LIKELY (info_cache != NULL))
1987     {
1988       InfoCacheEntry *cache;
1989       cache = g_hash_table_lookup (info_cache, info);
1990       if (G_LIKELY (cache != NULL))
1991         {
1992           result = g_hash_table_lookup (cache->signal_name_to_data, name);
1993           G_UNLOCK (info_cache_lock);
1994           goto out;
1995         }
1996     }
1997   G_UNLOCK (info_cache_lock);
1998
1999   for (n = 0; info->signals != NULL && info->signals[n] != NULL; n++)
2000     {
2001       GDBusSignalInfo *i = info->signals[n];
2002
2003       if (g_strcmp0 (i->name, name) == 0)
2004         {
2005           result = i;
2006           goto out;
2007         }
2008     }
2009
2010   result = NULL;
2011
2012  out:
2013   return result;
2014 }
2015
2016 /* ---------------------------------------------------------------------------------------------------- */
2017
2018 /**
2019  * g_dbus_interface_info_lookup_property:
2020  * @info: A #GDBusInterfaceInfo.
2021  * @name: A D-Bus property name (typically in CamelCase).
2022  *
2023  * Looks up information about a property.
2024  *
2025  * The cost of this function is O(n) in number of properties unless
2026  * g_dbus_interface_info_cache_build() has been used on @info.
2027  *
2028  * Returns: (nullable) (transfer none): A #GDBusPropertyInfo or %NULL if not found. Do not free, it is owned by @info.
2029  *
2030  * Since: 2.26
2031  */
2032 GDBusPropertyInfo *
2033 g_dbus_interface_info_lookup_property (GDBusInterfaceInfo *info,
2034                                        const gchar        *name)
2035 {
2036   guint n;
2037   GDBusPropertyInfo *result;
2038
2039   G_LOCK (info_cache_lock);
2040   if (G_LIKELY (info_cache != NULL))
2041     {
2042       InfoCacheEntry *cache;
2043       cache = g_hash_table_lookup (info_cache, info);
2044       if (G_LIKELY (cache != NULL))
2045         {
2046           result = g_hash_table_lookup (cache->property_name_to_data, name);
2047           G_UNLOCK (info_cache_lock);
2048           goto out;
2049         }
2050     }
2051   G_UNLOCK (info_cache_lock);
2052
2053   for (n = 0; info->properties != NULL && info->properties[n] != NULL; n++)
2054     {
2055       GDBusPropertyInfo *i = info->properties[n];
2056
2057       if (g_strcmp0 (i->name, name) == 0)
2058         {
2059           result = i;
2060           goto out;
2061         }
2062     }
2063
2064   result = NULL;
2065
2066  out:
2067   return result;
2068 }
2069
2070 /* ---------------------------------------------------------------------------------------------------- */
2071
2072 /**
2073  * g_dbus_interface_info_cache_build:
2074  * @info: A #GDBusInterfaceInfo.
2075  *
2076  * Builds a lookup-cache to speed up
2077  * g_dbus_interface_info_lookup_method(),
2078  * g_dbus_interface_info_lookup_signal() and
2079  * g_dbus_interface_info_lookup_property().
2080  *
2081  * If this has already been called with @info, the existing cache is
2082  * used and its use count is increased.
2083  *
2084  * Note that @info cannot be modified until
2085  * g_dbus_interface_info_cache_release() is called.
2086  *
2087  * Since: 2.30
2088  */
2089 void
2090 g_dbus_interface_info_cache_build (GDBusInterfaceInfo *info)
2091 {
2092   InfoCacheEntry *cache;
2093   guint n;
2094
2095   G_LOCK (info_cache_lock);
2096   if (info_cache == NULL)
2097     info_cache = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) info_cache_free);
2098   cache = g_hash_table_lookup (info_cache, info);
2099   if (cache != NULL)
2100     {
2101       cache->use_count += 1;
2102       goto out;
2103     }
2104   cache = g_slice_new0 (InfoCacheEntry);
2105   cache->use_count = 1;
2106   cache->method_name_to_data = g_hash_table_new (g_str_hash, g_str_equal);
2107   cache->signal_name_to_data = g_hash_table_new (g_str_hash, g_str_equal);
2108   cache->property_name_to_data = g_hash_table_new (g_str_hash, g_str_equal);
2109   for (n = 0; info->methods != NULL && info->methods[n] != NULL; n++)
2110     g_hash_table_insert (cache->method_name_to_data, info->methods[n]->name, info->methods[n]);
2111   for (n = 0; info->signals != NULL && info->signals[n] != NULL; n++)
2112     g_hash_table_insert (cache->signal_name_to_data, info->signals[n]->name, info->signals[n]);
2113   for (n = 0; info->properties != NULL && info->properties[n] != NULL; n++)
2114     g_hash_table_insert (cache->property_name_to_data, info->properties[n]->name, info->properties[n]);
2115   g_hash_table_insert (info_cache, info, cache);
2116  out:
2117   G_UNLOCK (info_cache_lock);
2118 }
2119
2120 /**
2121  * g_dbus_interface_info_cache_release:
2122  * @info: A GDBusInterfaceInfo
2123  *
2124  * Decrements the usage count for the cache for @info built by
2125  * g_dbus_interface_info_cache_build() (if any) and frees the
2126  * resources used by the cache if the usage count drops to zero.
2127  *
2128  * Since: 2.30
2129  */
2130 void
2131 g_dbus_interface_info_cache_release (GDBusInterfaceInfo *info)
2132 {
2133   InfoCacheEntry *cache;
2134
2135   G_LOCK (info_cache_lock);
2136   if (G_UNLIKELY (info_cache == NULL))
2137     {
2138       g_warning ("%s called for interface %s but there is no cache", info->name, G_STRFUNC);
2139       goto out;
2140     }
2141
2142   cache = g_hash_table_lookup (info_cache, info);
2143   if (G_UNLIKELY (cache == NULL))
2144     {
2145       g_warning ("%s called for interface %s but there is no cache entry", info->name, G_STRFUNC);
2146       goto out;
2147     }
2148   cache->use_count -= 1;
2149   if (cache->use_count == 0)
2150     {
2151       g_hash_table_remove (info_cache, info);
2152       /* could nuke info_cache itself if empty */
2153     }
2154  out:
2155   G_UNLOCK (info_cache_lock);
2156 }
2157
2158
2159 /* ---------------------------------------------------------------------------------------------------- */
2160
2161 /**
2162  * g_dbus_node_info_lookup_interface:
2163  * @info: A #GDBusNodeInfo.
2164  * @name: A D-Bus interface name.
2165  *
2166  * Looks up information about an interface.
2167  *
2168  * The cost of this function is O(n) in number of interfaces.
2169  *
2170  * Returns: (nullable) (transfer none): A #GDBusInterfaceInfo or %NULL if not found. Do not free, it is owned by @info.
2171  *
2172  * Since: 2.26
2173  */
2174 GDBusInterfaceInfo *
2175 g_dbus_node_info_lookup_interface (GDBusNodeInfo *info,
2176                                    const gchar   *name)
2177 {
2178   guint n;
2179   GDBusInterfaceInfo *result;
2180
2181   for (n = 0; info->interfaces != NULL && info->interfaces[n] != NULL; n++)
2182     {
2183       GDBusInterfaceInfo *i = info->interfaces[n];
2184
2185       if (g_strcmp0 (i->name, name) == 0)
2186         {
2187           result = i;
2188           goto out;
2189         }
2190     }
2191
2192   result = NULL;
2193
2194  out:
2195   return result;
2196 }