1 /* GDBus - GLib D-Bus Library
3 * Copyright (C) 2008-2010 Red Hat, Inc.
5 * SPDX-License-Identifier: LGPL-2.1-or-later
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.
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.
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/>.
20 * Author: David Zeuthen <davidz@redhat.com>
28 #include "gdbusintrospection.h"
33 * SECTION:gdbusintrospection
34 * @title: D-Bus Introspection Data
35 * @short_description: Node and interface description data structures
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().
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)
46 /* ---------------------------------------------------------------------------------------------------- */
48 #define _MY_DEFINE_BOXED_TYPE(TypeName, type_name) \
49 G_DEFINE_BOXED_TYPE (TypeName, type_name, type_name##_ref, type_name##_unref)
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)
59 #undef _MY_DEFINE_BOXED_TYPE
61 /* ---------------------------------------------------------------------------------------------------- */
65 /* stuff we are currently collecting */
70 GPtrArray *properties;
71 GPtrArray *interfaces;
73 GPtrArray *annotations;
75 /* A list of GPtrArray's containing annotations */
76 GSList *annotations_stack;
78 /* A list of GPtrArray's containing interfaces */
79 GSList *interfaces_stack;
81 /* A list of GPtrArray's containing nodes */
84 /* Whether the direction was "in" for last parsed arg */
85 gboolean last_arg_was_in;
87 /* Number of args currently being collected; used for assigning
88 * names to args without a "name" attribute
94 /* ---------------------------------------------------------------------------------------------------- */
97 * g_dbus_node_info_ref:
98 * @info: A #GDBusNodeInfo
100 * If @info is statically allocated does nothing. Otherwise increases
101 * the reference count.
103 * Returns: (not nullable): The same @info.
108 g_dbus_node_info_ref (GDBusNodeInfo *info)
110 if (g_atomic_int_get (&info->ref_count) == -1)
112 g_atomic_int_inc (&info->ref_count);
117 * g_dbus_interface_info_ref:
118 * @info: A #GDBusInterfaceInfo
120 * If @info is statically allocated does nothing. Otherwise increases
121 * the reference count.
123 * Returns: (not nullable): The same @info.
128 g_dbus_interface_info_ref (GDBusInterfaceInfo *info)
130 if (g_atomic_int_get (&info->ref_count) == -1)
132 g_atomic_int_inc (&info->ref_count);
137 * g_dbus_method_info_ref:
138 * @info: A #GDBusMethodInfo
140 * If @info is statically allocated does nothing. Otherwise increases
141 * the reference count.
143 * Returns: (not nullable): The same @info.
148 g_dbus_method_info_ref (GDBusMethodInfo *info)
150 if (g_atomic_int_get (&info->ref_count) == -1)
152 g_atomic_int_inc (&info->ref_count);
157 * g_dbus_signal_info_ref:
158 * @info: A #GDBusSignalInfo
160 * If @info is statically allocated does nothing. Otherwise increases
161 * the reference count.
163 * Returns: (not nullable): The same @info.
168 g_dbus_signal_info_ref (GDBusSignalInfo *info)
170 if (g_atomic_int_get (&info->ref_count) == -1)
172 g_atomic_int_inc (&info->ref_count);
177 * g_dbus_property_info_ref:
178 * @info: A #GDBusPropertyInfo
180 * If @info is statically allocated does nothing. Otherwise increases
181 * the reference count.
183 * Returns: (not nullable): The same @info.
188 g_dbus_property_info_ref (GDBusPropertyInfo *info)
190 if (g_atomic_int_get (&info->ref_count) == -1)
192 g_atomic_int_inc (&info->ref_count);
197 * g_dbus_arg_info_ref:
198 * @info: A #GDBusArgInfo
200 * If @info is statically allocated does nothing. Otherwise increases
201 * the reference count.
203 * Returns: (not nullable): The same @info.
208 g_dbus_arg_info_ref (GDBusArgInfo *info)
210 if (g_atomic_int_get (&info->ref_count) == -1)
212 g_atomic_int_inc (&info->ref_count);
217 * g_dbus_annotation_info_ref:
218 * @info: A #GDBusNodeInfo
220 * If @info is statically allocated does nothing. Otherwise increases
221 * the reference count.
223 * Returns: (not nullable): The same @info.
227 GDBusAnnotationInfo *
228 g_dbus_annotation_info_ref (GDBusAnnotationInfo *info)
230 if (g_atomic_int_get (&info->ref_count) == -1)
232 g_atomic_int_inc (&info->ref_count);
236 /* ---------------------------------------------------------------------------------------------------- */
239 free_null_terminated_array (gpointer array, GDestroyNotify unref_func)
245 for (n = 0; p[n] != NULL; n++)
251 * g_dbus_annotation_info_unref:
252 * @info: A #GDBusAnnotationInfo.
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.
261 g_dbus_annotation_info_unref (GDBusAnnotationInfo *info)
263 if (g_atomic_int_get (&info->ref_count) == -1)
265 if (g_atomic_int_dec_and_test (&info->ref_count))
268 g_free (info->value);
269 free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
275 * g_dbus_arg_info_unref:
276 * @info: A #GDBusArgInfo.
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.
285 g_dbus_arg_info_unref (GDBusArgInfo *info)
287 if (g_atomic_int_get (&info->ref_count) == -1)
289 if (g_atomic_int_dec_and_test (&info->ref_count))
292 g_free (info->signature);
293 free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
299 * g_dbus_method_info_unref:
300 * @info: A #GDBusMethodInfo.
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.
309 g_dbus_method_info_unref (GDBusMethodInfo *info)
311 if (g_atomic_int_get (&info->ref_count) == -1)
313 if (g_atomic_int_dec_and_test (&info->ref_count))
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);
324 * g_dbus_signal_info_unref:
325 * @info: A #GDBusSignalInfo.
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.
334 g_dbus_signal_info_unref (GDBusSignalInfo *info)
336 if (g_atomic_int_get (&info->ref_count) == -1)
338 if (g_atomic_int_dec_and_test (&info->ref_count))
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);
348 * g_dbus_property_info_unref:
349 * @info: A #GDBusPropertyInfo.
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.
358 g_dbus_property_info_unref (GDBusPropertyInfo *info)
360 if (g_atomic_int_get (&info->ref_count) == -1)
362 if (g_atomic_int_dec_and_test (&info->ref_count))
365 g_free (info->signature);
366 free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
372 * g_dbus_interface_info_unref:
373 * @info: A #GDBusInterfaceInfo.
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.
382 g_dbus_interface_info_unref (GDBusInterfaceInfo *info)
384 if (g_atomic_int_get (&info->ref_count) == -1)
386 if (g_atomic_int_dec_and_test (&info->ref_count))
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);
398 * g_dbus_node_info_unref:
399 * @info: A #GDBusNodeInfo.
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.
408 g_dbus_node_info_unref (GDBusNodeInfo *info)
410 if (g_atomic_int_get (&info->ref_count) == -1)
412 if (g_atomic_int_dec_and_test (&info->ref_count))
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);
422 /* ---------------------------------------------------------------------------------------------------- */
425 g_dbus_annotation_info_set (ParseData *data,
426 GDBusAnnotationInfo *info,
429 GDBusAnnotationInfo **embedded_annotations)
434 info->key = g_strdup (key);
437 info->value = g_strdup (value);
439 if (embedded_annotations != NULL)
440 info->annotations = embedded_annotations;
444 g_dbus_arg_info_set (ParseData *data,
447 const gchar *signature,
448 GDBusAnnotationInfo **annotations)
452 /* name may be NULL - TODO: compute name? */
454 info->name = g_strdup (name);
456 if (signature != NULL)
457 info->signature = g_strdup (signature);
459 if (annotations != NULL)
460 info->annotations = annotations;
464 g_dbus_method_info_set (ParseData *data,
465 GDBusMethodInfo *info,
467 GDBusArgInfo **in_args,
468 GDBusArgInfo **out_args,
469 GDBusAnnotationInfo **annotations)
474 info->name = g_strdup (name);
477 info->in_args = in_args;
479 if (out_args != NULL)
480 info->out_args = out_args;
482 if (annotations != NULL)
483 info->annotations = annotations;
487 g_dbus_signal_info_set (ParseData *data,
488 GDBusSignalInfo *info,
491 GDBusAnnotationInfo **annotations)
496 info->name = g_strdup (name);
501 if (annotations != NULL)
502 info->annotations = annotations;
506 g_dbus_property_info_set (ParseData *data,
507 GDBusPropertyInfo *info,
509 const gchar *signature,
510 GDBusPropertyInfoFlags flags,
511 GDBusAnnotationInfo **annotations)
516 info->name = g_strdup (name);
518 if (flags != G_DBUS_PROPERTY_INFO_FLAGS_NONE)
521 if (signature != NULL)
522 info->signature = g_strdup (signature);
524 if (annotations != NULL)
525 info->annotations = annotations;
529 g_dbus_interface_info_set (ParseData *data,
530 GDBusInterfaceInfo *info,
532 GDBusMethodInfo **methods,
533 GDBusSignalInfo **signals,
534 GDBusPropertyInfo **properties,
535 GDBusAnnotationInfo **annotations)
540 info->name = g_strdup (name);
543 info->methods = methods;
546 info->signals = signals;
548 if (properties != NULL)
549 info->properties = properties;
551 if (annotations != NULL)
552 info->annotations = annotations;
556 g_dbus_node_info_set (ParseData *data,
559 GDBusInterfaceInfo **interfaces,
560 GDBusNodeInfo **nodes,
561 GDBusAnnotationInfo **annotations)
567 info->path = g_strdup (path);
568 /* TODO: relative / absolute path snafu */
571 if (interfaces != NULL)
572 info->interfaces = interfaces;
577 if (annotations != NULL)
578 info->annotations = annotations;
581 /* ---------------------------------------------------------------------------------------------------- */
584 g_dbus_annotation_info_generate_xml (GDBusAnnotationInfo *info,
586 GString *string_builder)
591 tmp = g_markup_printf_escaped ("%*s<annotation name=\"%s\" value=\"%s\"",
595 g_string_append (string_builder, tmp);
598 if (info->annotations == NULL)
600 g_string_append (string_builder, "/>\n");
604 g_string_append (string_builder, ">\n");
606 for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
607 g_dbus_annotation_info_generate_xml (info->annotations[n],
611 g_string_append_printf (string_builder, "%*s</annotation>\n",
618 g_dbus_arg_info_generate_xml (GDBusArgInfo *info,
620 const gchar *extra_attributes,
621 GString *string_builder)
625 g_string_append_printf (string_builder, "%*s<arg type=\"%s\"",
629 if (info->name != NULL)
630 g_string_append_printf (string_builder, " name=\"%s\"", info->name);
632 if (extra_attributes != NULL)
633 g_string_append_printf (string_builder, " %s", extra_attributes);
635 if (info->annotations == NULL)
637 g_string_append (string_builder, "/>\n");
641 g_string_append (string_builder, ">\n");
643 for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
644 g_dbus_annotation_info_generate_xml (info->annotations[n],
648 g_string_append_printf (string_builder, "%*s</arg>\n", indent, "");
654 g_dbus_method_info_generate_xml (GDBusMethodInfo *info,
656 GString *string_builder)
660 g_string_append_printf (string_builder, "%*s<method name=\"%s\"",
664 if (info->annotations == NULL && info->in_args == NULL && info->out_args == NULL)
666 g_string_append (string_builder, "/>\n");
670 g_string_append (string_builder, ">\n");
672 for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
673 g_dbus_annotation_info_generate_xml (info->annotations[n],
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],
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],
689 g_string_append_printf (string_builder, "%*s</method>\n", indent, "");
694 g_dbus_signal_info_generate_xml (GDBusSignalInfo *info,
696 GString *string_builder)
700 g_string_append_printf (string_builder, "%*s<signal name=\"%s\"",
704 if (info->annotations == NULL && info->args == NULL)
706 g_string_append (string_builder, "/>\n");
710 g_string_append (string_builder, ">\n");
712 for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
713 g_dbus_annotation_info_generate_xml (info->annotations[n],
717 for (n = 0; info->args != NULL && info->args[n] != NULL; n++)
718 g_dbus_arg_info_generate_xml (info->args[n],
723 g_string_append_printf (string_builder, "%*s</signal>\n", indent, "");
728 g_dbus_property_info_generate_xml (GDBusPropertyInfo *info,
730 GString *string_builder)
733 const gchar *access_string;
735 if ((info->flags & G_DBUS_PROPERTY_INFO_FLAGS_READABLE) &&
736 (info->flags & G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE))
738 access_string = "readwrite";
740 else if (info->flags & G_DBUS_PROPERTY_INFO_FLAGS_READABLE)
742 access_string = "read";
744 else if (info->flags & G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE)
746 access_string = "write";
750 g_assert_not_reached ();
753 g_string_append_printf (string_builder, "%*s<property type=\"%s\" name=\"%s\" access=\"%s\"",
759 if (info->annotations == NULL)
761 g_string_append (string_builder, "/>\n");
765 g_string_append (string_builder, ">\n");
767 for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
768 g_dbus_annotation_info_generate_xml (info->annotations[n],
772 g_string_append_printf (string_builder, "%*s</property>\n", indent, "");
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.
783 * Appends an XML representation of @info (and its children) to @string_builder.
785 * This function is typically used for generating introspection XML
786 * documents at run-time for handling the
787 * `org.freedesktop.DBus.Introspectable.Introspect`
793 g_dbus_interface_info_generate_xml (GDBusInterfaceInfo *info,
795 GString *string_builder)
799 g_string_append_printf (string_builder, "%*s<interface name=\"%s\">\n",
803 for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
804 g_dbus_annotation_info_generate_xml (info->annotations[n],
808 for (n = 0; info->methods != NULL && info->methods[n] != NULL; n++)
809 g_dbus_method_info_generate_xml (info->methods[n],
813 for (n = 0; info->signals != NULL && info->signals[n] != NULL; n++)
814 g_dbus_signal_info_generate_xml (info->signals[n],
818 for (n = 0; info->properties != NULL && info->properties[n] != NULL; n++)
819 g_dbus_property_info_generate_xml (info->properties[n],
823 g_string_append_printf (string_builder, "%*s</interface>\n", indent, "");
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.
832 * Appends an XML representation of @info (and its children) to @string_builder.
834 * This function is typically used for generating introspection XML documents at run-time for
835 * handling the `org.freedesktop.DBus.Introspectable.Introspect` method.
840 g_dbus_node_info_generate_xml (GDBusNodeInfo *info,
842 GString *string_builder)
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);
850 if (info->interfaces == NULL && info->nodes == NULL && info->annotations == NULL)
852 g_string_append (string_builder, "/>\n");
856 g_string_append (string_builder, ">\n");
858 for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
859 g_dbus_annotation_info_generate_xml (info->annotations[n],
863 for (n = 0; info->interfaces != NULL && info->interfaces[n] != NULL; n++)
864 g_dbus_interface_info_generate_xml (info->interfaces[n],
868 for (n = 0; info->nodes != NULL && info->nodes[n] != NULL; n++)
869 g_dbus_node_info_generate_xml (info->nodes[n],
873 g_string_append_printf (string_builder, "%*s</node>\n", indent, "");
877 /* ---------------------------------------------------------------------------------------------------- */
879 static GDBusAnnotationInfo **
880 parse_data_steal_annotations (ParseData *data,
881 guint *out_num_elements)
883 GDBusAnnotationInfo **ret;
884 if (out_num_elements != NULL)
885 *out_num_elements = data->annotations->len;
886 if (data->annotations == NULL)
890 g_ptr_array_add (data->annotations, NULL);
891 ret = (GDBusAnnotationInfo **) g_ptr_array_free (data->annotations, FALSE);
893 data->annotations = g_ptr_array_new ();
897 static GDBusArgInfo **
898 parse_data_steal_args (ParseData *data,
899 guint *out_num_elements)
902 if (out_num_elements != NULL)
903 *out_num_elements = data->args->len;
904 if (data->args == NULL)
908 g_ptr_array_add (data->args, NULL);
909 ret = (GDBusArgInfo **) g_ptr_array_free (data->args, FALSE);
911 data->args = g_ptr_array_new ();
915 static GDBusArgInfo **
916 parse_data_steal_out_args (ParseData *data,
917 guint *out_num_elements)
920 if (out_num_elements != NULL)
921 *out_num_elements = data->out_args->len;
922 if (data->out_args == NULL)
926 g_ptr_array_add (data->out_args, NULL);
927 ret = (GDBusArgInfo **) g_ptr_array_free (data->out_args, FALSE);
929 data->out_args = g_ptr_array_new ();
933 static GDBusMethodInfo **
934 parse_data_steal_methods (ParseData *data,
935 guint *out_num_elements)
937 GDBusMethodInfo **ret;
938 if (out_num_elements != NULL)
939 *out_num_elements = data->methods->len;
940 if (data->methods == NULL)
944 g_ptr_array_add (data->methods, NULL);
945 ret = (GDBusMethodInfo **) g_ptr_array_free (data->methods, FALSE);
947 data->methods = g_ptr_array_new ();
951 static GDBusSignalInfo **
952 parse_data_steal_signals (ParseData *data,
953 guint *out_num_elements)
955 GDBusSignalInfo **ret;
956 if (out_num_elements != NULL)
957 *out_num_elements = data->signals->len;
958 if (data->signals == NULL)
962 g_ptr_array_add (data->signals, NULL);
963 ret = (GDBusSignalInfo **) g_ptr_array_free (data->signals, FALSE);
965 data->signals = g_ptr_array_new ();
969 static GDBusPropertyInfo **
970 parse_data_steal_properties (ParseData *data,
971 guint *out_num_elements)
973 GDBusPropertyInfo **ret;
974 if (out_num_elements != NULL)
975 *out_num_elements = data->properties->len;
976 if (data->properties == NULL)
980 g_ptr_array_add (data->properties, NULL);
981 ret = (GDBusPropertyInfo **) g_ptr_array_free (data->properties, FALSE);
983 data->properties = g_ptr_array_new ();
987 static GDBusInterfaceInfo **
988 parse_data_steal_interfaces (ParseData *data,
989 guint *out_num_elements)
991 GDBusInterfaceInfo **ret;
992 if (out_num_elements != NULL)
993 *out_num_elements = data->interfaces->len;
994 if (data->interfaces == NULL)
998 g_ptr_array_add (data->interfaces, NULL);
999 ret = (GDBusInterfaceInfo **) g_ptr_array_free (data->interfaces, FALSE);
1001 data->interfaces = g_ptr_array_new ();
1005 static GDBusNodeInfo **
1006 parse_data_steal_nodes (ParseData *data,
1007 guint *out_num_elements)
1009 GDBusNodeInfo **ret;
1010 if (out_num_elements != NULL)
1011 *out_num_elements = data->nodes->len;
1012 if (data->nodes == NULL)
1016 g_ptr_array_add (data->nodes, NULL);
1017 ret = (GDBusNodeInfo **) g_ptr_array_free (data->nodes, FALSE);
1019 data->nodes = g_ptr_array_new ();
1023 /* ---------------------------------------------------------------------------------------------------- */
1026 parse_data_free_annotations (ParseData *data)
1028 if (data->annotations == NULL)
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;
1036 parse_data_free_args (ParseData *data)
1038 if (data->args == NULL)
1040 g_ptr_array_foreach (data->args, (GFunc) g_dbus_arg_info_unref, NULL);
1041 g_ptr_array_free (data->args, TRUE);
1046 parse_data_free_out_args (ParseData *data)
1048 if (data->out_args == NULL)
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;
1056 parse_data_free_methods (ParseData *data)
1058 if (data->methods == NULL)
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;
1066 parse_data_free_signals (ParseData *data)
1068 if (data->signals == NULL)
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;
1076 parse_data_free_properties (ParseData *data)
1078 if (data->properties == NULL)
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;
1086 parse_data_free_interfaces (ParseData *data)
1088 if (data->interfaces == NULL)
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;
1096 parse_data_free_nodes (ParseData *data)
1098 if (data->nodes == NULL)
1100 g_ptr_array_foreach (data->nodes, (GFunc) g_dbus_node_info_unref, NULL);
1101 g_ptr_array_free (data->nodes, TRUE);
1105 /* ---------------------------------------------------------------------------------------------------- */
1107 static GDBusAnnotationInfo *
1108 parse_data_get_annotation (ParseData *data,
1109 gboolean create_new)
1112 g_ptr_array_add (data->annotations, g_new0 (GDBusAnnotationInfo, 1));
1113 return data->annotations->pdata[data->annotations->len - 1];
1116 static GDBusArgInfo *
1117 parse_data_get_arg (ParseData *data,
1118 gboolean create_new)
1121 g_ptr_array_add (data->args, g_new0 (GDBusArgInfo, 1));
1122 return data->args->pdata[data->args->len - 1];
1125 static GDBusArgInfo *
1126 parse_data_get_out_arg (ParseData *data,
1127 gboolean 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];
1134 static GDBusMethodInfo *
1135 parse_data_get_method (ParseData *data,
1136 gboolean create_new)
1139 g_ptr_array_add (data->methods, g_new0 (GDBusMethodInfo, 1));
1140 return data->methods->pdata[data->methods->len - 1];
1143 static GDBusSignalInfo *
1144 parse_data_get_signal (ParseData *data,
1145 gboolean create_new)
1148 g_ptr_array_add (data->signals, g_new0 (GDBusSignalInfo, 1));
1149 return data->signals->pdata[data->signals->len - 1];
1152 static GDBusPropertyInfo *
1153 parse_data_get_property (ParseData *data,
1154 gboolean create_new)
1157 g_ptr_array_add (data->properties, g_new0 (GDBusPropertyInfo, 1));
1158 return data->properties->pdata[data->properties->len - 1];
1161 static GDBusInterfaceInfo *
1162 parse_data_get_interface (ParseData *data,
1163 gboolean create_new)
1166 g_ptr_array_add (data->interfaces, g_new0 (GDBusInterfaceInfo, 1));
1167 return data->interfaces->pdata[data->interfaces->len - 1];
1170 static GDBusNodeInfo *
1171 parse_data_get_node (ParseData *data,
1172 gboolean create_new)
1175 g_ptr_array_add (data->nodes, g_new0 (GDBusNodeInfo, 1));
1176 return data->nodes->pdata[data->nodes->len - 1];
1179 /* ---------------------------------------------------------------------------------------------------- */
1182 parse_data_new (void)
1186 data = g_new0 (ParseData, 1);
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);
1202 parse_data_free (ParseData *data)
1206 /* free stack of annotation arrays */
1207 for (l = data->annotations_stack; l != NULL; l = l->next)
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);
1213 g_slist_free (data->annotations_stack);
1215 /* free stack of interface arrays */
1216 for (l = data->interfaces_stack; l != NULL; l = l->next)
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);
1222 g_slist_free (data->interfaces_stack);
1224 /* free stack of node arrays */
1225 for (l = data->nodes_stack; l != NULL; l = l->next)
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);
1231 g_slist_free (data->nodes_stack);
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);
1246 /* ---------------------------------------------------------------------------------------------------- */
1249 parser_start_element (GMarkupParseContext *context,
1250 const gchar *element_name,
1251 const gchar **attribute_names,
1252 const gchar **attribute_values,
1256 ParseData *data = user_data;
1260 const gchar *access;
1261 const gchar *direction;
1270 stack = (GSList *) g_markup_parse_context_get_element_stack (context);
1272 /* ---------------------------------------------------------------------------------------------------- */
1273 if (strcmp (element_name, "node") == 0)
1275 if (!(g_slist_length (stack) >= 1 || strcmp (stack->next->data, "node") != 0))
1277 g_set_error_literal (error,
1279 G_MARKUP_ERROR_INVALID_CONTENT,
1280 "<node> elements can only be top-level or embedded in other <node> elements");
1284 if (!g_markup_collect_attributes (element_name,
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))
1294 g_dbus_node_info_set (data,
1295 parse_data_get_node (data, TRUE),
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);
1306 data->nodes_stack = g_slist_prepend (data->nodes_stack, data->nodes);
1308 parse_data_steal_nodes (data, NULL);
1311 /* ---------------------------------------------------------------------------------------------------- */
1312 else if (strcmp (element_name, "interface") == 0)
1314 if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "node") != 0)
1316 g_set_error_literal (error,
1318 G_MARKUP_ERROR_INVALID_CONTENT,
1319 "<interface> elements can only be embedded in <node> elements");
1323 if (!g_markup_collect_attributes (element_name,
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))
1333 g_dbus_interface_info_set (data,
1334 parse_data_get_interface (data, TRUE),
1342 /* ---------------------------------------------------------------------------------------------------- */
1343 else if (strcmp (element_name, "method") == 0)
1345 if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "interface") != 0)
1347 g_set_error_literal (error,
1349 G_MARKUP_ERROR_INVALID_CONTENT,
1350 "<method> elements can only be embedded in <interface> elements");
1354 if (!g_markup_collect_attributes (element_name,
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))
1364 g_dbus_method_info_set (data,
1365 parse_data_get_method (data, TRUE),
1374 /* ---------------------------------------------------------------------------------------------------- */
1375 else if (strcmp (element_name, "signal") == 0)
1377 if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "interface") != 0)
1379 g_set_error_literal (error,
1381 G_MARKUP_ERROR_INVALID_CONTENT,
1382 "<signal> elements can only be embedded in <interface> elements");
1386 if (!g_markup_collect_attributes (element_name,
1390 G_MARKUP_COLLECT_STRING, "name", &name,
1391 G_MARKUP_COLLECT_INVALID))
1394 g_dbus_signal_info_set (data,
1395 parse_data_get_signal (data, TRUE),
1403 /* ---------------------------------------------------------------------------------------------------- */
1404 else if (strcmp (element_name, "property") == 0)
1406 GDBusPropertyInfoFlags flags;
1408 if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "interface") != 0)
1410 g_set_error_literal (error,
1412 G_MARKUP_ERROR_INVALID_CONTENT,
1413 "<property> elements can only be embedded in <interface> elements");
1417 if (!g_markup_collect_attributes (element_name,
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))
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;
1437 G_MARKUP_ERROR_INVALID_CONTENT,
1438 "Unknown value '%s' of access attribute for element <property>",
1443 g_dbus_property_info_set (data,
1444 parse_data_get_property (data, TRUE),
1451 /* ---------------------------------------------------------------------------------------------------- */
1452 else if (strcmp (element_name, "arg") == 0)
1457 if (g_slist_length (stack) < 2 ||
1458 (strcmp (stack->next->data, "method") != 0 &&
1459 strcmp (stack->next->data, "signal") != 0))
1461 g_set_error_literal (error,
1463 G_MARKUP_ERROR_INVALID_CONTENT,
1464 "<arg> elements can only be embedded in <method> or <signal> elements");
1468 if (!g_markup_collect_attributes (element_name,
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))
1478 if (strcmp (stack->next->data, "method") == 0)
1482 if (direction != NULL)
1484 if (strcmp (direction, "in") == 0)
1486 else if (strcmp (direction, "out") == 0)
1492 G_MARKUP_ERROR_INVALID_CONTENT,
1493 "Unknown value '%s' of direction attribute",
1499 if (is_in && strcmp (stack->next->data, "signal") == 0)
1501 g_set_error_literal (error,
1503 G_MARKUP_ERROR_INVALID_CONTENT,
1504 "Only direction 'out' is allowed for <arg> elements embedded in <signal>");
1509 name_to_use = g_strdup_printf ("arg_%d", data->num_args);
1511 name_to_use = g_strdup (name);
1516 g_dbus_arg_info_set (data,
1517 parse_data_get_arg (data, TRUE),
1521 data->last_arg_was_in = TRUE;
1525 g_dbus_arg_info_set (data,
1526 parse_data_get_out_arg (data, TRUE),
1530 data->last_arg_was_in = FALSE;
1534 g_free (name_to_use);
1536 /* ---------------------------------------------------------------------------------------------------- */
1537 else if (strcmp (element_name, "annotation") == 0)
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))
1548 g_set_error_literal (error,
1550 G_MARKUP_ERROR_INVALID_CONTENT,
1551 "<annotation> elements can only be embedded in <node>, <interface>, <signal>, <method>, <property>, <arg> or <annotation> elements");
1555 if (!g_markup_collect_attributes (element_name,
1559 G_MARKUP_COLLECT_STRING, "name", &name,
1560 G_MARKUP_COLLECT_STRING, "value", &value,
1561 G_MARKUP_COLLECT_INVALID))
1564 g_dbus_annotation_info_set (data,
1565 parse_data_get_annotation (data, TRUE),
1570 /* ---------------------------------------------------------------------------------------------------- */
1573 /* don't bail on unknown elements; just ignore them */
1575 /* ---------------------------------------------------------------------------------------------------- */
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);
1586 /* ---------------------------------------------------------------------------------------------------- */
1588 static GDBusAnnotationInfo **
1589 steal_annotations (ParseData *data)
1591 return parse_data_steal_annotations (data, NULL);
1596 parser_end_element (GMarkupParseContext *context,
1597 const gchar *element_name,
1601 ParseData *data = user_data;
1602 gboolean have_popped_annotations;
1604 have_popped_annotations = FALSE;
1606 if (strcmp (element_name, "node") == 0)
1609 guint num_interfaces;
1610 GDBusNodeInfo **nodes;
1611 GDBusInterfaceInfo **interfaces;
1613 nodes = parse_data_steal_nodes (data, &num_nodes);
1614 interfaces = parse_data_steal_interfaces (data, &num_interfaces);
1616 /* destroy the nodes, interfaces for scope we're exiting and pop the nodes, interfaces from the
1617 * scope we're reentering
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);
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);
1627 g_dbus_node_info_set (data,
1628 parse_data_get_node (data, FALSE),
1632 steal_annotations (data));
1635 else if (strcmp (element_name, "interface") == 0)
1639 guint num_properties;
1640 GDBusMethodInfo **methods;
1641 GDBusSignalInfo **signals;
1642 GDBusPropertyInfo **properties;
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);
1648 g_dbus_interface_info_set (data,
1649 parse_data_get_interface (data, FALSE),
1654 steal_annotations (data));
1657 else if (strcmp (element_name, "method") == 0)
1661 GDBusArgInfo **in_args;
1662 GDBusArgInfo **out_args;
1664 in_args = parse_data_steal_args (data, &in_num_args);
1665 out_args = parse_data_steal_out_args (data, &out_num_args);
1667 g_dbus_method_info_set (data,
1668 parse_data_get_method (data, FALSE),
1672 steal_annotations (data));
1674 else if (strcmp (element_name, "signal") == 0)
1677 GDBusArgInfo **args;
1679 args = parse_data_steal_out_args (data, &num_args);
1681 g_dbus_signal_info_set (data,
1682 parse_data_get_signal (data, FALSE),
1685 steal_annotations (data));
1687 else if (strcmp (element_name, "property") == 0)
1689 g_dbus_property_info_set (data,
1690 parse_data_get_property (data, FALSE),
1693 G_DBUS_PROPERTY_INFO_FLAGS_NONE,
1694 steal_annotations (data));
1696 else if (strcmp (element_name, "arg") == 0)
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),
1702 steal_annotations (data));
1704 else if (strcmp (element_name, "annotation") == 0)
1706 GDBusAnnotationInfo **embedded_annotations;
1708 embedded_annotations = steal_annotations (data);
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);
1715 have_popped_annotations = TRUE;
1717 g_dbus_annotation_info_set (data,
1718 parse_data_get_annotation (data, FALSE),
1721 embedded_annotations);
1725 /* don't bail on unknown elements; just ignore them */
1728 if (!have_popped_annotations)
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);
1737 /* ---------------------------------------------------------------------------------------------------- */
1740 parser_error (GMarkupParseContext *context,
1747 g_markup_parse_context_get_position (context, &line_number, &char_number);
1749 g_prefix_error (&error, "%d:%d: ",
1754 /* ---------------------------------------------------------------------------------------------------- */
1757 * g_dbus_node_info_new_for_xml:
1758 * @xml_data: Valid D-Bus introspection XML.
1759 * @error: Return location for error.
1761 * Parses @xml_data and returns a #GDBusNodeInfo representing the data.
1763 * The introspection XML must contain exactly one top-level
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.
1770 * Returns: A #GDBusNodeInfo structure or %NULL if @error is set. Free
1771 * with g_dbus_node_info_unref().
1776 g_dbus_node_info_new_for_xml (const gchar *xml_data,
1780 GMarkupParseContext *context;
1781 GMarkupParser *parser;
1784 GDBusNodeInfo **ughret;
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;
1795 data = parse_data_new ();
1796 context = g_markup_parse_context_new (parser,
1797 G_MARKUP_IGNORE_QUALIFIED,
1799 (GDestroyNotify) parse_data_free);
1801 if (!g_markup_parse_context_parse (context,
1807 if (!g_markup_parse_context_end_parse (context, error))
1810 ughret = parse_data_steal_nodes (data, &num_nodes);
1818 G_MARKUP_ERROR_INVALID_CONTENT,
1819 "Expected a single node in introspection XML, found %d",
1823 for (n = 0; n < num_nodes; n++)
1825 g_dbus_node_info_unref (ughret[n]);
1835 if (context != NULL)
1836 g_markup_parse_context_free (context);
1841 /* ---------------------------------------------------------------------------------------------------- */
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.
1848 * Looks up the value of an annotation.
1850 * The cost of this function is O(n) in number of annotations.
1852 * Returns: (nullable): The value or %NULL if not found. Do not free, it is owned by @annotations.
1857 g_dbus_annotation_info_lookup (GDBusAnnotationInfo **annotations,
1864 for (n = 0; annotations != NULL && annotations[n] != NULL; n++)
1866 if (g_strcmp0 (annotations[n]->key, name) == 0)
1868 ret = annotations[n]->value;
1877 /* ---------------------------------------------------------------------------------------------------- */
1879 G_LOCK_DEFINE_STATIC (info_cache_lock);
1885 /* gchar* -> GDBusMethodInfo* */
1886 GHashTable *method_name_to_data;
1888 /* gchar* -> GDBusMethodInfo* */
1889 GHashTable *signal_name_to_data;
1891 /* gchar* -> GDBusMethodInfo* */
1892 GHashTable *property_name_to_data;
1896 info_cache_free (InfoCacheEntry *cache)
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);
1905 /* maps from GDBusInterfaceInfo* to InfoCacheEntry* */
1906 static GHashTable *info_cache = NULL;
1908 /* ---------------------------------------------------------------------------------------------------- */
1911 * g_dbus_interface_info_lookup_method:
1912 * @info: A #GDBusInterfaceInfo.
1913 * @name: A D-Bus method name (typically in CamelCase)
1915 * Looks up information about a method.
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.
1920 * Returns: (nullable) (transfer none): A #GDBusMethodInfo or %NULL if not found. Do not free, it is owned by @info.
1925 g_dbus_interface_info_lookup_method (GDBusInterfaceInfo *info,
1929 GDBusMethodInfo *result;
1931 G_LOCK (info_cache_lock);
1932 if (G_LIKELY (info_cache != NULL))
1934 InfoCacheEntry *cache;
1935 cache = g_hash_table_lookup (info_cache, info);
1936 if (G_LIKELY (cache != NULL))
1938 result = g_hash_table_lookup (cache->method_name_to_data, name);
1939 G_UNLOCK (info_cache_lock);
1943 G_UNLOCK (info_cache_lock);
1945 for (n = 0; info->methods != NULL && info->methods[n] != NULL; n++)
1947 GDBusMethodInfo *i = info->methods[n];
1949 if (g_strcmp0 (i->name, name) == 0)
1962 /* ---------------------------------------------------------------------------------------------------- */
1965 * g_dbus_interface_info_lookup_signal:
1966 * @info: A #GDBusInterfaceInfo.
1967 * @name: A D-Bus signal name (typically in CamelCase)
1969 * Looks up information about a signal.
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.
1974 * Returns: (nullable) (transfer none): A #GDBusSignalInfo or %NULL if not found. Do not free, it is owned by @info.
1979 g_dbus_interface_info_lookup_signal (GDBusInterfaceInfo *info,
1983 GDBusSignalInfo *result;
1985 G_LOCK (info_cache_lock);
1986 if (G_LIKELY (info_cache != NULL))
1988 InfoCacheEntry *cache;
1989 cache = g_hash_table_lookup (info_cache, info);
1990 if (G_LIKELY (cache != NULL))
1992 result = g_hash_table_lookup (cache->signal_name_to_data, name);
1993 G_UNLOCK (info_cache_lock);
1997 G_UNLOCK (info_cache_lock);
1999 for (n = 0; info->signals != NULL && info->signals[n] != NULL; n++)
2001 GDBusSignalInfo *i = info->signals[n];
2003 if (g_strcmp0 (i->name, name) == 0)
2016 /* ---------------------------------------------------------------------------------------------------- */
2019 * g_dbus_interface_info_lookup_property:
2020 * @info: A #GDBusInterfaceInfo.
2021 * @name: A D-Bus property name (typically in CamelCase).
2023 * Looks up information about a property.
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.
2028 * Returns: (nullable) (transfer none): A #GDBusPropertyInfo or %NULL if not found. Do not free, it is owned by @info.
2033 g_dbus_interface_info_lookup_property (GDBusInterfaceInfo *info,
2037 GDBusPropertyInfo *result;
2039 G_LOCK (info_cache_lock);
2040 if (G_LIKELY (info_cache != NULL))
2042 InfoCacheEntry *cache;
2043 cache = g_hash_table_lookup (info_cache, info);
2044 if (G_LIKELY (cache != NULL))
2046 result = g_hash_table_lookup (cache->property_name_to_data, name);
2047 G_UNLOCK (info_cache_lock);
2051 G_UNLOCK (info_cache_lock);
2053 for (n = 0; info->properties != NULL && info->properties[n] != NULL; n++)
2055 GDBusPropertyInfo *i = info->properties[n];
2057 if (g_strcmp0 (i->name, name) == 0)
2070 /* ---------------------------------------------------------------------------------------------------- */
2073 * g_dbus_interface_info_cache_build:
2074 * @info: A #GDBusInterfaceInfo.
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().
2081 * If this has already been called with @info, the existing cache is
2082 * used and its use count is increased.
2084 * Note that @info cannot be modified until
2085 * g_dbus_interface_info_cache_release() is called.
2090 g_dbus_interface_info_cache_build (GDBusInterfaceInfo *info)
2092 InfoCacheEntry *cache;
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);
2101 cache->use_count += 1;
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);
2117 G_UNLOCK (info_cache_lock);
2121 * g_dbus_interface_info_cache_release:
2122 * @info: A GDBusInterfaceInfo
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.
2131 g_dbus_interface_info_cache_release (GDBusInterfaceInfo *info)
2133 InfoCacheEntry *cache;
2135 G_LOCK (info_cache_lock);
2136 if (G_UNLIKELY (info_cache == NULL))
2138 g_warning ("%s called for interface %s but there is no cache", info->name, G_STRFUNC);
2142 cache = g_hash_table_lookup (info_cache, info);
2143 if (G_UNLIKELY (cache == NULL))
2145 g_warning ("%s called for interface %s but there is no cache entry", info->name, G_STRFUNC);
2148 cache->use_count -= 1;
2149 if (cache->use_count == 0)
2151 g_hash_table_remove (info_cache, info);
2152 /* could nuke info_cache itself if empty */
2155 G_UNLOCK (info_cache_lock);
2159 /* ---------------------------------------------------------------------------------------------------- */
2162 * g_dbus_node_info_lookup_interface:
2163 * @info: A #GDBusNodeInfo.
2164 * @name: A D-Bus interface name.
2166 * Looks up information about an interface.
2168 * The cost of this function is O(n) in number of interfaces.
2170 * Returns: (nullable) (transfer none): A #GDBusInterfaceInfo or %NULL if not found. Do not free, it is owned by @info.
2174 GDBusInterfaceInfo *
2175 g_dbus_node_info_lookup_interface (GDBusNodeInfo *info,
2179 GDBusInterfaceInfo *result;
2181 for (n = 0; info->interfaces != NULL && info->interfaces[n] != NULL; n++)
2183 GDBusInterfaceInfo *i = info->interfaces[n];
2185 if (g_strcmp0 (i->name, name) == 0)