diff --git a/girepository.c b/girepository.c index 1afba0c80..a2a778d91 100644 --- a/girepository.c +++ b/girepository.c @@ -45,6 +45,7 @@ struct _GIRepositoryPrivate GHashTable *typelibs; /* (string) namespace -> GITypelib */ GHashTable *lazy_typelibs; /* (string) namespace-version -> GITypelib */ GHashTable *info_by_gtype; /* GType -> GIBaseInfo */ + GHashTable *info_by_error_domain; /* GQuark -> GIBaseInfo */ }; G_DEFINE_TYPE (GIRepository, g_irepository, G_TYPE_OBJECT); @@ -64,6 +65,10 @@ g_irepository_init (GIRepository *repository) = g_hash_table_new_full (g_direct_hash, g_direct_equal, (GDestroyNotify) NULL, (GDestroyNotify) g_base_info_unref); + repository->priv->info_by_error_domain + = g_hash_table_new_full (g_direct_hash, g_direct_equal, + (GDestroyNotify) NULL, + (GDestroyNotify) g_base_info_unref); } static void @@ -74,6 +79,7 @@ g_irepository_finalize (GObject *object) g_hash_table_destroy (repository->priv->typelibs); g_hash_table_destroy (repository->priv->lazy_typelibs); g_hash_table_destroy (repository->priv->info_by_gtype); + g_hash_table_destroy (repository->priv->info_by_error_domain); (* G_OBJECT_CLASS (g_irepository_parent_class)->finalize) (G_OBJECT (repository)); } @@ -675,6 +681,83 @@ g_irepository_find_by_name (GIRepository *repository, NULL, typelib, entry->offset); } +typedef struct { + GIRepository *repository; + GQuark domain; + + GITypelib *result_typelib; + DirEntry *result; +} FindByErrorDomainData; + +static void +find_by_error_domain_foreach (gpointer key, + gpointer value, + gpointer datap) +{ + GITypelib *typelib = (GITypelib*)value; + FindByErrorDomainData *data = datap; + + if (data->result != NULL) + return; + + data->result = g_typelib_get_dir_entry_by_error_domain (typelib, data->domain); + if (data->result) + data->result_typelib = typelib; +} + +/** + * g_irepository_find_by_error_domain: + * @repository: (allow-none): A #GIRepository, may be %NULL for the default + * @domain: a #GError domain + * + * Searches for the enum type corresponding to the given #GError + * domain. Before calling this function for a particular namespace, + * you must call g_irepository_require() once to load the namespace, or + * otherwise ensure the namespace has already been loaded. + * + * Returns: (transfer full): #GIEnumInfo representing metadata about @domain's + * enum type, or %NULL + * + * Since: 1.29.17 + */ +GIEnumInfo * +g_irepository_find_by_error_domain (GIRepository *repository, + GQuark domain) +{ + FindByErrorDomainData data; + GIEnumInfo *cached; + + repository = get_repository (repository); + + cached = g_hash_table_lookup (repository->priv->info_by_error_domain, + GUINT_TO_POINTER (domain)); + + if (cached != NULL) + return g_base_info_ref ((GIBaseInfo *)cached); + + data.repository = repository; + data.domain = domain; + data.result_typelib = NULL; + data.result = NULL; + + g_hash_table_foreach (repository->priv->typelibs, find_by_error_domain_foreach, &data); + if (data.result == NULL) + g_hash_table_foreach (repository->priv->lazy_typelibs, find_by_error_domain_foreach, &data); + + if (data.result != NULL) + { + cached = _g_info_new_full (data.result->blob_type, + repository, + NULL, data.result_typelib, data.result->offset); + + g_hash_table_insert (repository->priv->info_by_error_domain, + GUINT_TO_POINTER (domain), + g_base_info_ref (cached)); + return cached; + } + return NULL; +} + static void collect_namespaces (gpointer key, gpointer value, diff --git a/girepository.h b/girepository.h index fddcf8c16..9e99f6e31 100644 --- a/girepository.h +++ b/girepository.h @@ -123,6 +123,8 @@ gint g_irepository_get_n_infos (GIRepository *repository, GIBaseInfo * g_irepository_get_info (GIRepository *repository, const gchar *namespace_, gint index); +GIEnumInfo * g_irepository_find_by_error_domain (GIRepository *repository, + GQuark domain); const gchar * g_irepository_get_typelib_path (GIRepository *repository, const gchar *namespace_); const gchar * g_irepository_get_shared_library (GIRepository *repository, diff --git a/gitypelib-internal.h b/gitypelib-internal.h index 49fbe4e3e..1dde5163b 100644 --- a/gitypelib-internal.h +++ b/gitypelib-internal.h @@ -1117,6 +1117,9 @@ DirEntry *g_typelib_get_dir_entry_by_gtype (GITypelib *typelib, gboolean fastpass, GType gtype); +DirEntry *g_typelib_get_dir_entry_by_error_domain (GITypelib *typelib, + GQuark error_domain); + void g_typelib_check_sanity (void); #define g_typelib_get_string(typelib,offset) ((const gchar*)&(typelib->data)[(offset)]) diff --git a/gitypelib.c b/gitypelib.c index 3869a6d25..f610d4586 100644 --- a/gitypelib.c +++ b/gitypelib.c @@ -249,6 +249,36 @@ g_typelib_get_dir_entry_by_gtype (GITypelib *typelib, return NULL; } +DirEntry * +g_typelib_get_dir_entry_by_error_domain (GITypelib *typelib, + GQuark error_domain) +{ + Header *header = (Header *)typelib->data; + guint n_entries = header->n_local_entries; + const char *domain_string = g_quark_to_string (error_domain); + DirEntry *entry; + guint i; + + for (i = 1; i <= n_entries; i++) + { + EnumBlob *blob; + const char *enum_domain_string; + + entry = g_typelib_get_dir_entry (typelib, i); + if (entry->blob_type != BLOB_TYPE_ENUM) + continue; + + blob = (EnumBlob *)(&typelib->data[entry->offset]); + if (!blob->error_domain) + continue; + + enum_domain_string = g_typelib_get_string (typelib, blob->error_domain); + if (strcmp (domain_string, enum_domain_string) == 0) + return entry; + } + return NULL; +} + void g_typelib_check_sanity (void) {