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"
32 /* ---------------------------------------------------------------------------------------------------- */
34 #define _MY_DEFINE_BOXED_TYPE(TypeName, type_name) \
35 G_DEFINE_BOXED_TYPE (TypeName, type_name, type_name##_ref, type_name##_unref)
37 _MY_DEFINE_BOXED_TYPE (GDBusNodeInfo, g_dbus_node_info)
38 _MY_DEFINE_BOXED_TYPE (GDBusInterfaceInfo, g_dbus_interface_info)
39 _MY_DEFINE_BOXED_TYPE (GDBusMethodInfo, g_dbus_method_info)
40 _MY_DEFINE_BOXED_TYPE (GDBusSignalInfo, g_dbus_signal_info)
41 _MY_DEFINE_BOXED_TYPE (GDBusPropertyInfo, g_dbus_property_info)
42 _MY_DEFINE_BOXED_TYPE (GDBusArgInfo, g_dbus_arg_info)
43 _MY_DEFINE_BOXED_TYPE (GDBusAnnotationInfo, g_dbus_annotation_info)
45 #undef _MY_DEFINE_BOXED_TYPE
47 /* ---------------------------------------------------------------------------------------------------- */
51 /* stuff we are currently collecting */
56 GPtrArray *properties;
57 GPtrArray *interfaces;
59 GPtrArray *annotations;
61 /* A list of GPtrArray's containing annotations */
62 GSList *annotations_stack;
64 /* A list of GPtrArray's containing interfaces */
65 GSList *interfaces_stack;
67 /* A list of GPtrArray's containing nodes */
70 /* Whether the direction was "in" for last parsed arg */
71 gboolean last_arg_was_in;
73 /* Number of args currently being collected; used for assigning
74 * names to args without a "name" attribute
80 /* ---------------------------------------------------------------------------------------------------- */
83 * g_dbus_node_info_ref:
84 * @info: A #GDBusNodeInfo
86 * If @info is statically allocated does nothing. Otherwise increases
87 * the reference count.
89 * Returns: (not nullable): The same @info.
94 g_dbus_node_info_ref (GDBusNodeInfo *info)
96 if (g_atomic_int_get (&info->ref_count) == -1)
98 g_atomic_int_inc (&info->ref_count);
103 * g_dbus_interface_info_ref:
104 * @info: A #GDBusInterfaceInfo
106 * If @info is statically allocated does nothing. Otherwise increases
107 * the reference count.
109 * Returns: (not nullable): The same @info.
114 g_dbus_interface_info_ref (GDBusInterfaceInfo *info)
116 if (g_atomic_int_get (&info->ref_count) == -1)
118 g_atomic_int_inc (&info->ref_count);
123 * g_dbus_method_info_ref:
124 * @info: A #GDBusMethodInfo
126 * If @info is statically allocated does nothing. Otherwise increases
127 * the reference count.
129 * Returns: (not nullable): The same @info.
134 g_dbus_method_info_ref (GDBusMethodInfo *info)
136 if (g_atomic_int_get (&info->ref_count) == -1)
138 g_atomic_int_inc (&info->ref_count);
143 * g_dbus_signal_info_ref:
144 * @info: A #GDBusSignalInfo
146 * If @info is statically allocated does nothing. Otherwise increases
147 * the reference count.
149 * Returns: (not nullable): The same @info.
154 g_dbus_signal_info_ref (GDBusSignalInfo *info)
156 if (g_atomic_int_get (&info->ref_count) == -1)
158 g_atomic_int_inc (&info->ref_count);
163 * g_dbus_property_info_ref:
164 * @info: A #GDBusPropertyInfo
166 * If @info is statically allocated does nothing. Otherwise increases
167 * the reference count.
169 * Returns: (not nullable): The same @info.
174 g_dbus_property_info_ref (GDBusPropertyInfo *info)
176 if (g_atomic_int_get (&info->ref_count) == -1)
178 g_atomic_int_inc (&info->ref_count);
183 * g_dbus_arg_info_ref:
184 * @info: A #GDBusArgInfo
186 * If @info is statically allocated does nothing. Otherwise increases
187 * the reference count.
189 * Returns: (not nullable): The same @info.
194 g_dbus_arg_info_ref (GDBusArgInfo *info)
196 if (g_atomic_int_get (&info->ref_count) == -1)
198 g_atomic_int_inc (&info->ref_count);
203 * g_dbus_annotation_info_ref:
204 * @info: A #GDBusNodeInfo
206 * If @info is statically allocated does nothing. Otherwise increases
207 * the reference count.
209 * Returns: (not nullable): The same @info.
213 GDBusAnnotationInfo *
214 g_dbus_annotation_info_ref (GDBusAnnotationInfo *info)
216 if (g_atomic_int_get (&info->ref_count) == -1)
218 g_atomic_int_inc (&info->ref_count);
222 /* ---------------------------------------------------------------------------------------------------- */
225 free_null_terminated_array (gpointer array, GDestroyNotify unref_func)
231 for (n = 0; p[n] != NULL; n++)
237 * g_dbus_annotation_info_unref:
238 * @info: A #GDBusAnnotationInfo.
240 * If @info is statically allocated, does nothing. Otherwise decreases
241 * the reference count of @info. When its reference count drops to 0,
242 * the memory used is freed.
247 g_dbus_annotation_info_unref (GDBusAnnotationInfo *info)
249 if (g_atomic_int_get (&info->ref_count) == -1)
251 if (g_atomic_int_dec_and_test (&info->ref_count))
254 g_free (info->value);
255 free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
261 * g_dbus_arg_info_unref:
262 * @info: A #GDBusArgInfo.
264 * If @info is statically allocated, does nothing. Otherwise decreases
265 * the reference count of @info. When its reference count drops to 0,
266 * the memory used is freed.
271 g_dbus_arg_info_unref (GDBusArgInfo *info)
273 if (g_atomic_int_get (&info->ref_count) == -1)
275 if (g_atomic_int_dec_and_test (&info->ref_count))
278 g_free (info->signature);
279 free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
285 * g_dbus_method_info_unref:
286 * @info: A #GDBusMethodInfo.
288 * If @info is statically allocated, does nothing. Otherwise decreases
289 * the reference count of @info. When its reference count drops to 0,
290 * the memory used is freed.
295 g_dbus_method_info_unref (GDBusMethodInfo *info)
297 if (g_atomic_int_get (&info->ref_count) == -1)
299 if (g_atomic_int_dec_and_test (&info->ref_count))
302 free_null_terminated_array (info->in_args, (GDestroyNotify) g_dbus_arg_info_unref);
303 free_null_terminated_array (info->out_args, (GDestroyNotify) g_dbus_arg_info_unref);
304 free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
310 * g_dbus_signal_info_unref:
311 * @info: A #GDBusSignalInfo.
313 * If @info is statically allocated, does nothing. Otherwise decreases
314 * the reference count of @info. When its reference count drops to 0,
315 * the memory used is freed.
320 g_dbus_signal_info_unref (GDBusSignalInfo *info)
322 if (g_atomic_int_get (&info->ref_count) == -1)
324 if (g_atomic_int_dec_and_test (&info->ref_count))
327 free_null_terminated_array (info->args, (GDestroyNotify) g_dbus_arg_info_unref);
328 free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
334 * g_dbus_property_info_unref:
335 * @info: A #GDBusPropertyInfo.
337 * If @info is statically allocated, does nothing. Otherwise decreases
338 * the reference count of @info. When its reference count drops to 0,
339 * the memory used is freed.
344 g_dbus_property_info_unref (GDBusPropertyInfo *info)
346 if (g_atomic_int_get (&info->ref_count) == -1)
348 if (g_atomic_int_dec_and_test (&info->ref_count))
351 g_free (info->signature);
352 free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
358 * g_dbus_interface_info_unref:
359 * @info: A #GDBusInterfaceInfo.
361 * If @info is statically allocated, does nothing. Otherwise decreases
362 * the reference count of @info. When its reference count drops to 0,
363 * the memory used is freed.
368 g_dbus_interface_info_unref (GDBusInterfaceInfo *info)
370 if (g_atomic_int_get (&info->ref_count) == -1)
372 if (g_atomic_int_dec_and_test (&info->ref_count))
375 free_null_terminated_array (info->methods, (GDestroyNotify) g_dbus_method_info_unref);
376 free_null_terminated_array (info->signals, (GDestroyNotify) g_dbus_signal_info_unref);
377 free_null_terminated_array (info->properties, (GDestroyNotify) g_dbus_property_info_unref);
378 free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
384 * g_dbus_node_info_unref:
385 * @info: A #GDBusNodeInfo.
387 * If @info is statically allocated, does nothing. Otherwise decreases
388 * the reference count of @info. When its reference count drops to 0,
389 * the memory used is freed.
394 g_dbus_node_info_unref (GDBusNodeInfo *info)
396 if (g_atomic_int_get (&info->ref_count) == -1)
398 if (g_atomic_int_dec_and_test (&info->ref_count))
401 free_null_terminated_array (info->interfaces, (GDestroyNotify) g_dbus_interface_info_unref);
402 free_null_terminated_array (info->nodes, (GDestroyNotify) g_dbus_node_info_unref);
403 free_null_terminated_array (info->annotations, (GDestroyNotify) g_dbus_annotation_info_unref);
408 /* ---------------------------------------------------------------------------------------------------- */
411 g_dbus_annotation_info_set (ParseData *data,
412 GDBusAnnotationInfo *info,
415 GDBusAnnotationInfo **embedded_annotations)
420 info->key = g_strdup (key);
423 info->value = g_strdup (value);
425 if (embedded_annotations != NULL)
426 info->annotations = embedded_annotations;
430 g_dbus_arg_info_set (ParseData *data,
433 const gchar *signature,
434 GDBusAnnotationInfo **annotations)
438 /* name may be NULL - TODO: compute name? */
440 info->name = g_strdup (name);
442 if (signature != NULL)
443 info->signature = g_strdup (signature);
445 if (annotations != NULL)
446 info->annotations = annotations;
450 g_dbus_method_info_set (ParseData *data,
451 GDBusMethodInfo *info,
453 GDBusArgInfo **in_args,
454 GDBusArgInfo **out_args,
455 GDBusAnnotationInfo **annotations)
460 info->name = g_strdup (name);
463 info->in_args = in_args;
465 if (out_args != NULL)
466 info->out_args = out_args;
468 if (annotations != NULL)
469 info->annotations = annotations;
473 g_dbus_signal_info_set (ParseData *data,
474 GDBusSignalInfo *info,
477 GDBusAnnotationInfo **annotations)
482 info->name = g_strdup (name);
487 if (annotations != NULL)
488 info->annotations = annotations;
492 g_dbus_property_info_set (ParseData *data,
493 GDBusPropertyInfo *info,
495 const gchar *signature,
496 GDBusPropertyInfoFlags flags,
497 GDBusAnnotationInfo **annotations)
502 info->name = g_strdup (name);
504 if (flags != G_DBUS_PROPERTY_INFO_FLAGS_NONE)
507 if (signature != NULL)
508 info->signature = g_strdup (signature);
510 if (annotations != NULL)
511 info->annotations = annotations;
515 g_dbus_interface_info_set (ParseData *data,
516 GDBusInterfaceInfo *info,
518 GDBusMethodInfo **methods,
519 GDBusSignalInfo **signals,
520 GDBusPropertyInfo **properties,
521 GDBusAnnotationInfo **annotations)
526 info->name = g_strdup (name);
529 info->methods = methods;
532 info->signals = signals;
534 if (properties != NULL)
535 info->properties = properties;
537 if (annotations != NULL)
538 info->annotations = annotations;
542 g_dbus_node_info_set (ParseData *data,
545 GDBusInterfaceInfo **interfaces,
546 GDBusNodeInfo **nodes,
547 GDBusAnnotationInfo **annotations)
553 info->path = g_strdup (path);
554 /* TODO: relative / absolute path snafu */
557 if (interfaces != NULL)
558 info->interfaces = interfaces;
563 if (annotations != NULL)
564 info->annotations = annotations;
567 /* ---------------------------------------------------------------------------------------------------- */
570 g_dbus_annotation_info_generate_xml (GDBusAnnotationInfo *info,
572 GString *string_builder)
577 tmp = g_markup_printf_escaped ("%*s<annotation name=\"%s\" value=\"%s\"",
581 g_string_append (string_builder, tmp);
584 if (info->annotations == NULL)
586 g_string_append (string_builder, "/>\n");
590 g_string_append (string_builder, ">\n");
592 for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
593 g_dbus_annotation_info_generate_xml (info->annotations[n],
597 g_string_append_printf (string_builder, "%*s</annotation>\n",
604 g_dbus_arg_info_generate_xml (GDBusArgInfo *info,
606 const gchar *extra_attributes,
607 GString *string_builder)
611 g_string_append_printf (string_builder, "%*s<arg type=\"%s\"",
615 if (info->name != NULL)
616 g_string_append_printf (string_builder, " name=\"%s\"", info->name);
618 if (extra_attributes != NULL)
619 g_string_append_printf (string_builder, " %s", extra_attributes);
621 if (info->annotations == NULL)
623 g_string_append (string_builder, "/>\n");
627 g_string_append (string_builder, ">\n");
629 for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
630 g_dbus_annotation_info_generate_xml (info->annotations[n],
634 g_string_append_printf (string_builder, "%*s</arg>\n", indent, "");
640 g_dbus_method_info_generate_xml (GDBusMethodInfo *info,
642 GString *string_builder)
646 g_string_append_printf (string_builder, "%*s<method name=\"%s\"",
650 if (info->annotations == NULL && info->in_args == NULL && info->out_args == NULL)
652 g_string_append (string_builder, "/>\n");
656 g_string_append (string_builder, ">\n");
658 for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
659 g_dbus_annotation_info_generate_xml (info->annotations[n],
663 for (n = 0; info->in_args != NULL && info->in_args[n] != NULL; n++)
664 g_dbus_arg_info_generate_xml (info->in_args[n],
669 for (n = 0; info->out_args != NULL && info->out_args[n] != NULL; n++)
670 g_dbus_arg_info_generate_xml (info->out_args[n],
675 g_string_append_printf (string_builder, "%*s</method>\n", indent, "");
680 g_dbus_signal_info_generate_xml (GDBusSignalInfo *info,
682 GString *string_builder)
686 g_string_append_printf (string_builder, "%*s<signal name=\"%s\"",
690 if (info->annotations == NULL && info->args == NULL)
692 g_string_append (string_builder, "/>\n");
696 g_string_append (string_builder, ">\n");
698 for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
699 g_dbus_annotation_info_generate_xml (info->annotations[n],
703 for (n = 0; info->args != NULL && info->args[n] != NULL; n++)
704 g_dbus_arg_info_generate_xml (info->args[n],
709 g_string_append_printf (string_builder, "%*s</signal>\n", indent, "");
714 g_dbus_property_info_generate_xml (GDBusPropertyInfo *info,
716 GString *string_builder)
719 const gchar *access_string;
721 if ((info->flags & G_DBUS_PROPERTY_INFO_FLAGS_READABLE) &&
722 (info->flags & G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE))
724 access_string = "readwrite";
726 else if (info->flags & G_DBUS_PROPERTY_INFO_FLAGS_READABLE)
728 access_string = "read";
730 else if (info->flags & G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE)
732 access_string = "write";
736 g_assert_not_reached ();
739 g_string_append_printf (string_builder, "%*s<property type=\"%s\" name=\"%s\" access=\"%s\"",
745 if (info->annotations == NULL)
747 g_string_append (string_builder, "/>\n");
751 g_string_append (string_builder, ">\n");
753 for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
754 g_dbus_annotation_info_generate_xml (info->annotations[n],
758 g_string_append_printf (string_builder, "%*s</property>\n", indent, "");
764 * g_dbus_interface_info_generate_xml:
765 * @info: A #GDBusNodeInfo
766 * @indent: Indentation level.
767 * @string_builder: A #GString to to append XML data to.
769 * Appends an XML representation of @info (and its children) to @string_builder.
771 * This function is typically used for generating introspection XML
772 * documents at run-time for handling the
773 * `org.freedesktop.DBus.Introspectable.Introspect`
779 g_dbus_interface_info_generate_xml (GDBusInterfaceInfo *info,
781 GString *string_builder)
785 g_string_append_printf (string_builder, "%*s<interface name=\"%s\">\n",
789 for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
790 g_dbus_annotation_info_generate_xml (info->annotations[n],
794 for (n = 0; info->methods != NULL && info->methods[n] != NULL; n++)
795 g_dbus_method_info_generate_xml (info->methods[n],
799 for (n = 0; info->signals != NULL && info->signals[n] != NULL; n++)
800 g_dbus_signal_info_generate_xml (info->signals[n],
804 for (n = 0; info->properties != NULL && info->properties[n] != NULL; n++)
805 g_dbus_property_info_generate_xml (info->properties[n],
809 g_string_append_printf (string_builder, "%*s</interface>\n", indent, "");
813 * g_dbus_node_info_generate_xml:
814 * @info: A #GDBusNodeInfo.
815 * @indent: Indentation level.
816 * @string_builder: A #GString to to append XML data to.
818 * Appends an XML representation of @info (and its children) to @string_builder.
820 * This function is typically used for generating introspection XML documents at run-time for
821 * handling the `org.freedesktop.DBus.Introspectable.Introspect` method.
826 g_dbus_node_info_generate_xml (GDBusNodeInfo *info,
828 GString *string_builder)
832 g_string_append_printf (string_builder, "%*s<node", indent, "");
833 if (info->path != NULL)
834 g_string_append_printf (string_builder, " name=\"%s\"", info->path);
836 if (info->interfaces == NULL && info->nodes == NULL && info->annotations == NULL)
838 g_string_append (string_builder, "/>\n");
842 g_string_append (string_builder, ">\n");
844 for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++)
845 g_dbus_annotation_info_generate_xml (info->annotations[n],
849 for (n = 0; info->interfaces != NULL && info->interfaces[n] != NULL; n++)
850 g_dbus_interface_info_generate_xml (info->interfaces[n],
854 for (n = 0; info->nodes != NULL && info->nodes[n] != NULL; n++)
855 g_dbus_node_info_generate_xml (info->nodes[n],
859 g_string_append_printf (string_builder, "%*s</node>\n", indent, "");
863 /* ---------------------------------------------------------------------------------------------------- */
865 static GDBusAnnotationInfo **
866 parse_data_steal_annotations (ParseData *data,
867 guint *out_num_elements)
869 GDBusAnnotationInfo **ret;
870 if (out_num_elements != NULL)
871 *out_num_elements = data->annotations->len;
872 if (data->annotations == NULL)
876 g_ptr_array_add (data->annotations, NULL);
877 ret = (GDBusAnnotationInfo **) g_ptr_array_free (data->annotations, FALSE);
879 data->annotations = g_ptr_array_new ();
883 static GDBusArgInfo **
884 parse_data_steal_args (ParseData *data,
885 guint *out_num_elements)
888 if (out_num_elements != NULL)
889 *out_num_elements = data->args->len;
890 if (data->args == NULL)
894 g_ptr_array_add (data->args, NULL);
895 ret = (GDBusArgInfo **) g_ptr_array_free (data->args, FALSE);
897 data->args = g_ptr_array_new ();
901 static GDBusArgInfo **
902 parse_data_steal_out_args (ParseData *data,
903 guint *out_num_elements)
906 if (out_num_elements != NULL)
907 *out_num_elements = data->out_args->len;
908 if (data->out_args == NULL)
912 g_ptr_array_add (data->out_args, NULL);
913 ret = (GDBusArgInfo **) g_ptr_array_free (data->out_args, FALSE);
915 data->out_args = g_ptr_array_new ();
919 static GDBusMethodInfo **
920 parse_data_steal_methods (ParseData *data,
921 guint *out_num_elements)
923 GDBusMethodInfo **ret;
924 if (out_num_elements != NULL)
925 *out_num_elements = data->methods->len;
926 if (data->methods == NULL)
930 g_ptr_array_add (data->methods, NULL);
931 ret = (GDBusMethodInfo **) g_ptr_array_free (data->methods, FALSE);
933 data->methods = g_ptr_array_new ();
937 static GDBusSignalInfo **
938 parse_data_steal_signals (ParseData *data,
939 guint *out_num_elements)
941 GDBusSignalInfo **ret;
942 if (out_num_elements != NULL)
943 *out_num_elements = data->signals->len;
944 if (data->signals == NULL)
948 g_ptr_array_add (data->signals, NULL);
949 ret = (GDBusSignalInfo **) g_ptr_array_free (data->signals, FALSE);
951 data->signals = g_ptr_array_new ();
955 static GDBusPropertyInfo **
956 parse_data_steal_properties (ParseData *data,
957 guint *out_num_elements)
959 GDBusPropertyInfo **ret;
960 if (out_num_elements != NULL)
961 *out_num_elements = data->properties->len;
962 if (data->properties == NULL)
966 g_ptr_array_add (data->properties, NULL);
967 ret = (GDBusPropertyInfo **) g_ptr_array_free (data->properties, FALSE);
969 data->properties = g_ptr_array_new ();
973 static GDBusInterfaceInfo **
974 parse_data_steal_interfaces (ParseData *data,
975 guint *out_num_elements)
977 GDBusInterfaceInfo **ret;
978 if (out_num_elements != NULL)
979 *out_num_elements = data->interfaces->len;
980 if (data->interfaces == NULL)
984 g_ptr_array_add (data->interfaces, NULL);
985 ret = (GDBusInterfaceInfo **) g_ptr_array_free (data->interfaces, FALSE);
987 data->interfaces = g_ptr_array_new ();
991 static GDBusNodeInfo **
992 parse_data_steal_nodes (ParseData *data,
993 guint *out_num_elements)
996 if (out_num_elements != NULL)
997 *out_num_elements = data->nodes->len;
998 if (data->nodes == NULL)
1002 g_ptr_array_add (data->nodes, NULL);
1003 ret = (GDBusNodeInfo **) g_ptr_array_free (data->nodes, FALSE);
1005 data->nodes = g_ptr_array_new ();
1009 /* ---------------------------------------------------------------------------------------------------- */
1012 parse_data_free_annotations (ParseData *data)
1014 if (data->annotations == NULL)
1016 g_ptr_array_foreach (data->annotations, (GFunc) g_dbus_annotation_info_unref, NULL);
1017 g_ptr_array_free (data->annotations, TRUE);
1018 data->annotations = NULL;
1022 parse_data_free_args (ParseData *data)
1024 if (data->args == NULL)
1026 g_ptr_array_foreach (data->args, (GFunc) g_dbus_arg_info_unref, NULL);
1027 g_ptr_array_free (data->args, TRUE);
1032 parse_data_free_out_args (ParseData *data)
1034 if (data->out_args == NULL)
1036 g_ptr_array_foreach (data->out_args, (GFunc) g_dbus_arg_info_unref, NULL);
1037 g_ptr_array_free (data->out_args, TRUE);
1038 data->out_args = NULL;
1042 parse_data_free_methods (ParseData *data)
1044 if (data->methods == NULL)
1046 g_ptr_array_foreach (data->methods, (GFunc) g_dbus_method_info_unref, NULL);
1047 g_ptr_array_free (data->methods, TRUE);
1048 data->methods = NULL;
1052 parse_data_free_signals (ParseData *data)
1054 if (data->signals == NULL)
1056 g_ptr_array_foreach (data->signals, (GFunc) g_dbus_signal_info_unref, NULL);
1057 g_ptr_array_free (data->signals, TRUE);
1058 data->signals = NULL;
1062 parse_data_free_properties (ParseData *data)
1064 if (data->properties == NULL)
1066 g_ptr_array_foreach (data->properties, (GFunc) g_dbus_property_info_unref, NULL);
1067 g_ptr_array_free (data->properties, TRUE);
1068 data->properties = NULL;
1072 parse_data_free_interfaces (ParseData *data)
1074 if (data->interfaces == NULL)
1076 g_ptr_array_foreach (data->interfaces, (GFunc) g_dbus_interface_info_unref, NULL);
1077 g_ptr_array_free (data->interfaces, TRUE);
1078 data->interfaces = NULL;
1082 parse_data_free_nodes (ParseData *data)
1084 if (data->nodes == NULL)
1086 g_ptr_array_foreach (data->nodes, (GFunc) g_dbus_node_info_unref, NULL);
1087 g_ptr_array_free (data->nodes, TRUE);
1091 /* ---------------------------------------------------------------------------------------------------- */
1093 static GDBusAnnotationInfo *
1094 parse_data_get_annotation (ParseData *data,
1095 gboolean create_new)
1098 g_ptr_array_add (data->annotations, g_new0 (GDBusAnnotationInfo, 1));
1099 return data->annotations->pdata[data->annotations->len - 1];
1102 static GDBusArgInfo *
1103 parse_data_get_arg (ParseData *data,
1104 gboolean create_new)
1107 g_ptr_array_add (data->args, g_new0 (GDBusArgInfo, 1));
1108 return data->args->pdata[data->args->len - 1];
1111 static GDBusArgInfo *
1112 parse_data_get_out_arg (ParseData *data,
1113 gboolean create_new)
1116 g_ptr_array_add (data->out_args, g_new0 (GDBusArgInfo, 1));
1117 return data->out_args->pdata[data->out_args->len - 1];
1120 static GDBusMethodInfo *
1121 parse_data_get_method (ParseData *data,
1122 gboolean create_new)
1125 g_ptr_array_add (data->methods, g_new0 (GDBusMethodInfo, 1));
1126 return data->methods->pdata[data->methods->len - 1];
1129 static GDBusSignalInfo *
1130 parse_data_get_signal (ParseData *data,
1131 gboolean create_new)
1134 g_ptr_array_add (data->signals, g_new0 (GDBusSignalInfo, 1));
1135 return data->signals->pdata[data->signals->len - 1];
1138 static GDBusPropertyInfo *
1139 parse_data_get_property (ParseData *data,
1140 gboolean create_new)
1143 g_ptr_array_add (data->properties, g_new0 (GDBusPropertyInfo, 1));
1144 return data->properties->pdata[data->properties->len - 1];
1147 static GDBusInterfaceInfo *
1148 parse_data_get_interface (ParseData *data,
1149 gboolean create_new)
1152 g_ptr_array_add (data->interfaces, g_new0 (GDBusInterfaceInfo, 1));
1153 return data->interfaces->pdata[data->interfaces->len - 1];
1156 static GDBusNodeInfo *
1157 parse_data_get_node (ParseData *data,
1158 gboolean create_new)
1161 g_ptr_array_add (data->nodes, g_new0 (GDBusNodeInfo, 1));
1162 return data->nodes->pdata[data->nodes->len - 1];
1165 /* ---------------------------------------------------------------------------------------------------- */
1168 parse_data_new (void)
1172 data = g_new0 (ParseData, 1);
1174 /* initialize arrays */
1175 parse_data_steal_annotations (data, NULL);
1176 parse_data_steal_args (data, NULL);
1177 parse_data_steal_out_args (data, NULL);
1178 parse_data_steal_methods (data, NULL);
1179 parse_data_steal_signals (data, NULL);
1180 parse_data_steal_properties (data, NULL);
1181 parse_data_steal_interfaces (data, NULL);
1182 parse_data_steal_nodes (data, NULL);
1188 parse_data_free (ParseData *data)
1192 /* free stack of annotation arrays */
1193 for (l = data->annotations_stack; l != NULL; l = l->next)
1195 GPtrArray *annotations = l->data;
1196 g_ptr_array_foreach (annotations, (GFunc) g_dbus_annotation_info_unref, NULL);
1197 g_ptr_array_free (annotations, TRUE);
1199 g_slist_free (data->annotations_stack);
1201 /* free stack of interface arrays */
1202 for (l = data->interfaces_stack; l != NULL; l = l->next)
1204 GPtrArray *interfaces = l->data;
1205 g_ptr_array_foreach (interfaces, (GFunc) g_dbus_interface_info_unref, NULL);
1206 g_ptr_array_free (interfaces, TRUE);
1208 g_slist_free (data->interfaces_stack);
1210 /* free stack of node arrays */
1211 for (l = data->nodes_stack; l != NULL; l = l->next)
1213 GPtrArray *nodes = l->data;
1214 g_ptr_array_foreach (nodes, (GFunc) g_dbus_node_info_unref, NULL);
1215 g_ptr_array_free (nodes, TRUE);
1217 g_slist_free (data->nodes_stack);
1219 /* free arrays (data->annotations, data->interfaces and data->nodes have been freed above) */
1220 parse_data_free_args (data);
1221 parse_data_free_out_args (data);
1222 parse_data_free_methods (data);
1223 parse_data_free_signals (data);
1224 parse_data_free_properties (data);
1225 parse_data_free_interfaces (data);
1226 parse_data_free_annotations (data);
1227 parse_data_free_nodes (data);
1232 /* ---------------------------------------------------------------------------------------------------- */
1235 parser_start_element (GMarkupParseContext *context,
1236 const gchar *element_name,
1237 const gchar **attribute_names,
1238 const gchar **attribute_values,
1242 ParseData *data = user_data;
1246 const gchar *access;
1247 const gchar *direction;
1256 stack = (GSList *) g_markup_parse_context_get_element_stack (context);
1258 /* ---------------------------------------------------------------------------------------------------- */
1259 if (strcmp (element_name, "node") == 0)
1261 if (!(g_slist_length (stack) >= 1 || strcmp (stack->next->data, "node") != 0))
1263 g_set_error_literal (error,
1265 G_MARKUP_ERROR_INVALID_CONTENT,
1266 "<node> elements can only be top-level or embedded in other <node> elements");
1270 if (!g_markup_collect_attributes (element_name,
1274 G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "name", &name,
1275 /* some hand-written introspection XML documents use this */
1276 G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "xmlns:doc", NULL,
1277 G_MARKUP_COLLECT_INVALID))
1280 g_dbus_node_info_set (data,
1281 parse_data_get_node (data, TRUE),
1287 /* push the currently retrieved interfaces and nodes on the stack and prepare new arrays */
1288 data->interfaces_stack = g_slist_prepend (data->interfaces_stack, data->interfaces);
1289 data->interfaces = NULL;
1290 parse_data_steal_interfaces (data, NULL);
1292 data->nodes_stack = g_slist_prepend (data->nodes_stack, data->nodes);
1294 parse_data_steal_nodes (data, NULL);
1297 /* ---------------------------------------------------------------------------------------------------- */
1298 else if (strcmp (element_name, "interface") == 0)
1300 if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "node") != 0)
1302 g_set_error_literal (error,
1304 G_MARKUP_ERROR_INVALID_CONTENT,
1305 "<interface> elements can only be embedded in <node> elements");
1309 if (!g_markup_collect_attributes (element_name,
1313 G_MARKUP_COLLECT_STRING, "name", &name,
1314 /* seen in the wild */
1315 G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "version", NULL,
1316 G_MARKUP_COLLECT_INVALID))
1319 g_dbus_interface_info_set (data,
1320 parse_data_get_interface (data, TRUE),
1328 /* ---------------------------------------------------------------------------------------------------- */
1329 else if (strcmp (element_name, "method") == 0)
1331 if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "interface") != 0)
1333 g_set_error_literal (error,
1335 G_MARKUP_ERROR_INVALID_CONTENT,
1336 "<method> elements can only be embedded in <interface> elements");
1340 if (!g_markup_collect_attributes (element_name,
1344 G_MARKUP_COLLECT_STRING, "name", &name,
1345 /* seen in the wild */
1346 G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "version", NULL,
1347 G_MARKUP_COLLECT_INVALID))
1350 g_dbus_method_info_set (data,
1351 parse_data_get_method (data, TRUE),
1360 /* ---------------------------------------------------------------------------------------------------- */
1361 else if (strcmp (element_name, "signal") == 0)
1363 if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "interface") != 0)
1365 g_set_error_literal (error,
1367 G_MARKUP_ERROR_INVALID_CONTENT,
1368 "<signal> elements can only be embedded in <interface> elements");
1372 if (!g_markup_collect_attributes (element_name,
1376 G_MARKUP_COLLECT_STRING, "name", &name,
1377 G_MARKUP_COLLECT_INVALID))
1380 g_dbus_signal_info_set (data,
1381 parse_data_get_signal (data, TRUE),
1389 /* ---------------------------------------------------------------------------------------------------- */
1390 else if (strcmp (element_name, "property") == 0)
1392 GDBusPropertyInfoFlags flags;
1394 if (g_slist_length (stack) < 2 || strcmp (stack->next->data, "interface") != 0)
1396 g_set_error_literal (error,
1398 G_MARKUP_ERROR_INVALID_CONTENT,
1399 "<property> elements can only be embedded in <interface> elements");
1403 if (!g_markup_collect_attributes (element_name,
1407 G_MARKUP_COLLECT_STRING, "name", &name,
1408 G_MARKUP_COLLECT_STRING, "type", &type,
1409 G_MARKUP_COLLECT_STRING, "access", &access,
1410 G_MARKUP_COLLECT_INVALID))
1413 if (strcmp (access, "read") == 0)
1414 flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE;
1415 else if (strcmp (access, "write") == 0)
1416 flags = G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE;
1417 else if (strcmp (access, "readwrite") == 0)
1418 flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE;
1423 G_MARKUP_ERROR_INVALID_CONTENT,
1424 "Unknown value '%s' of access attribute for element <property>",
1429 g_dbus_property_info_set (data,
1430 parse_data_get_property (data, TRUE),
1437 /* ---------------------------------------------------------------------------------------------------- */
1438 else if (strcmp (element_name, "arg") == 0)
1443 if (g_slist_length (stack) < 2 ||
1444 (strcmp (stack->next->data, "method") != 0 &&
1445 strcmp (stack->next->data, "signal") != 0))
1447 g_set_error_literal (error,
1449 G_MARKUP_ERROR_INVALID_CONTENT,
1450 "<arg> elements can only be embedded in <method> or <signal> elements");
1454 if (!g_markup_collect_attributes (element_name,
1458 G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "name", &name,
1459 G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "direction", &direction,
1460 G_MARKUP_COLLECT_STRING, "type", &type,
1461 G_MARKUP_COLLECT_INVALID))
1464 if (strcmp (stack->next->data, "method") == 0)
1468 if (direction != NULL)
1470 if (strcmp (direction, "in") == 0)
1472 else if (strcmp (direction, "out") == 0)
1478 G_MARKUP_ERROR_INVALID_CONTENT,
1479 "Unknown value '%s' of direction attribute",
1485 if (is_in && strcmp (stack->next->data, "signal") == 0)
1487 g_set_error_literal (error,
1489 G_MARKUP_ERROR_INVALID_CONTENT,
1490 "Only direction 'out' is allowed for <arg> elements embedded in <signal>");
1495 name_to_use = g_strdup_printf ("arg_%d", data->num_args);
1497 name_to_use = g_strdup (name);
1502 g_dbus_arg_info_set (data,
1503 parse_data_get_arg (data, TRUE),
1507 data->last_arg_was_in = TRUE;
1511 g_dbus_arg_info_set (data,
1512 parse_data_get_out_arg (data, TRUE),
1516 data->last_arg_was_in = FALSE;
1520 g_free (name_to_use);
1522 /* ---------------------------------------------------------------------------------------------------- */
1523 else if (strcmp (element_name, "annotation") == 0)
1525 if (g_slist_length (stack) < 2 ||
1526 (strcmp (stack->next->data, "node") != 0 &&
1527 strcmp (stack->next->data, "interface") != 0 &&
1528 strcmp (stack->next->data, "signal") != 0 &&
1529 strcmp (stack->next->data, "method") != 0 &&
1530 strcmp (stack->next->data, "property") != 0 &&
1531 strcmp (stack->next->data, "arg") != 0 &&
1532 strcmp (stack->next->data, "annotation") != 0))
1534 g_set_error_literal (error,
1536 G_MARKUP_ERROR_INVALID_CONTENT,
1537 "<annotation> elements can only be embedded in <node>, <interface>, <signal>, <method>, <property>, <arg> or <annotation> elements");
1541 if (!g_markup_collect_attributes (element_name,
1545 G_MARKUP_COLLECT_STRING, "name", &name,
1546 G_MARKUP_COLLECT_STRING, "value", &value,
1547 G_MARKUP_COLLECT_INVALID))
1550 g_dbus_annotation_info_set (data,
1551 parse_data_get_annotation (data, TRUE),
1556 /* ---------------------------------------------------------------------------------------------------- */
1559 /* don't bail on unknown elements; just ignore them */
1561 /* ---------------------------------------------------------------------------------------------------- */
1563 /* push the currently retrieved annotations on the stack and prepare a new one */
1564 data->annotations_stack = g_slist_prepend (data->annotations_stack, data->annotations);
1565 data->annotations = NULL;
1566 parse_data_steal_annotations (data, NULL);
1572 /* ---------------------------------------------------------------------------------------------------- */
1574 static GDBusAnnotationInfo **
1575 steal_annotations (ParseData *data)
1577 return parse_data_steal_annotations (data, NULL);
1582 parser_end_element (GMarkupParseContext *context,
1583 const gchar *element_name,
1587 ParseData *data = user_data;
1588 gboolean have_popped_annotations;
1590 have_popped_annotations = FALSE;
1592 if (strcmp (element_name, "node") == 0)
1595 guint num_interfaces;
1596 GDBusNodeInfo **nodes;
1597 GDBusInterfaceInfo **interfaces;
1599 nodes = parse_data_steal_nodes (data, &num_nodes);
1600 interfaces = parse_data_steal_interfaces (data, &num_interfaces);
1602 /* destroy the nodes, interfaces for scope we're exiting and pop the nodes, interfaces from the
1603 * scope we're reentering
1605 parse_data_free_interfaces (data);
1606 data->interfaces = (GPtrArray *) data->interfaces_stack->data;
1607 data->interfaces_stack = g_slist_remove (data->interfaces_stack, data->interfaces_stack->data);
1609 parse_data_free_nodes (data);
1610 data->nodes = (GPtrArray *) data->nodes_stack->data;
1611 data->nodes_stack = g_slist_remove (data->nodes_stack, data->nodes_stack->data);
1613 g_dbus_node_info_set (data,
1614 parse_data_get_node (data, FALSE),
1618 steal_annotations (data));
1621 else if (strcmp (element_name, "interface") == 0)
1625 guint num_properties;
1626 GDBusMethodInfo **methods;
1627 GDBusSignalInfo **signals;
1628 GDBusPropertyInfo **properties;
1630 methods = parse_data_steal_methods (data, &num_methods);
1631 signals = parse_data_steal_signals (data, &num_signals);
1632 properties = parse_data_steal_properties (data, &num_properties);
1634 g_dbus_interface_info_set (data,
1635 parse_data_get_interface (data, FALSE),
1640 steal_annotations (data));
1643 else if (strcmp (element_name, "method") == 0)
1647 GDBusArgInfo **in_args;
1648 GDBusArgInfo **out_args;
1650 in_args = parse_data_steal_args (data, &in_num_args);
1651 out_args = parse_data_steal_out_args (data, &out_num_args);
1653 g_dbus_method_info_set (data,
1654 parse_data_get_method (data, FALSE),
1658 steal_annotations (data));
1660 else if (strcmp (element_name, "signal") == 0)
1663 GDBusArgInfo **args;
1665 args = parse_data_steal_out_args (data, &num_args);
1667 g_dbus_signal_info_set (data,
1668 parse_data_get_signal (data, FALSE),
1671 steal_annotations (data));
1673 else if (strcmp (element_name, "property") == 0)
1675 g_dbus_property_info_set (data,
1676 parse_data_get_property (data, FALSE),
1679 G_DBUS_PROPERTY_INFO_FLAGS_NONE,
1680 steal_annotations (data));
1682 else if (strcmp (element_name, "arg") == 0)
1684 g_dbus_arg_info_set (data,
1685 data->last_arg_was_in ? parse_data_get_arg (data, FALSE) : parse_data_get_out_arg (data, FALSE),
1688 steal_annotations (data));
1690 else if (strcmp (element_name, "annotation") == 0)
1692 GDBusAnnotationInfo **embedded_annotations;
1694 embedded_annotations = steal_annotations (data);
1696 /* destroy the annotations for scope we're exiting and pop the annotations from the scope we're reentering */
1697 parse_data_free_annotations (data);
1698 data->annotations = (GPtrArray *) data->annotations_stack->data;
1699 data->annotations_stack = g_slist_remove (data->annotations_stack, data->annotations_stack->data);
1701 have_popped_annotations = TRUE;
1703 g_dbus_annotation_info_set (data,
1704 parse_data_get_annotation (data, FALSE),
1707 embedded_annotations);
1711 /* don't bail on unknown elements; just ignore them */
1714 if (!have_popped_annotations)
1716 /* destroy the annotations for scope we're exiting and pop the annotations from the scope we're reentering */
1717 parse_data_free_annotations (data);
1718 data->annotations = (GPtrArray *) data->annotations_stack->data;
1719 data->annotations_stack = g_slist_remove (data->annotations_stack, data->annotations_stack->data);
1723 /* ---------------------------------------------------------------------------------------------------- */
1726 parser_error (GMarkupParseContext *context,
1733 g_markup_parse_context_get_position (context, &line_number, &char_number);
1735 g_prefix_error (&error, "%d:%d: ",
1740 /* ---------------------------------------------------------------------------------------------------- */
1743 * g_dbus_node_info_new_for_xml:
1744 * @xml_data: Valid D-Bus introspection XML.
1745 * @error: Return location for error.
1747 * Parses @xml_data and returns a #GDBusNodeInfo representing the data.
1749 * The introspection XML must contain exactly one top-level
1752 * Note that this routine is using a
1753 * [GMarkup][glib-Simple-XML-Subset-Parser.description]-based
1754 * parser that only accepts a subset of valid XML documents.
1756 * Returns: A #GDBusNodeInfo structure or %NULL if @error is set. Free
1757 * with g_dbus_node_info_unref().
1762 g_dbus_node_info_new_for_xml (const gchar *xml_data,
1766 GMarkupParseContext *context;
1767 GMarkupParser *parser;
1770 GDBusNodeInfo **ughret;
1776 parser = g_new0 (GMarkupParser, 1);
1777 parser->start_element = parser_start_element;
1778 parser->end_element = parser_end_element;
1779 parser->error = parser_error;
1781 data = parse_data_new ();
1782 context = g_markup_parse_context_new (parser,
1783 G_MARKUP_IGNORE_QUALIFIED,
1785 (GDestroyNotify) parse_data_free);
1787 if (!g_markup_parse_context_parse (context,
1793 if (!g_markup_parse_context_end_parse (context, error))
1796 ughret = parse_data_steal_nodes (data, &num_nodes);
1804 G_MARKUP_ERROR_INVALID_CONTENT,
1805 "Expected a single node in introspection XML, found %d",
1809 for (n = 0; n < num_nodes; n++)
1811 g_dbus_node_info_unref (ughret[n]);
1821 if (context != NULL)
1822 g_markup_parse_context_free (context);
1827 /* ---------------------------------------------------------------------------------------------------- */
1830 * g_dbus_annotation_info_lookup:
1831 * @annotations: (array zero-terminated=1) (nullable): A %NULL-terminated array of annotations or %NULL.
1832 * @name: The name of the annotation to look up.
1834 * Looks up the value of an annotation.
1836 * The cost of this function is O(n) in number of annotations.
1838 * Returns: (nullable): The value or %NULL if not found. Do not free, it is owned by @annotations.
1843 g_dbus_annotation_info_lookup (GDBusAnnotationInfo **annotations,
1850 for (n = 0; annotations != NULL && annotations[n] != NULL; n++)
1852 if (g_strcmp0 (annotations[n]->key, name) == 0)
1854 ret = annotations[n]->value;
1863 /* ---------------------------------------------------------------------------------------------------- */
1865 G_LOCK_DEFINE_STATIC (info_cache_lock);
1871 /* gchar* -> GDBusMethodInfo* */
1872 GHashTable *method_name_to_data;
1874 /* gchar* -> GDBusMethodInfo* */
1875 GHashTable *signal_name_to_data;
1877 /* gchar* -> GDBusMethodInfo* */
1878 GHashTable *property_name_to_data;
1882 info_cache_free (InfoCacheEntry *cache)
1884 g_assert (cache->use_count == 0);
1885 g_hash_table_unref (cache->method_name_to_data);
1886 g_hash_table_unref (cache->signal_name_to_data);
1887 g_hash_table_unref (cache->property_name_to_data);
1888 g_slice_free (InfoCacheEntry, cache);
1891 /* maps from GDBusInterfaceInfo* to InfoCacheEntry* */
1892 static GHashTable *info_cache = NULL;
1894 /* ---------------------------------------------------------------------------------------------------- */
1897 * g_dbus_interface_info_lookup_method:
1898 * @info: A #GDBusInterfaceInfo.
1899 * @name: A D-Bus method name (typically in CamelCase)
1901 * Looks up information about a method.
1903 * The cost of this function is O(n) in number of methods unless
1904 * g_dbus_interface_info_cache_build() has been used on @info.
1906 * Returns: (nullable) (transfer none): A #GDBusMethodInfo or %NULL if not found. Do not free, it is owned by @info.
1911 g_dbus_interface_info_lookup_method (GDBusInterfaceInfo *info,
1915 GDBusMethodInfo *result;
1917 G_LOCK (info_cache_lock);
1918 if (G_LIKELY (info_cache != NULL))
1920 InfoCacheEntry *cache;
1921 cache = g_hash_table_lookup (info_cache, info);
1922 if (G_LIKELY (cache != NULL))
1924 result = g_hash_table_lookup (cache->method_name_to_data, name);
1925 G_UNLOCK (info_cache_lock);
1929 G_UNLOCK (info_cache_lock);
1931 for (n = 0; info->methods != NULL && info->methods[n] != NULL; n++)
1933 GDBusMethodInfo *i = info->methods[n];
1935 if (g_strcmp0 (i->name, name) == 0)
1948 /* ---------------------------------------------------------------------------------------------------- */
1951 * g_dbus_interface_info_lookup_signal:
1952 * @info: A #GDBusInterfaceInfo.
1953 * @name: A D-Bus signal name (typically in CamelCase)
1955 * Looks up information about a signal.
1957 * The cost of this function is O(n) in number of signals unless
1958 * g_dbus_interface_info_cache_build() has been used on @info.
1960 * Returns: (nullable) (transfer none): A #GDBusSignalInfo or %NULL if not found. Do not free, it is owned by @info.
1965 g_dbus_interface_info_lookup_signal (GDBusInterfaceInfo *info,
1969 GDBusSignalInfo *result;
1971 G_LOCK (info_cache_lock);
1972 if (G_LIKELY (info_cache != NULL))
1974 InfoCacheEntry *cache;
1975 cache = g_hash_table_lookup (info_cache, info);
1976 if (G_LIKELY (cache != NULL))
1978 result = g_hash_table_lookup (cache->signal_name_to_data, name);
1979 G_UNLOCK (info_cache_lock);
1983 G_UNLOCK (info_cache_lock);
1985 for (n = 0; info->signals != NULL && info->signals[n] != NULL; n++)
1987 GDBusSignalInfo *i = info->signals[n];
1989 if (g_strcmp0 (i->name, name) == 0)
2002 /* ---------------------------------------------------------------------------------------------------- */
2005 * g_dbus_interface_info_lookup_property:
2006 * @info: A #GDBusInterfaceInfo.
2007 * @name: A D-Bus property name (typically in CamelCase).
2009 * Looks up information about a property.
2011 * The cost of this function is O(n) in number of properties unless
2012 * g_dbus_interface_info_cache_build() has been used on @info.
2014 * Returns: (nullable) (transfer none): A #GDBusPropertyInfo or %NULL if not found. Do not free, it is owned by @info.
2019 g_dbus_interface_info_lookup_property (GDBusInterfaceInfo *info,
2023 GDBusPropertyInfo *result;
2025 G_LOCK (info_cache_lock);
2026 if (G_LIKELY (info_cache != NULL))
2028 InfoCacheEntry *cache;
2029 cache = g_hash_table_lookup (info_cache, info);
2030 if (G_LIKELY (cache != NULL))
2032 result = g_hash_table_lookup (cache->property_name_to_data, name);
2033 G_UNLOCK (info_cache_lock);
2037 G_UNLOCK (info_cache_lock);
2039 for (n = 0; info->properties != NULL && info->properties[n] != NULL; n++)
2041 GDBusPropertyInfo *i = info->properties[n];
2043 if (g_strcmp0 (i->name, name) == 0)
2056 /* ---------------------------------------------------------------------------------------------------- */
2059 * g_dbus_interface_info_cache_build:
2060 * @info: A #GDBusInterfaceInfo.
2062 * Builds a lookup-cache to speed up
2063 * g_dbus_interface_info_lookup_method(),
2064 * g_dbus_interface_info_lookup_signal() and
2065 * g_dbus_interface_info_lookup_property().
2067 * If this has already been called with @info, the existing cache is
2068 * used and its use count is increased.
2070 * Note that @info cannot be modified until
2071 * g_dbus_interface_info_cache_release() is called.
2076 g_dbus_interface_info_cache_build (GDBusInterfaceInfo *info)
2078 InfoCacheEntry *cache;
2081 G_LOCK (info_cache_lock);
2082 if (info_cache == NULL)
2083 info_cache = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) info_cache_free);
2084 cache = g_hash_table_lookup (info_cache, info);
2087 cache->use_count += 1;
2090 cache = g_slice_new0 (InfoCacheEntry);
2091 cache->use_count = 1;
2092 cache->method_name_to_data = g_hash_table_new (g_str_hash, g_str_equal);
2093 cache->signal_name_to_data = g_hash_table_new (g_str_hash, g_str_equal);
2094 cache->property_name_to_data = g_hash_table_new (g_str_hash, g_str_equal);
2095 for (n = 0; info->methods != NULL && info->methods[n] != NULL; n++)
2096 g_hash_table_insert (cache->method_name_to_data, info->methods[n]->name, info->methods[n]);
2097 for (n = 0; info->signals != NULL && info->signals[n] != NULL; n++)
2098 g_hash_table_insert (cache->signal_name_to_data, info->signals[n]->name, info->signals[n]);
2099 for (n = 0; info->properties != NULL && info->properties[n] != NULL; n++)
2100 g_hash_table_insert (cache->property_name_to_data, info->properties[n]->name, info->properties[n]);
2101 g_hash_table_insert (info_cache, info, cache);
2103 G_UNLOCK (info_cache_lock);
2107 * g_dbus_interface_info_cache_release:
2108 * @info: A GDBusInterfaceInfo
2110 * Decrements the usage count for the cache for @info built by
2111 * g_dbus_interface_info_cache_build() (if any) and frees the
2112 * resources used by the cache if the usage count drops to zero.
2117 g_dbus_interface_info_cache_release (GDBusInterfaceInfo *info)
2119 InfoCacheEntry *cache;
2121 G_LOCK (info_cache_lock);
2122 if (G_UNLIKELY (info_cache == NULL))
2124 g_warning ("%s called for interface %s but there is no cache", info->name, G_STRFUNC);
2128 cache = g_hash_table_lookup (info_cache, info);
2129 if (G_UNLIKELY (cache == NULL))
2131 g_warning ("%s called for interface %s but there is no cache entry", info->name, G_STRFUNC);
2134 cache->use_count -= 1;
2135 if (cache->use_count == 0)
2137 g_hash_table_remove (info_cache, info);
2138 /* could nuke info_cache itself if empty */
2141 G_UNLOCK (info_cache_lock);
2145 /* ---------------------------------------------------------------------------------------------------- */
2148 * g_dbus_node_info_lookup_interface:
2149 * @info: A #GDBusNodeInfo.
2150 * @name: A D-Bus interface name.
2152 * Looks up information about an interface.
2154 * The cost of this function is O(n) in number of interfaces.
2156 * Returns: (nullable) (transfer none): A #GDBusInterfaceInfo or %NULL if not found. Do not free, it is owned by @info.
2160 GDBusInterfaceInfo *
2161 g_dbus_node_info_lookup_interface (GDBusNodeInfo *info,
2165 GDBusInterfaceInfo *result;
2167 for (n = 0; info->interfaces != NULL && info->interfaces[n] != NULL; n++)
2169 GDBusInterfaceInfo *i = info->interfaces[n];
2171 if (g_strcmp0 (i->name, name) == 0)