X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgdbusintrospection.c;h=6d3ff93ead7224c5e4477e3a0cfc3cea1e132baa;hb=7103484017ff000d01ed94567539d37fa09b32b2;hp=c76af4eb8045f97478baf969f22289c6b94536b5;hpb=c490c14f4e3fbbe8c74b26e6cacac31b0e744c92;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gdbusintrospection.c b/gio/gdbusintrospection.c index c76af4e..6d3ff93 100644 --- a/gio/gdbusintrospection.c +++ b/gio/gdbusintrospection.c @@ -1,6 +1,6 @@ /* GDBus - GLib D-Bus Library * - * Copyright (C) 2008-2009 Red Hat, Inc. + * Copyright (C) 2008-2010 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -13,9 +13,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. + * Public License along with this library; if not, see . * * Author: David Zeuthen */ @@ -23,42 +21,35 @@ #include "config.h" #include - -#include +#include #include "gdbusintrospection.h" +#include "glibintl.h" + /** * SECTION:gdbusintrospection - * @title: Introspection XML - * @short_description: Parse and Generate Introspection XML + * @title: D-Bus Introspection Data + * @short_description: Node and interface description data structures * @include: gio/gio.h * * Various data structures and convenience routines to parse and - * generate D-Bus introspection XML. + * generate D-Bus introspection XML. Introspection information is + * used when registering objects with g_dbus_connection_register_object(). + * + * The format of D-Bus introspection XML is specified in the + * [D-Bus specification](http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format) */ /* ---------------------------------------------------------------------------------------------------- */ -/* See also https://bugzilla.gnome.org/show_bug.cgi?id=449565 ... */ -#define _MY_DEFINE_BOXED_TYPE(TypeName, type_name) \ - GType \ - type_name##_get_type (void) \ - { \ - static volatile gsize type_volatile = 0; \ - if (g_once_init_enter (&type_volatile)) \ - { \ - GType type = g_boxed_type_register_static (g_intern_static_string (#TypeName), \ - (GBoxedCopyFunc) type_name##_ref, \ - (GBoxedFreeFunc) type_name##_unref); \ - g_once_init_leave (&type_volatile, type); \ - } \ - return (GType) type_volatile; \ - } +#define _MY_DEFINE_BOXED_TYPE(TypeName, type_name) \ + G_DEFINE_BOXED_TYPE (TypeName, type_name, type_name##_ref, type_name##_unref) _MY_DEFINE_BOXED_TYPE (GDBusNodeInfo, g_dbus_node_info); _MY_DEFINE_BOXED_TYPE (GDBusInterfaceInfo, g_dbus_interface_info); _MY_DEFINE_BOXED_TYPE (GDBusMethodInfo, g_dbus_method_info); +_MY_DEFINE_BOXED_TYPE (GDBusSignalInfo, g_dbus_signal_info); _MY_DEFINE_BOXED_TYPE (GDBusPropertyInfo, g_dbus_property_info); _MY_DEFINE_BOXED_TYPE (GDBusArgInfo, g_dbus_arg_info); _MY_DEFINE_BOXED_TYPE (GDBusAnnotationInfo, g_dbus_annotation_info); @@ -106,6 +97,8 @@ typedef struct * the reference count. * * Returns: The same @info. + * + * Since: 2.26 */ GDBusNodeInfo * g_dbus_node_info_ref (GDBusNodeInfo *info) @@ -124,6 +117,8 @@ g_dbus_node_info_ref (GDBusNodeInfo *info) * the reference count. * * Returns: The same @info. + * + * Since: 2.26 */ GDBusInterfaceInfo * g_dbus_interface_info_ref (GDBusInterfaceInfo *info) @@ -142,6 +137,8 @@ g_dbus_interface_info_ref (GDBusInterfaceInfo *info) * the reference count. * * Returns: The same @info. + * + * Since: 2.26 */ GDBusMethodInfo * g_dbus_method_info_ref (GDBusMethodInfo *info) @@ -160,6 +157,8 @@ g_dbus_method_info_ref (GDBusMethodInfo *info) * the reference count. * * Returns: The same @info. + * + * Since: 2.26 */ GDBusSignalInfo * g_dbus_signal_info_ref (GDBusSignalInfo *info) @@ -178,6 +177,8 @@ g_dbus_signal_info_ref (GDBusSignalInfo *info) * the reference count. * * Returns: The same @info. + * + * Since: 2.26 */ GDBusPropertyInfo * g_dbus_property_info_ref (GDBusPropertyInfo *info) @@ -196,6 +197,8 @@ g_dbus_property_info_ref (GDBusPropertyInfo *info) * the reference count. * * Returns: The same @info. + * + * Since: 2.26 */ GDBusArgInfo * g_dbus_arg_info_ref (GDBusArgInfo *info) @@ -207,13 +210,15 @@ g_dbus_arg_info_ref (GDBusArgInfo *info) } /** - * g_dbus_node_info_ref: + * g_dbus_annotation_info_ref: * @info: A #GDBusNodeInfo * * If @info is statically allocated does nothing. Otherwise increases * the reference count. * * Returns: The same @info. + * + * Since: 2.26 */ GDBusAnnotationInfo * g_dbus_annotation_info_ref (GDBusAnnotationInfo *info) @@ -245,6 +250,8 @@ free_null_terminated_array (gpointer array, GDestroyNotify unref_func) * If @info is statically allocated, does nothing. Otherwise decreases * the reference count of @info. When its reference count drops to 0, * the memory used is freed. + * + * Since: 2.26 */ void g_dbus_annotation_info_unref (GDBusAnnotationInfo *info) @@ -267,6 +274,8 @@ g_dbus_annotation_info_unref (GDBusAnnotationInfo *info) * If @info is statically allocated, does nothing. Otherwise decreases * the reference count of @info. When its reference count drops to 0, * the memory used is freed. + * + * Since: 2.26 */ void g_dbus_arg_info_unref (GDBusArgInfo *info) @@ -289,6 +298,8 @@ g_dbus_arg_info_unref (GDBusArgInfo *info) * If @info is statically allocated, does nothing. Otherwise decreases * the reference count of @info. When its reference count drops to 0, * the memory used is freed. + * + * Since: 2.26 */ void g_dbus_method_info_unref (GDBusMethodInfo *info) @@ -312,6 +323,8 @@ g_dbus_method_info_unref (GDBusMethodInfo *info) * If @info is statically allocated, does nothing. Otherwise decreases * the reference count of @info. When its reference count drops to 0, * the memory used is freed. + * + * Since: 2.26 */ void g_dbus_signal_info_unref (GDBusSignalInfo *info) @@ -334,6 +347,8 @@ g_dbus_signal_info_unref (GDBusSignalInfo *info) * If @info is statically allocated, does nothing. Otherwise decreases * the reference count of @info. When its reference count drops to 0, * the memory used is freed. + * + * Since: 2.26 */ void g_dbus_property_info_unref (GDBusPropertyInfo *info) @@ -356,6 +371,8 @@ g_dbus_property_info_unref (GDBusPropertyInfo *info) * If @info is statically allocated, does nothing. Otherwise decreases * the reference count of @info. When its reference count drops to 0, * the memory used is freed. + * + * Since: 2.26 */ void g_dbus_interface_info_unref (GDBusInterfaceInfo *info) @@ -380,6 +397,8 @@ g_dbus_interface_info_unref (GDBusInterfaceInfo *info) * If @info is statically allocated, does nothing. Otherwise decreases * the reference count of @info. When its reference count drops to 0, * the memory used is freed. + * + * Since: 2.26 */ void g_dbus_node_info_unref (GDBusNodeInfo *info) @@ -399,10 +418,10 @@ g_dbus_node_info_unref (GDBusNodeInfo *info) /* ---------------------------------------------------------------------------------------------------- */ static void -g_dbus_annotation_info_set (ParseData *data, - GDBusAnnotationInfo *info, - const gchar *key, - const gchar *value, +g_dbus_annotation_info_set (ParseData *data, + GDBusAnnotationInfo *info, + const gchar *key, + const gchar *value, GDBusAnnotationInfo **embedded_annotations) { info->ref_count = 1; @@ -441,9 +460,7 @@ static void g_dbus_method_info_set (ParseData *data, GDBusMethodInfo *info, const gchar *name, - guint in_num_args, GDBusArgInfo **in_args, - guint out_num_args, GDBusArgInfo **out_args, GDBusAnnotationInfo **annotations) { @@ -452,17 +469,11 @@ g_dbus_method_info_set (ParseData *data, if (name != NULL) info->name = g_strdup (name); - if (in_num_args != 0) - { - //info->in_num_args = in_num_args; - info->in_args = in_args; - } + if (in_args != NULL) + info->in_args = in_args; - if (out_num_args != 0) - { - //info->out_num_args = out_num_args; - info->out_args = out_args; - } + if (out_args != NULL) + info->out_args = out_args; if (annotations != NULL) info->annotations = annotations; @@ -472,7 +483,6 @@ static void g_dbus_signal_info_set (ParseData *data, GDBusSignalInfo *info, const gchar *name, - guint num_args, GDBusArgInfo **args, GDBusAnnotationInfo **annotations) { @@ -481,16 +491,11 @@ g_dbus_signal_info_set (ParseData *data, if (name != NULL) info->name = g_strdup (name); - if (num_args != 0) - { - //info->num_args = num_args; - info->args = args; - } + if (args != NULL) + info->args = args; if (annotations != NULL) - { - info->annotations = annotations; - } + info->annotations = annotations; } static void @@ -510,66 +515,44 @@ g_dbus_property_info_set (ParseData *data, info->flags = flags; if (signature != NULL) - { - info->signature = g_strdup (signature); - } + info->signature = g_strdup (signature); if (annotations != NULL) - { - info->annotations = annotations; - } + info->annotations = annotations; } static void g_dbus_interface_info_set (ParseData *data, GDBusInterfaceInfo *info, const gchar *name, - guint num_methods, GDBusMethodInfo **methods, - guint num_signals, GDBusSignalInfo **signals, - guint num_properties, GDBusPropertyInfo **properties, GDBusAnnotationInfo **annotations) { info->ref_count = 1; if (name != NULL) - { - info->name = g_strdup (name); - } + info->name = g_strdup (name); - if (num_methods != 0) - { - //info->num_methods = num_methods; - info->methods = methods; - } + if (methods != NULL) + info->methods = methods; - if (num_signals != 0) - { - //info->num_signals = num_signals; - info->signals = signals; - } + if (signals != NULL) + info->signals = signals; - if (num_properties != 0) - { - //info->num_properties = num_properties; - info->properties = properties; - } + if (properties != NULL) + info->properties = properties; if (annotations != NULL) - { - info->annotations = annotations; - } + info->annotations = annotations; } static void g_dbus_node_info_set (ParseData *data, GDBusNodeInfo *info, const gchar *path, - guint num_interfaces, GDBusInterfaceInfo **interfaces, - guint num_nodes, GDBusNodeInfo **nodes, GDBusAnnotationInfo **annotations) { @@ -581,38 +564,32 @@ g_dbus_node_info_set (ParseData *data, /* TODO: relative / absolute path snafu */ } - if (num_interfaces != 0) - { - //info->num_interfaces = num_interfaces; - info->interfaces = interfaces; - } + if (interfaces != NULL) + info->interfaces = interfaces; - if (num_nodes != 0) - { - //info->num_nodes = num_nodes; - info->nodes = nodes; - } + if (nodes != NULL) + info->nodes = nodes; if (annotations != NULL) - { - info->annotations = annotations; - } - + info->annotations = annotations; } /* ---------------------------------------------------------------------------------------------------- */ static void -g_dbus_annotation_info_generate_xml (const GDBusAnnotationInfo *info, - guint indent, - GString *string_builder) +g_dbus_annotation_info_generate_xml (GDBusAnnotationInfo *info, + guint indent, + GString *string_builder) { + gchar *tmp; guint n; - g_string_append_printf (string_builder, "%*skey, - info->value); + tmp = g_markup_printf_escaped ("%*skey, + info->value); + g_string_append (string_builder, tmp); + g_free (tmp); if (info->annotations == NULL) { @@ -634,10 +611,10 @@ g_dbus_annotation_info_generate_xml (const GDBusAnnotationInfo *info, } static void -g_dbus_arg_info_generate_xml (const GDBusArgInfo *info, - guint indent, - const gchar *extra_attributes, - GString *string_builder) +g_dbus_arg_info_generate_xml (GDBusArgInfo *info, + guint indent, + const gchar *extra_attributes, + GString *string_builder) { guint n; @@ -670,9 +647,9 @@ g_dbus_arg_info_generate_xml (const GDBusArgInfo *info, } static void -g_dbus_method_info_generate_xml (const GDBusMethodInfo *info, - guint indent, - GString *string_builder) +g_dbus_method_info_generate_xml (GDBusMethodInfo *info, + guint indent, + GString *string_builder) { guint n; @@ -710,9 +687,9 @@ g_dbus_method_info_generate_xml (const GDBusMethodInfo *info, } static void -g_dbus_signal_info_generate_xml (const GDBusSignalInfo *info, - guint indent, - GString *string_builder) +g_dbus_signal_info_generate_xml (GDBusSignalInfo *info, + guint indent, + GString *string_builder) { guint n; @@ -744,9 +721,9 @@ g_dbus_signal_info_generate_xml (const GDBusSignalInfo *info, } static void -g_dbus_property_info_generate_xml (const GDBusPropertyInfo *info, - guint indent, - GString *string_builder) +g_dbus_property_info_generate_xml (GDBusPropertyInfo *info, + guint indent, + GString *string_builder) { guint n; const gchar *access_string; @@ -797,19 +774,21 @@ g_dbus_property_info_generate_xml (const GDBusPropertyInfo *info, * g_dbus_interface_info_generate_xml: * @info: A #GDBusNodeInfo * @indent: Indentation level. - * @string_builder: A #GString to to append XML data to. + * @string_builder: (out): A #GString to to append XML data to. * * Appends an XML representation of @info (and its children) to @string_builder. * * This function is typically used for generating introspection XML * documents at run-time for handling the - * org.freedesktop.DBus.Introspectable.Introspect + * `org.freedesktop.DBus.Introspectable.Introspect` * method. + * + * Since: 2.26 */ void -g_dbus_interface_info_generate_xml (const GDBusInterfaceInfo *info, - guint indent, - GString *string_builder) +g_dbus_interface_info_generate_xml (GDBusInterfaceInfo *info, + guint indent, + GString *string_builder) { guint n; @@ -842,27 +821,29 @@ g_dbus_interface_info_generate_xml (const GDBusInterfaceInfo *info, /** * g_dbus_node_info_generate_xml: - * @node_info: A #GDBusNodeInfo. + * @info: A #GDBusNodeInfo. * @indent: Indentation level. - * @string_builder: A #GString to to append XML data to. + * @string_builder: (out): A #GString to to append XML data to. * - * Appends an XML representation of @node_info (and its children) to @string_builder. + * Appends an XML representation of @info (and its children) to @string_builder. * * This function is typically used for generating introspection XML documents at run-time for - * handling the org.freedesktop.DBus.Introspectable.Introspect method. + * handling the `org.freedesktop.DBus.Introspectable.Introspect` method. + * + * Since: 2.26 */ void -g_dbus_node_info_generate_xml (const GDBusNodeInfo *node_info, - guint indent, - GString *string_builder) +g_dbus_node_info_generate_xml (GDBusNodeInfo *info, + guint indent, + GString *string_builder) { guint n; g_string_append_printf (string_builder, "%*spath != NULL) - g_string_append_printf (string_builder, " name=\"%s\"", node_info->path); + if (info->path != NULL) + g_string_append_printf (string_builder, " name=\"%s\"", info->path); - if (node_info->interfaces == NULL && node_info->nodes == NULL && node_info->annotations == NULL) + if (info->interfaces == NULL && info->nodes == NULL && info->annotations == NULL) { g_string_append (string_builder, "/>\n"); } @@ -870,18 +851,18 @@ g_dbus_node_info_generate_xml (const GDBusNodeInfo *node_info, { g_string_append (string_builder, ">\n"); - for (n = 0; node_info->annotations != NULL && node_info->annotations[n] != NULL; n++) - g_dbus_annotation_info_generate_xml (node_info->annotations[n], + for (n = 0; info->annotations != NULL && info->annotations[n] != NULL; n++) + g_dbus_annotation_info_generate_xml (info->annotations[n], indent + 2, string_builder); - for (n = 0; node_info->interfaces != NULL && node_info->interfaces[n] != NULL; n++) - g_dbus_interface_info_generate_xml (node_info->interfaces[n], + for (n = 0; info->interfaces != NULL && info->interfaces[n] != NULL; n++) + g_dbus_interface_info_generate_xml (info->interfaces[n], indent + 2, string_builder); - for (n = 0; node_info->nodes != NULL && node_info->nodes[n] != NULL; n++) - g_dbus_node_info_generate_xml (node_info->nodes[n], + for (n = 0; info->nodes != NULL && info->nodes[n] != NULL; n++) + g_dbus_node_info_generate_xml (info->nodes[n], indent + 2, string_builder); @@ -892,7 +873,8 @@ g_dbus_node_info_generate_xml (const GDBusNodeInfo *node_info, /* ---------------------------------------------------------------------------------------------------- */ static GDBusAnnotationInfo ** -parse_data_steal_annotations (ParseData *data, guint *out_num_elements) +parse_data_steal_annotations (ParseData *data, + guint *out_num_elements) { GDBusAnnotationInfo **ret; if (out_num_elements != NULL) @@ -909,7 +891,8 @@ parse_data_steal_annotations (ParseData *data, guint *out_num_elements) } static GDBusArgInfo ** -parse_data_steal_args (ParseData *data, guint *out_num_elements) +parse_data_steal_args (ParseData *data, + guint *out_num_elements) { GDBusArgInfo **ret; if (out_num_elements != NULL) @@ -926,7 +909,8 @@ parse_data_steal_args (ParseData *data, guint *out_num_elements) } static GDBusArgInfo ** -parse_data_steal_out_args (ParseData *data, guint *out_num_elements) +parse_data_steal_out_args (ParseData *data, + guint *out_num_elements) { GDBusArgInfo **ret; if (out_num_elements != NULL) @@ -943,7 +927,8 @@ parse_data_steal_out_args (ParseData *data, guint *out_num_elements) } static GDBusMethodInfo ** -parse_data_steal_methods (ParseData *data, guint *out_num_elements) +parse_data_steal_methods (ParseData *data, + guint *out_num_elements) { GDBusMethodInfo **ret; if (out_num_elements != NULL) @@ -960,7 +945,8 @@ parse_data_steal_methods (ParseData *data, guint *out_num_elements) } static GDBusSignalInfo ** -parse_data_steal_signals (ParseData *data, guint *out_num_elements) +parse_data_steal_signals (ParseData *data, + guint *out_num_elements) { GDBusSignalInfo **ret; if (out_num_elements != NULL) @@ -977,7 +963,8 @@ parse_data_steal_signals (ParseData *data, guint *out_num_elements) } static GDBusPropertyInfo ** -parse_data_steal_properties (ParseData *data, guint *out_num_elements) +parse_data_steal_properties (ParseData *data, + guint *out_num_elements) { GDBusPropertyInfo **ret; if (out_num_elements != NULL) @@ -994,7 +981,8 @@ parse_data_steal_properties (ParseData *data, guint *out_num_elements) } static GDBusInterfaceInfo ** -parse_data_steal_interfaces (ParseData *data, guint *out_num_elements) +parse_data_steal_interfaces (ParseData *data, + guint *out_num_elements) { GDBusInterfaceInfo **ret; if (out_num_elements != NULL) @@ -1011,7 +999,8 @@ parse_data_steal_interfaces (ParseData *data, guint *out_num_elements) } static GDBusNodeInfo ** -parse_data_steal_nodes (ParseData *data, guint *out_num_elements) +parse_data_steal_nodes (ParseData *data, + guint *out_num_elements) { GDBusNodeInfo **ret; if (out_num_elements != NULL) @@ -1112,7 +1101,8 @@ parse_data_free_nodes (ParseData *data) /* ---------------------------------------------------------------------------------------------------- */ static GDBusAnnotationInfo * -parse_data_get_annotation (ParseData *data, gboolean create_new) +parse_data_get_annotation (ParseData *data, + gboolean create_new) { if (create_new) g_ptr_array_add (data->annotations, g_new0 (GDBusAnnotationInfo, 1)); @@ -1120,7 +1110,8 @@ parse_data_get_annotation (ParseData *data, gboolean create_new) } static GDBusArgInfo * -parse_data_get_arg (ParseData *data, gboolean create_new) +parse_data_get_arg (ParseData *data, + gboolean create_new) { if (create_new) g_ptr_array_add (data->args, g_new0 (GDBusArgInfo, 1)); @@ -1128,7 +1119,8 @@ parse_data_get_arg (ParseData *data, gboolean create_new) } static GDBusArgInfo * -parse_data_get_out_arg (ParseData *data, gboolean create_new) +parse_data_get_out_arg (ParseData *data, + gboolean create_new) { if (create_new) g_ptr_array_add (data->out_args, g_new0 (GDBusArgInfo, 1)); @@ -1136,7 +1128,8 @@ parse_data_get_out_arg (ParseData *data, gboolean create_new) } static GDBusMethodInfo * -parse_data_get_method (ParseData *data, gboolean create_new) +parse_data_get_method (ParseData *data, + gboolean create_new) { if (create_new) g_ptr_array_add (data->methods, g_new0 (GDBusMethodInfo, 1)); @@ -1144,7 +1137,8 @@ parse_data_get_method (ParseData *data, gboolean create_new) } static GDBusSignalInfo * -parse_data_get_signal (ParseData *data, gboolean create_new) +parse_data_get_signal (ParseData *data, + gboolean create_new) { if (create_new) g_ptr_array_add (data->signals, g_new0 (GDBusSignalInfo, 1)); @@ -1152,7 +1146,8 @@ parse_data_get_signal (ParseData *data, gboolean create_new) } static GDBusPropertyInfo * -parse_data_get_property (ParseData *data, gboolean create_new) +parse_data_get_property (ParseData *data, + gboolean create_new) { if (create_new) g_ptr_array_add (data->properties, g_new0 (GDBusPropertyInfo, 1)); @@ -1160,7 +1155,8 @@ parse_data_get_property (ParseData *data, gboolean create_new) } static GDBusInterfaceInfo * -parse_data_get_interface (ParseData *data, gboolean create_new) +parse_data_get_interface (ParseData *data, + gboolean create_new) { if (create_new) g_ptr_array_add (data->interfaces, g_new0 (GDBusInterfaceInfo, 1)); @@ -1168,7 +1164,8 @@ parse_data_get_interface (ParseData *data, gboolean create_new) } static GDBusNodeInfo * -parse_data_get_node (ParseData *data, gboolean create_new) +parse_data_get_node (ParseData *data, + gboolean create_new) { if (create_new) g_ptr_array_add (data->nodes, g_new0 (GDBusNodeInfo, 1)); @@ -1235,6 +1232,9 @@ parse_data_free (ParseData *data) parse_data_free_methods (data); parse_data_free_signals (data); parse_data_free_properties (data); + parse_data_free_interfaces (data); + parse_data_free_annotations (data); + parse_data_free_nodes (data); g_free (data); } @@ -1242,12 +1242,12 @@ parse_data_free (ParseData *data) /* ---------------------------------------------------------------------------------------------------- */ static void -parser_start_element (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - gpointer user_data, - GError **error) +parser_start_element (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error) { ParseData *data = user_data; GSList *stack; @@ -1290,8 +1290,8 @@ parser_start_element (GMarkupParseContext *context, g_dbus_node_info_set (data, parse_data_get_node (data, TRUE), name, - 0, NULL, - 0, NULL, + NULL, + NULL, NULL); /* push the currently retrieved interfaces and nodes on the stack and prepare new arrays */ @@ -1321,15 +1321,17 @@ parser_start_element (GMarkupParseContext *context, attribute_values, error, G_MARKUP_COLLECT_STRING, "name", &name, + /* seen in the wild */ + G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "version", NULL, G_MARKUP_COLLECT_INVALID)) goto out; g_dbus_interface_info_set (data, parse_data_get_interface (data, TRUE), name, - 0, NULL, - 0, NULL, - 0, NULL, + NULL, + NULL, + NULL, NULL); } @@ -1350,14 +1352,16 @@ parser_start_element (GMarkupParseContext *context, attribute_values, error, G_MARKUP_COLLECT_STRING, "name", &name, + /* seen in the wild */ + G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL, "version", NULL, G_MARKUP_COLLECT_INVALID)) goto out; g_dbus_method_info_set (data, parse_data_get_method (data, TRUE), name, - 0, NULL, - 0, NULL, + NULL, + NULL, NULL); data->num_args = 0; @@ -1386,7 +1390,7 @@ parser_start_element (GMarkupParseContext *context, g_dbus_signal_info_set (data, parse_data_get_signal (data, TRUE), name, - 0, NULL, + NULL, NULL); data->num_args = 0; @@ -1467,7 +1471,10 @@ parser_start_element (GMarkupParseContext *context, G_MARKUP_COLLECT_INVALID)) goto out; - is_in = FALSE; + if (strcmp (stack->next->data, "method") == 0) + is_in = TRUE; + else + is_in = FALSE; if (direction != NULL) { if (strcmp (direction, "in") == 0) @@ -1582,10 +1589,10 @@ steal_annotations (ParseData *data) static void -parser_end_element (GMarkupParseContext *context, - const gchar *element_name, - gpointer user_data, - GError **error) +parser_end_element (GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, + GError **error) { ParseData *data = user_data; gboolean have_popped_annotations; @@ -1616,9 +1623,7 @@ parser_end_element (GMarkupParseContext *context, g_dbus_node_info_set (data, parse_data_get_node (data, FALSE), NULL, - num_interfaces, interfaces, - num_nodes, nodes, steal_annotations (data)); @@ -1639,11 +1644,8 @@ parser_end_element (GMarkupParseContext *context, g_dbus_interface_info_set (data, parse_data_get_interface (data, FALSE), NULL, - num_methods, methods, - num_signals, signals, - num_properties, properties, steal_annotations (data)); @@ -1661,9 +1663,7 @@ parser_end_element (GMarkupParseContext *context, g_dbus_method_info_set (data, parse_data_get_method (data, FALSE), NULL, - in_num_args, in_args, - out_num_args, out_args, steal_annotations (data)); } @@ -1677,7 +1677,6 @@ parser_end_element (GMarkupParseContext *context, g_dbus_signal_info_set (data, parse_data_get_signal (data, FALSE), NULL, - num_args, args, steal_annotations (data)); } @@ -1757,8 +1756,17 @@ parser_error (GMarkupParseContext *context, * * Parses @xml_data and returns a #GDBusNodeInfo representing the data. * + * The introspection XML must contain exactly one top-level + * element. + * + * Note that this routine is using a + * [GMarkup][glib-Simple-XML-Subset-Parser.description]-based + * parser that only accepts a subset of valid XML documents. + * * Returns: A #GDBusNodeInfo structure or %NULL if @error is set. Free * with g_dbus_node_info_unref(). + * + * Since: 2.26 */ GDBusNodeInfo * g_dbus_node_info_new_for_xml (const gchar *xml_data, @@ -1769,6 +1777,7 @@ g_dbus_node_info_new_for_xml (const gchar *xml_data, GMarkupParser *parser; guint num_nodes; ParseData *data; + GDBusNodeInfo **ughret; ret = NULL; parser = NULL; @@ -1781,7 +1790,7 @@ g_dbus_node_info_new_for_xml (const gchar *xml_data, data = parse_data_new (); context = g_markup_parse_context_new (parser, - 0, + G_MARKUP_IGNORE_QUALIFIED, data, (GDestroyNotify) parse_data_free); @@ -1791,7 +1800,9 @@ g_dbus_node_info_new_for_xml (const gchar *xml_data, error)) goto out; - GDBusNodeInfo **ughret; + if (!g_markup_parse_context_end_parse (context, error)) + goto out; + ughret = parse_data_steal_nodes (data, &num_nodes); if (num_nodes != 1) @@ -1807,19 +1818,16 @@ g_dbus_node_info_new_for_xml (const gchar *xml_data, /* clean up */ for (n = 0; n < num_nodes; n++) { - for (n = 0; n < num_nodes; n++) - g_dbus_node_info_unref (&(ret[n])); + g_dbus_node_info_unref (ughret[n]); + ughret[n] = NULL; } - g_free (ret); - ret = NULL; } ret = ughret[0]; g_free (ughret); out: - if (parser != NULL) - g_free (parser); + g_free (parser); if (context != NULL) g_markup_parse_context_free (context); @@ -1830,24 +1838,26 @@ g_dbus_node_info_new_for_xml (const gchar *xml_data, /** * g_dbus_annotation_info_lookup: - * @annotations: A %NULL-terminated array of annotations or %NULL. + * @annotations: (array zero-terminated=1) (allow-none): A %NULL-terminated array of annotations or %NULL. * @name: The name of the annotation to look up. * * Looks up the value of an annotation. * - * This cost of this function is O(n) in number of annotations. + * The cost of this function is O(n) in number of annotations. * * Returns: The value or %NULL if not found. Do not free, it is owned by @annotations. + * + * Since: 2.26 */ const gchar * -g_dbus_annotation_info_lookup (const GDBusAnnotationInfo **annotations, - const gchar *name) +g_dbus_annotation_info_lookup (GDBusAnnotationInfo **annotations, + const gchar *name) { guint n; const gchar *ret; ret = NULL; - for (n = 0; annotations != NULL && annotations[n]->key != NULL; n++) + for (n = 0; annotations != NULL && annotations[n] != NULL; n++) { if (g_strcmp0 (annotations[n]->key, name) == 0) { @@ -1862,6 +1872,37 @@ g_dbus_annotation_info_lookup (const GDBusAnnotationInfo **annotations, /* ---------------------------------------------------------------------------------------------------- */ +G_LOCK_DEFINE_STATIC (info_cache_lock); + +typedef struct +{ + gint use_count; + + /* gchar* -> GDBusMethodInfo* */ + GHashTable *method_name_to_data; + + /* gchar* -> GDBusMethodInfo* */ + GHashTable *signal_name_to_data; + + /* gchar* -> GDBusMethodInfo* */ + GHashTable *property_name_to_data; +} InfoCacheEntry; + +static void +info_cache_free (InfoCacheEntry *cache) +{ + g_assert (cache->use_count == 0); + g_hash_table_unref (cache->method_name_to_data); + g_hash_table_unref (cache->signal_name_to_data); + g_hash_table_unref (cache->property_name_to_data); + g_slice_free (InfoCacheEntry, cache); +} + +/* maps from GDBusInterfaceInfo* to InfoCacheEntry* */ +static GHashTable *info_cache = NULL; + +/* ---------------------------------------------------------------------------------------------------- */ + /** * g_dbus_interface_info_lookup_method: * @info: A #GDBusInterfaceInfo. @@ -1869,20 +1910,37 @@ g_dbus_annotation_info_lookup (const GDBusAnnotationInfo **annotations, * * Looks up information about a method. * - * This cost of this function is O(n) in number of methods. + * The cost of this function is O(n) in number of methods unless + * g_dbus_interface_info_cache_build() has been used on @info. * - * Returns: A #GDBusMethodInfo or %NULL if not found. Do not free, it is owned by @info. - **/ -const GDBusMethodInfo * -g_dbus_interface_info_lookup_method (const GDBusInterfaceInfo *info, - const gchar *name) + * Returns: (transfer none): A #GDBusMethodInfo or %NULL if not found. Do not free, it is owned by @info. + * + * Since: 2.26 + */ +GDBusMethodInfo * +g_dbus_interface_info_lookup_method (GDBusInterfaceInfo *info, + const gchar *name) { guint n; - const GDBusMethodInfo *result; + GDBusMethodInfo *result; + + G_LOCK (info_cache_lock); + if (G_LIKELY (info_cache != NULL)) + { + InfoCacheEntry *cache; + cache = g_hash_table_lookup (info_cache, info); + if (G_LIKELY (cache != NULL)) + { + result = g_hash_table_lookup (cache->method_name_to_data, name); + G_UNLOCK (info_cache_lock); + goto out; + } + } + G_UNLOCK (info_cache_lock); for (n = 0; info->methods != NULL && info->methods[n] != NULL; n++) { - const GDBusMethodInfo *i = info->methods[n]; + GDBusMethodInfo *i = info->methods[n]; if (g_strcmp0 (i->name, name) == 0) { @@ -1906,20 +1964,37 @@ g_dbus_interface_info_lookup_method (const GDBusInterfaceInfo *info, * * Looks up information about a signal. * - * This cost of this function is O(n) in number of signals. + * The cost of this function is O(n) in number of signals unless + * g_dbus_interface_info_cache_build() has been used on @info. + * + * Returns: (transfer none): A #GDBusSignalInfo or %NULL if not found. Do not free, it is owned by @info. * - * Returns: A #GDBusSignalInfo or %NULL if not found. Do not free, it is owned by @info. - **/ -const GDBusSignalInfo * -g_dbus_interface_info_lookup_signal (const GDBusInterfaceInfo *info, - const gchar *name) + * Since: 2.26 + */ +GDBusSignalInfo * +g_dbus_interface_info_lookup_signal (GDBusInterfaceInfo *info, + const gchar *name) { guint n; - const GDBusSignalInfo *result; + GDBusSignalInfo *result; + + G_LOCK (info_cache_lock); + if (G_LIKELY (info_cache != NULL)) + { + InfoCacheEntry *cache; + cache = g_hash_table_lookup (info_cache, info); + if (G_LIKELY (cache != NULL)) + { + result = g_hash_table_lookup (cache->signal_name_to_data, name); + G_UNLOCK (info_cache_lock); + goto out; + } + } + G_UNLOCK (info_cache_lock); for (n = 0; info->signals != NULL && info->signals[n] != NULL; n++) { - const GDBusSignalInfo *i = info->signals[n]; + GDBusSignalInfo *i = info->signals[n]; if (g_strcmp0 (i->name, name) == 0) { @@ -1943,20 +2018,37 @@ g_dbus_interface_info_lookup_signal (const GDBusInterfaceInfo *info, * * Looks up information about a property. * - * This cost of this function is O(n) in number of properties. + * The cost of this function is O(n) in number of properties unless + * g_dbus_interface_info_cache_build() has been used on @info. * - * Returns: A #GDBusPropertyInfo or %NULL if not found. Do not free, it is owned by @info. - **/ -const GDBusPropertyInfo * -g_dbus_interface_info_lookup_property (const GDBusInterfaceInfo *info, - const gchar *name) + * Returns: (transfer none): A #GDBusPropertyInfo or %NULL if not found. Do not free, it is owned by @info. + * + * Since: 2.26 + */ +GDBusPropertyInfo * +g_dbus_interface_info_lookup_property (GDBusInterfaceInfo *info, + const gchar *name) { guint n; - const GDBusPropertyInfo *result; + GDBusPropertyInfo *result; + + G_LOCK (info_cache_lock); + if (G_LIKELY (info_cache != NULL)) + { + InfoCacheEntry *cache; + cache = g_hash_table_lookup (info_cache, info); + if (G_LIKELY (cache != NULL)) + { + result = g_hash_table_lookup (cache->property_name_to_data, name); + G_UNLOCK (info_cache_lock); + goto out; + } + } + G_UNLOCK (info_cache_lock); for (n = 0; info->properties != NULL && info->properties[n] != NULL; n++) { - const GDBusPropertyInfo *i = info->properties[n]; + GDBusPropertyInfo *i = info->properties[n]; if (g_strcmp0 (i->name, name) == 0) { @@ -1974,26 +2066,117 @@ g_dbus_interface_info_lookup_property (const GDBusInterfaceInfo *info, /* ---------------------------------------------------------------------------------------------------- */ /** + * g_dbus_interface_info_cache_build: + * @info: A #GDBusInterfaceInfo. + * + * Builds a lookup-cache to speed up + * g_dbus_interface_info_lookup_method(), + * g_dbus_interface_info_lookup_signal() and + * g_dbus_interface_info_lookup_property(). + * + * If this has already been called with @info, the existing cache is + * used and its use count is increased. + * + * Note that @info cannot be modified until + * g_dbus_interface_info_cache_release() is called. + * + * Since: 2.30 + */ +void +g_dbus_interface_info_cache_build (GDBusInterfaceInfo *info) +{ + InfoCacheEntry *cache; + guint n; + + G_LOCK (info_cache_lock); + if (info_cache == NULL) + info_cache = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) info_cache_free); + cache = g_hash_table_lookup (info_cache, info); + if (cache != NULL) + { + cache->use_count += 1; + goto out; + } + cache = g_slice_new0 (InfoCacheEntry); + cache->use_count = 1; + cache->method_name_to_data = g_hash_table_new (g_str_hash, g_str_equal); + cache->signal_name_to_data = g_hash_table_new (g_str_hash, g_str_equal); + cache->property_name_to_data = g_hash_table_new (g_str_hash, g_str_equal); + for (n = 0; info->methods != NULL && info->methods[n] != NULL; n++) + g_hash_table_insert (cache->method_name_to_data, info->methods[n]->name, info->methods[n]); + for (n = 0; info->signals != NULL && info->signals[n] != NULL; n++) + g_hash_table_insert (cache->signal_name_to_data, info->signals[n]->name, info->signals[n]); + for (n = 0; info->properties != NULL && info->properties[n] != NULL; n++) + g_hash_table_insert (cache->property_name_to_data, info->properties[n]->name, info->properties[n]); + g_hash_table_insert (info_cache, info, cache); + out: + G_UNLOCK (info_cache_lock); +} + +/** + * g_dbus_interface_info_cache_release: + * @info: A GDBusInterfaceInfo + * + * Decrements the usage count for the cache for @info built by + * g_dbus_interface_info_cache_build() (if any) and frees the + * resources used by the cache if the usage count drops to zero. + * + * Since: 2.30 + */ +void +g_dbus_interface_info_cache_release (GDBusInterfaceInfo *info) +{ + InfoCacheEntry *cache; + + G_LOCK (info_cache_lock); + if (G_UNLIKELY (info_cache == NULL)) + { + g_warning ("%s called for interface %s but there is no cache", info->name, G_STRFUNC); + goto out; + } + + cache = g_hash_table_lookup (info_cache, info); + if (G_UNLIKELY (cache == NULL)) + { + g_warning ("%s called for interface %s but there is no cache entry", info->name, G_STRFUNC); + goto out; + } + cache->use_count -= 1; + if (cache->use_count == 0) + { + g_hash_table_remove (info_cache, info); + /* could nuke info_cache itself if empty */ + } + out: + G_UNLOCK (info_cache_lock); +} + + +/* ---------------------------------------------------------------------------------------------------- */ + +/** * g_dbus_node_info_lookup_interface: - * @node_info: A #GDBusNodeInfo. + * @info: A #GDBusNodeInfo. * @name: A D-Bus interface name. * * Looks up information about an interface. * - * This cost of this function is O(n) in number of interfaces. + * The cost of this function is O(n) in number of interfaces. + * + * Returns: (transfer none): A #GDBusInterfaceInfo or %NULL if not found. Do not free, it is owned by @info. * - * Returns: A #GDBusInterfaceInfo or %NULL if not found. Do not free, it is owned by @node_info. - **/ -const GDBusInterfaceInfo * -g_dbus_node_info_lookup_interface (const GDBusNodeInfo *node_info, - const gchar *name) + * Since: 2.26 + */ +GDBusInterfaceInfo * +g_dbus_node_info_lookup_interface (GDBusNodeInfo *info, + const gchar *name) { guint n; - const GDBusInterfaceInfo *result; + GDBusInterfaceInfo *result; - for (n = 0; node_info->interfaces != NULL && node_info->interfaces[n] != NULL; n++) + for (n = 0; info->interfaces != NULL && info->interfaces[n] != NULL; n++) { - const GDBusInterfaceInfo *i = node_info->interfaces[n]; + GDBusInterfaceInfo *i = info->interfaces[n]; if (g_strcmp0 (i->name, name) == 0) {