(root)/
glib-2.79.0/
girepository/
girepository.c
       1  /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
       2   * GObject introspection: Repository implementation
       3   *
       4   * Copyright (C) 2005 Matthias Clasen
       5   * Copyright (C) 2008 Colin Walters <walters@verbum.org>
       6   * Copyright (C) 2008 Red Hat, Inc.
       7   *
       8   * SPDX-License-Identifier: LGPL-2.1-or-later
       9   *
      10   * This library is free software; you can redistribute it and/or
      11   * modify it under the terms of the GNU Lesser General Public
      12   * License as published by the Free Software Foundation; either
      13   * version 2 of the License, or (at your option) any later version.
      14   *
      15   * This library is distributed in the hope that it will be useful,
      16   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      17   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      18   * Lesser General Public License for more details.
      19   *
      20   * You should have received a copy of the GNU Lesser General Public
      21   * License along with this library; if not, write to the
      22   * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      23   * Boston, MA 02111-1307, USA.
      24   */
      25  
      26  #include "config.h"
      27  
      28  #include <stdio.h>
      29  #include <string.h>
      30  #include <stdlib.h>
      31  
      32  #include <glib.h>
      33  #include <glib/gprintf.h>
      34  #include <gmodule.h>
      35  #include "girepository.h"
      36  #include "gitypelib-internal.h"
      37  #include "girepository-private.h"
      38  
      39  /**
      40   * GIRepository:
      41   *
      42   * `GIRepository` is used to manage repositories of namespaces. Namespaces
      43   * are represented on disk by type libraries (`.typelib` files).
      44   *
      45   * ### Discovery of type libraries
      46   *
      47   * `GIRepository` will typically look for a `girepository-1.0` directory
      48   * under the library directory used when compiling gobject-introspection. On a
      49   * standard Linux system this will end up being `/usr/lib/girepository-1.0`.
      50   *
      51   * It is possible to control the search paths programmatically, using
      52   * [func@GIRepository.Repository.prepend_search_path]. It is also possible to
      53   * modify the search paths by using the `GI_TYPELIB_PATH` environment variable.
      54   * The environment variable takes precedence over the default search path
      55   * and the [func@GIRepository.Repository.prepend_search_path] calls.
      56   *
      57   * Since: 2.80
      58   */
      59  
      60  static GIRepository *default_repository = NULL;
      61  static GPtrArray *typelib_search_path = NULL;
      62  
      63  typedef struct {
      64    guint n_interfaces;
      65    GIBaseInfo *interfaces[];
      66  } GTypeInterfaceCache;
      67  
      68  static void
      69  gtype_interface_cache_free (gpointer data)
      70  {
      71    GTypeInterfaceCache *cache = data;
      72    guint i;
      73  
      74    for (i = 0; i < cache->n_interfaces; i++)
      75      gi_base_info_unref ((GIBaseInfo*) cache->interfaces[i]);
      76    g_free (cache);
      77  }
      78  
      79  struct _GIRepositoryPrivate
      80  {
      81    GHashTable *typelibs; /* (string) namespace -> GITypelib */
      82    GHashTable *lazy_typelibs; /* (string) namespace-version -> GITypelib */
      83    GHashTable *info_by_gtype; /* GType -> GIBaseInfo */
      84    GHashTable *info_by_error_domain; /* GQuark -> GIBaseInfo */
      85    GHashTable *interfaces_for_gtype; /* GType -> GTypeInterfaceCache */
      86    GHashTable *unknown_gtypes; /* hashset of GType */
      87  };
      88  
      89  G_DEFINE_TYPE_WITH_CODE (GIRepository, gi_repository, G_TYPE_OBJECT, G_ADD_PRIVATE (GIRepository));
      90  
      91  #ifdef G_PLATFORM_WIN32
      92  
      93  #include <windows.h>
      94  
      95  static HMODULE girepository_dll = NULL;
      96  
      97  #ifdef DLL_EXPORT
      98  
      99  BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
     100  
     101  BOOL WINAPI
     102  DllMain (HINSTANCE hinstDLL,
     103  	 DWORD     fdwReason,
     104  	 LPVOID    lpvReserved)
     105  {
     106    if (fdwReason == DLL_PROCESS_ATTACH)
     107        girepository_dll = hinstDLL;
     108  
     109    return TRUE;
     110  }
     111  
     112  #endif
     113  
     114  #undef GOBJECT_INTROSPECTION_LIBDIR
     115  
     116  /* GOBJECT_INTROSPECTION_LIBDIR is used only in code called just once,
     117   * so no problem leaking this
     118   */
     119  #define GOBJECT_INTROSPECTION_LIBDIR \
     120    g_build_filename (g_win32_get_package_installation_directory_of_module (girepository_dll), \
     121  		    "lib", \
     122  		    NULL)
     123  
     124  #endif
     125  
     126  static void
     127  gi_repository_init (GIRepository *repository)
     128  {
     129    repository->priv = gi_repository_get_instance_private (repository);
     130    repository->priv->typelibs
     131      = g_hash_table_new_full (g_str_hash, g_str_equal,
     132  			     (GDestroyNotify) g_free,
     133  			     (GDestroyNotify) gi_typelib_free);
     134    repository->priv->lazy_typelibs
     135      = g_hash_table_new_full (g_str_hash, g_str_equal,
     136                               (GDestroyNotify) g_free,
     137                               (GDestroyNotify) NULL);
     138    repository->priv->info_by_gtype
     139      = g_hash_table_new_full (g_direct_hash, g_direct_equal,
     140                               (GDestroyNotify) NULL,
     141                               (GDestroyNotify) gi_base_info_unref);
     142    repository->priv->info_by_error_domain
     143      = g_hash_table_new_full (g_direct_hash, g_direct_equal,
     144                               (GDestroyNotify) NULL,
     145                               (GDestroyNotify) gi_base_info_unref);
     146    repository->priv->interfaces_for_gtype
     147      = g_hash_table_new_full (g_direct_hash, g_direct_equal,
     148                               (GDestroyNotify) NULL,
     149                               (GDestroyNotify) gtype_interface_cache_free);
     150    repository->priv->unknown_gtypes = g_hash_table_new (NULL, NULL);
     151  }
     152  
     153  static void
     154  gi_repository_finalize (GObject *object)
     155  {
     156    GIRepository *repository = GI_REPOSITORY (object);
     157  
     158    g_hash_table_destroy (repository->priv->typelibs);
     159    g_hash_table_destroy (repository->priv->lazy_typelibs);
     160    g_hash_table_destroy (repository->priv->info_by_gtype);
     161    g_hash_table_destroy (repository->priv->info_by_error_domain);
     162    g_hash_table_destroy (repository->priv->interfaces_for_gtype);
     163    g_hash_table_destroy (repository->priv->unknown_gtypes);
     164  
     165    (* G_OBJECT_CLASS (gi_repository_parent_class)->finalize) (G_OBJECT (repository));
     166  }
     167  
     168  static void
     169  gi_repository_class_init (GIRepositoryClass *class)
     170  {
     171    GObjectClass *gobject_class;
     172  
     173    gobject_class = G_OBJECT_CLASS (class);
     174  
     175    gobject_class->finalize = gi_repository_finalize;
     176  }
     177  
     178  static void
     179  init_globals (void)
     180  {
     181    static gsize initialized = 0;
     182  
     183    if (!g_once_init_enter (&initialized))
     184      return;
     185  
     186    if (default_repository == NULL)
     187      default_repository = gi_repository_new ();
     188  
     189    if (typelib_search_path == NULL)
     190      {
     191        const char *libdir;
     192        char *typelib_dir;
     193        const gchar *type_lib_path_env;
     194  
     195        /* This variable is intended to take precedence over both:
     196         *   - the default search path;
     197         *   - all gi_repository_prepend_search_path() calls.
     198         */
     199        type_lib_path_env = g_getenv ("GI_TYPELIB_PATH");
     200  
     201        if (type_lib_path_env)
     202          {
     203            gchar **custom_dirs;
     204  
     205            custom_dirs = g_strsplit (type_lib_path_env, G_SEARCHPATH_SEPARATOR_S, 0);
     206            typelib_search_path =
     207              g_ptr_array_new_take_null_terminated ((gpointer) g_steal_pointer (&custom_dirs), g_free);
     208          }
     209        else
     210          {
     211            typelib_search_path = g_ptr_array_new_null_terminated (1, g_free, TRUE);
     212          }
     213  
     214        libdir = GOBJECT_INTROSPECTION_LIBDIR;
     215  
     216        typelib_dir = g_build_filename (libdir, "girepository-1.0", NULL);
     217  
     218        g_ptr_array_add (typelib_search_path, g_steal_pointer (&typelib_dir));
     219      }
     220  
     221    g_once_init_leave (&initialized, 1);
     222  }
     223  
     224  /**
     225   * gi_repository_prepend_search_path:
     226   * @directory: (type filename): directory name to prepend to the typelib
     227   *   search path
     228   *
     229   * Prepends @directory to the typelib search path.
     230   *
     231   * See also: gi_repository_get_search_path().
     232   *
     233   * Since: 2.80
     234   */
     235  void
     236  gi_repository_prepend_search_path (const char *directory)
     237  {
     238    init_globals ();
     239    g_ptr_array_insert (typelib_search_path, 0, g_strdup (directory));
     240  }
     241  
     242  /**
     243   * gi_repository_get_search_path:
     244   * @n_paths_out: (optional) (out): The number of search paths returned.
     245   *
     246   * Returns the current search path [class@GIRepository.Repository] will use when
     247   * loading typelib files.
     248   *
     249   * The list is internal to [class@GIRepository.Repository] and should not be
     250   * freed, nor should its string elements.
     251   *
     252   * Returns: (element-type filename) (transfer none) (array length=n_paths_out): list of search paths, most
     253   *   important first
     254   * Since: 2.80
     255   */
     256  const char * const *
     257  gi_repository_get_search_path (size_t *n_paths_out)
     258  {
     259    if G_UNLIKELY (!typelib_search_path || !typelib_search_path->pdata)
     260      {
     261        static const char * const empty_search_path[] = {NULL};
     262  
     263        if (n_paths_out)
     264          *n_paths_out = 0;
     265  
     266        return empty_search_path;
     267      }
     268  
     269    if (n_paths_out)
     270      *n_paths_out = typelib_search_path->len;
     271  
     272    return (const char * const *) typelib_search_path->pdata;
     273  }
     274  
     275  static char *
     276  build_typelib_key (const char *name, const char *source)
     277  {
     278    GString *str = g_string_new (name);
     279    g_string_append_c (str, '\0');
     280    g_string_append (str, source);
     281    return g_string_free (str, FALSE);
     282  }
     283  
     284  /* Note: Returns %NULL (not an empty %NULL-terminated array) if there are no
     285   * dependencies. */
     286  static char **
     287  get_typelib_dependencies (GITypelib *typelib)
     288  {
     289    Header *header;
     290    const char *dependencies_glob;
     291  
     292    header = (Header *)typelib->data;
     293  
     294    if (header->dependencies == 0)
     295      return NULL;
     296  
     297    dependencies_glob = gi_typelib_get_string (typelib, header->dependencies);
     298    return g_strsplit (dependencies_glob, "|", 0);
     299  }
     300  
     301  static GIRepository *
     302  get_repository (GIRepository *repository)
     303  {
     304    init_globals ();
     305  
     306    if (repository != NULL)
     307      return repository;
     308    else
     309      return default_repository;
     310  }
     311  
     312  static GITypelib *
     313  check_version_conflict (GITypelib *typelib,
     314  			const gchar *namespace,
     315  			const gchar *expected_version,
     316  			char       **version_conflict)
     317  {
     318    Header *header;
     319    const char *loaded_version;
     320  
     321    if (expected_version == NULL)
     322      {
     323        if (version_conflict)
     324  	*version_conflict = NULL;
     325        return typelib;
     326      }
     327  
     328    header = (Header*)typelib->data;
     329    loaded_version = gi_typelib_get_string (typelib, header->nsversion);
     330    g_assert (loaded_version != NULL);
     331  
     332    if (strcmp (expected_version, loaded_version) != 0)
     333      {
     334        if (version_conflict)
     335  	*version_conflict = (char*)loaded_version;
     336        return NULL;
     337      }
     338    if (version_conflict)
     339      *version_conflict = NULL;
     340    return typelib;
     341  }
     342  
     343  static GITypelib *
     344  get_registered_status (GIRepository *repository,
     345  		       const char   *namespace,
     346  		       const char   *version,
     347  		       gboolean      allow_lazy,
     348  		       gboolean     *lazy_status,
     349  		       char        **version_conflict)
     350  {
     351    GITypelib *typelib;
     352    repository = get_repository (repository);
     353    if (lazy_status)
     354      *lazy_status = FALSE;
     355    typelib = g_hash_table_lookup (repository->priv->typelibs, namespace);
     356    if (typelib)
     357      return check_version_conflict (typelib, namespace, version, version_conflict);
     358    typelib = g_hash_table_lookup (repository->priv->lazy_typelibs, namespace);
     359    if (!typelib)
     360      return NULL;
     361    if (lazy_status)
     362      *lazy_status = TRUE;
     363    if (!allow_lazy)
     364      return NULL;
     365    return check_version_conflict (typelib, namespace, version, version_conflict);
     366  }
     367  
     368  static GITypelib *
     369  get_registered (GIRepository *repository,
     370  		const char   *namespace,
     371  		const char   *version)
     372  {
     373    return get_registered_status (repository, namespace, version, TRUE, NULL, NULL);
     374  }
     375  
     376  static gboolean
     377  load_dependencies_recurse (GIRepository *repository,
     378  			   GITypelib     *typelib,
     379  			   GError      **error)
     380  {
     381    char **dependencies;
     382  
     383    dependencies = get_typelib_dependencies (typelib);
     384  
     385    if (dependencies != NULL)
     386      {
     387        int i;
     388  
     389        for (i = 0; dependencies[i]; i++)
     390  	{
     391  	  char *dependency = dependencies[i];
     392  	  const char *last_dash;
     393  	  char *dependency_namespace;
     394  	  const char *dependency_version;
     395  
     396  	  last_dash = strrchr (dependency, '-');
     397  	  dependency_namespace = g_strndup (dependency, last_dash - dependency);
     398  	  dependency_version = last_dash+1;
     399  
     400  	  if (!gi_repository_require (repository, dependency_namespace, dependency_version,
     401  				      0, error))
     402  	    {
     403  	      g_free (dependency_namespace);
     404  	      g_strfreev (dependencies);
     405  	      return FALSE;
     406  	    }
     407  	  g_free (dependency_namespace);
     408  	}
     409        g_strfreev (dependencies);
     410      }
     411    return TRUE;
     412  }
     413  
     414  static const char *
     415  register_internal (GIRepository *repository,
     416  		   const char   *source,
     417  		   gboolean      lazy,
     418  		   GITypelib     *typelib,
     419  		   GError      **error)
     420  {
     421    Header *header;
     422    const gchar *namespace;
     423  
     424    g_return_val_if_fail (typelib != NULL, FALSE);
     425  
     426    header = (Header *)typelib->data;
     427  
     428    g_return_val_if_fail (header != NULL, FALSE);
     429  
     430    namespace = gi_typelib_get_string (typelib, header->namespace);
     431  
     432    if (lazy)
     433      {
     434        g_assert (!g_hash_table_lookup (repository->priv->lazy_typelibs,
     435  				      namespace));
     436        g_hash_table_insert (repository->priv->lazy_typelibs,
     437  			   build_typelib_key (namespace, source), (void *)typelib);
     438      }
     439    else
     440      {
     441        gpointer value;
     442        char *key;
     443  
     444        /* First, try loading all the dependencies */
     445        if (!load_dependencies_recurse (repository, typelib, error))
     446  	return NULL;
     447  
     448        /* Check if we are transitioning from lazily loaded state */
     449        if (g_hash_table_lookup_extended (repository->priv->lazy_typelibs,
     450  					namespace,
     451  					(gpointer)&key, &value))
     452  	g_hash_table_remove (repository->priv->lazy_typelibs, key);
     453        else
     454  	key = build_typelib_key (namespace, source);
     455  
     456        g_hash_table_insert (repository->priv->typelibs,
     457                             g_steal_pointer (&key),
     458                             (void *)typelib);
     459      }
     460  
     461    /* These types might be resolved now, clear the cache */
     462    g_hash_table_remove_all (repository->priv->unknown_gtypes);
     463  
     464    return namespace;
     465  }
     466  
     467  /**
     468   * gi_repository_get_immediate_dependencies:
     469   * @repository: (nullable): A #GIRepository, or `NULL` for the singleton
     470   *   process-global default #GIRepository
     471   * @namespace_: Namespace of interest
     472   *
     473   * Return an array of the immediate versioned dependencies for @namespace_.
     474   * Returned strings are of the form `namespace-version`.
     475   *
     476   * Note: @namespace_ must have already been loaded using a function
     477   * such as [method@GIRepository.Repository.require] before calling this
     478   * function.
     479   *
     480   * To get the transitive closure of dependencies for @namespace_, use
     481   * [method@GIRepository.Repository.get_dependencies].
     482   *
     483   * Returns: (transfer full) (array zero-terminated=1): `NULL`-terminated string
     484   *   array of immediate versioned dependencies
     485   * Since: 2.80
     486   */
     487  char **
     488  gi_repository_get_immediate_dependencies (GIRepository *repository,
     489                                            const char   *namespace)
     490  {
     491    GITypelib *typelib;
     492    gchar **deps;
     493  
     494    g_return_val_if_fail (namespace != NULL, NULL);
     495  
     496    repository = get_repository (repository);
     497  
     498    typelib = get_registered (repository, namespace, NULL);
     499    g_return_val_if_fail (typelib != NULL, NULL);
     500  
     501    /* Ensure we always return a non-%NULL vector. */
     502    deps = get_typelib_dependencies (typelib);
     503    if (deps == NULL)
     504        deps = g_strsplit ("", "|", 0);
     505  
     506    return deps;
     507  }
     508  
     509  /* Load the transitive closure of dependency namespace-version strings for the
     510   * given @typelib. @repository must be non-%NULL. @transitive_dependencies must
     511   * be a pre-existing GHashTable<owned utf8, owned utf8> set for storing the
     512   * dependencies. */
     513  static void
     514  get_typelib_dependencies_transitive (GIRepository *repository,
     515                                       GITypelib    *typelib,
     516                                       GHashTable   *transitive_dependencies)
     517  {
     518    gchar **immediate_dependencies;
     519    guint i;
     520  
     521    immediate_dependencies = get_typelib_dependencies (typelib);
     522  
     523    for (i = 0; immediate_dependencies != NULL && immediate_dependencies[i]; i++)
     524      {
     525        gchar *dependency;
     526        const gchar *last_dash;
     527        gchar *dependency_namespace;
     528  
     529        dependency = immediate_dependencies[i];
     530  
     531        /* Steal from the strv. */
     532        g_hash_table_add (transitive_dependencies, dependency);
     533        immediate_dependencies[i] = NULL;
     534  
     535        /* Recurse for this namespace. */
     536        last_dash = strrchr (dependency, '-');
     537        dependency_namespace = g_strndup (dependency, last_dash - dependency);
     538  
     539        typelib = get_registered (repository, dependency_namespace, NULL);
     540        g_return_if_fail (typelib != NULL);
     541        get_typelib_dependencies_transitive (repository, typelib,
     542                                             transitive_dependencies);
     543  
     544        g_free (dependency_namespace);
     545      }
     546  
     547    g_free (immediate_dependencies);
     548  }
     549  
     550  /**
     551   * gi_repository_get_dependencies:
     552   * @repository: (nullable): A #GIRepository, or `NULL` for the singleton
     553   *   process-global default #GIRepository
     554   * @namespace_: Namespace of interest
     555   *
     556   * Retrieves all (transitive) versioned dependencies for
     557   * @namespace_.
     558   *
     559   * The returned strings are of the form `namespace-version`.
     560   *
     561   * Note: @namespace_ must have already been loaded using a function
     562   * such as [method@GIRepository.Repository.require] before calling this
     563   * function.
     564   *
     565   * To get only the immediate dependencies for @namespace_, use
     566   * [method@GIRepository.Repository.get_immediate_dependencies].
     567   *
     568   * Returns: (transfer full) (array zero-terminated=1): `NULL`-terminated string
     569   *   array of all versioned dependencies
     570   * Since: 2.80
     571   */
     572  char **
     573  gi_repository_get_dependencies (GIRepository *repository,
     574  				const char *namespace)
     575  {
     576    GITypelib *typelib;
     577    GHashTable *transitive_dependencies;  /* set of owned utf8 */
     578    GHashTableIter iter;
     579    gchar *dependency;
     580    GPtrArray *out;  /* owned utf8 elements */
     581  
     582    g_return_val_if_fail (namespace != NULL, NULL);
     583  
     584    repository = get_repository (repository);
     585  
     586    typelib = get_registered (repository, namespace, NULL);
     587    g_return_val_if_fail (typelib != NULL, NULL);
     588  
     589    /* Load the dependencies. */
     590    transitive_dependencies = g_hash_table_new_full (g_str_hash, g_str_equal,
     591                                                     g_free, NULL);
     592    get_typelib_dependencies_transitive (repository, typelib,
     593                                         transitive_dependencies);
     594  
     595    /* Convert to a string array. */
     596    out = g_ptr_array_new_null_terminated (g_hash_table_size (transitive_dependencies),
     597                                           g_free, TRUE);
     598    g_hash_table_iter_init (&iter, transitive_dependencies);
     599  
     600    while (g_hash_table_iter_next (&iter, (gpointer) &dependency, NULL))
     601      {
     602        g_ptr_array_add (out, dependency);
     603        g_hash_table_iter_steal (&iter);
     604      }
     605  
     606    g_hash_table_unref (transitive_dependencies);
     607  
     608    return (gchar **) g_ptr_array_free (out, FALSE);
     609  }
     610  
     611  /**
     612   * gi_repository_load_typelib:
     613   * @repository: (nullable): A #GIRepository, or `NULL` for the singleton
     614   *   process-global default #GIRepository
     615   * @typelib: the typelib to load
     616   * @flags: flags affecting the loading operation
     617   * @error: return location for a [type@GLib.Error], or `NULL`
     618   *
     619   * Load the given @typelib into the repository.
     620   *
     621   * Returns: namespace of the loaded typelib
     622   * Since: 2.80
     623   */
     624  const char *
     625  gi_repository_load_typelib (GIRepository *repository,
     626  			    GITypelib     *typelib,
     627  			    GIRepositoryLoadFlags flags,
     628  			    GError      **error)
     629  {
     630    Header *header;
     631    const char *namespace;
     632    const char *nsversion;
     633    gboolean allow_lazy = flags & GI_REPOSITORY_LOAD_FLAG_LAZY;
     634    gboolean is_lazy;
     635    char *version_conflict;
     636  
     637    repository = get_repository (repository);
     638  
     639    header = (Header *) typelib->data;
     640    namespace = gi_typelib_get_string (typelib, header->namespace);
     641    nsversion = gi_typelib_get_string (typelib, header->nsversion);
     642  
     643    if (get_registered_status (repository, namespace, nsversion, allow_lazy,
     644  			     &is_lazy, &version_conflict))
     645      {
     646        if (version_conflict != NULL)
     647  	{
     648  	  g_set_error (error, GI_REPOSITORY_ERROR,
     649  		       GI_REPOSITORY_ERROR_NAMESPACE_VERSION_CONFLICT,
     650  		       "Attempting to load namespace '%s', version '%s', but '%s' is already loaded",
     651  		       namespace, nsversion, version_conflict);
     652  	  return NULL;
     653  	}
     654        return namespace;
     655      }
     656    return register_internal (repository, "<builtin>",
     657  			    allow_lazy, typelib, error);
     658  }
     659  
     660  /**
     661   * gi_repository_is_registered:
     662   * @repository: (nullable): A #GIRepository, or `NULL` for the singleton
     663   *   process-global default #GIRepository
     664   * @namespace_: Namespace of interest
     665   * @version: (nullable): Required version, may be `NULL` for latest
     666   *
     667   * Check whether a particular namespace (and optionally, a specific
     668   * version thereof) is currently loaded.
     669   *
     670   * This function is likely to only be useful in unusual circumstances; in order
     671   * to act upon metadata in the namespace, you should call
     672   * [method@GIRepository.Repository.require] instead which will ensure the
     673   * namespace is loaded, and return as quickly as this function will if it has
     674   * already been loaded.
     675   *
     676   * Returns: `TRUE` if namespace-version is loaded, `FALSE` otherwise
     677   * Since: 2.80
     678   */
     679  gboolean
     680  gi_repository_is_registered (GIRepository *repository,
     681  			     const gchar *namespace,
     682  			     const gchar *version)
     683  {
     684    repository = get_repository (repository);
     685    return get_registered (repository, namespace, version) != NULL;
     686  }
     687  
     688  /**
     689   * gi_repository_get_default:
     690   *
     691   * Returns the singleton process-global default #GIRepository.
     692   *
     693   * It is not currently supported to have multiple repositories in a
     694   * particular process, but this function is provided in the unlikely
     695   * eventuality that it would become possible, and as a convenience for
     696   * higher level language bindings to conform to the GObject method
     697   * call conventions.
     698   *
     699   * All methods on #GIRepository also accept `NULL` as an instance
     700   * parameter to mean this default repository, which is usually more
     701   * convenient for C.
     702   *
     703   * Returns: (transfer none): The global singleton [class@GIRepository.Repository]
     704   * Since: 2.80
     705   */
     706  GIRepository *
     707  gi_repository_get_default (void)
     708  {
     709    return get_repository (NULL);
     710  }
     711  
     712  /**
     713   * gi_repository_new:
     714   *
     715   * Create a new (non-singleton) [class@GIRepository.Repository].
     716   *
     717   * Most callers should use [func@GIRepository.Repository.get_default] instead,
     718   * as a singleton repository is more useful in most situations.
     719   *
     720   * Returns: (transfer full): a new [class@GIRepository.Repository]
     721   * Since: 2.80
     722   */
     723  GIRepository *
     724  gi_repository_new (void)
     725  {
     726    return g_object_new (GI_TYPE_REPOSITORY, NULL);
     727  }
     728  
     729  /**
     730   * gi_repository_get_n_infos:
     731   * @repository: (nullable): A #GIRepository, or `NULL` for the singleton
     732   *   process-global default #GIRepository
     733   * @namespace_: Namespace to inspect
     734   *
     735   * This function returns the number of metadata entries in
     736   * given namespace @namespace_.
     737   *
     738   * The namespace must have already been loaded before calling this function.
     739   *
     740   * Returns: number of metadata entries
     741   * Since: 2.80
     742   */
     743  guint
     744  gi_repository_get_n_infos (GIRepository *repository,
     745  			   const gchar  *namespace)
     746  {
     747    GITypelib *typelib;
     748    guint n_interfaces = 0;
     749  
     750    g_return_val_if_fail (namespace != NULL, -1);
     751  
     752    repository = get_repository (repository);
     753  
     754    typelib = get_registered (repository, namespace, NULL);
     755  
     756    g_return_val_if_fail (typelib != NULL, -1);
     757  
     758    n_interfaces = ((Header *)typelib->data)->n_local_entries;
     759  
     760    return n_interfaces;
     761  }
     762  
     763  /**
     764   * gi_repository_get_info:
     765   * @repository: (nullable): A #GIRepository, or `NULL` for the singleton
     766   *   process-global default #GIRepository
     767   * @namespace_: Namespace to inspect
     768   * @idx: 0-based offset into namespace metadata for entry
     769   *
     770   * This function returns a particular metadata entry in the
     771   * given namespace @namespace_.
     772   *
     773   * The namespace must have already been loaded before calling this function.
     774   * See [method@GIRepository.Repository.get_n_infos] to find the maximum number
     775   * of entries.
     776   *
     777   * Returns: (transfer full) (nullable): [class@GIRepository.BaseInfo] containing
     778   *   metadata, or `NULL` if @idx was too high
     779   * Since: 2.80
     780   */
     781  GIBaseInfo *
     782  gi_repository_get_info (GIRepository *repository,
     783  			const gchar  *namespace,
     784  			guint         idx)
     785  {
     786    GITypelib *typelib;
     787    DirEntry *entry;
     788  
     789    g_return_val_if_fail (namespace != NULL, NULL);
     790  
     791    repository = get_repository (repository);
     792  
     793    typelib = get_registered (repository, namespace, NULL);
     794  
     795    g_return_val_if_fail (typelib != NULL, NULL);
     796  
     797    entry = gi_typelib_get_dir_entry (typelib, idx + 1);
     798    if (entry == NULL)
     799      return NULL;
     800    return gi_info_new_full (entry->blob_type,
     801                             repository,
     802                             NULL, typelib, entry->offset);
     803  }
     804  
     805  typedef struct {
     806    const gchar *gtype_name;
     807    GITypelib *result_typelib;
     808  } FindByGTypeData;
     809  
     810  static DirEntry *
     811  find_by_gtype (GHashTable *table, FindByGTypeData *data, gboolean check_prefix)
     812  {
     813    GHashTableIter iter;
     814    gpointer key, value;
     815    DirEntry *ret;
     816  
     817    g_hash_table_iter_init (&iter, table);
     818    while (g_hash_table_iter_next (&iter, &key, &value))
     819      {
     820        GITypelib *typelib = (GITypelib*)value;
     821        if (check_prefix)
     822          {
     823            if (!gi_typelib_matches_gtype_name_prefix (typelib, data->gtype_name))
     824              continue;
     825          }
     826  
     827        ret = gi_typelib_get_dir_entry_by_gtype_name (typelib, data->gtype_name);
     828        if (ret)
     829          {
     830            data->result_typelib = typelib;
     831            return ret;
     832          }
     833      }
     834  
     835    return NULL;
     836  }
     837  
     838  /**
     839   * gi_repository_find_by_gtype:
     840   * @repository: (nullable): A #GIRepository, or `NULL` for the singleton
     841   *   process-global default #GIRepository
     842   * @gtype: [type@GObject.Type] to search for
     843   *
     844   * Searches all loaded namespaces for a particular [type@GObject.Type].
     845   *
     846   * Note that in order to locate the metadata, the namespace corresponding to
     847   * the type must first have been loaded.  There is currently no
     848   * mechanism for determining the namespace which corresponds to an
     849   * arbitrary [type@GObject.Type] — thus, this function will operate most
     850   * reliably when you know the [type@GObject.Type] is from a loaded namespace.
     851   *
     852   * Returns: (transfer full) (nullable): [class@GIRepository.BaseInfo]
     853   *   representing metadata about @type, or `NULL` if none found
     854   * Since: 2.80
     855   */
     856  GIBaseInfo *
     857  gi_repository_find_by_gtype (GIRepository *repository,
     858                               GType         gtype)
     859  {
     860    FindByGTypeData data;
     861    GIBaseInfo *cached;
     862    DirEntry *entry;
     863  
     864    g_return_val_if_fail (gtype != G_TYPE_INVALID, NULL);
     865  
     866    repository = get_repository (repository);
     867  
     868    cached = g_hash_table_lookup (repository->priv->info_by_gtype,
     869  				(gpointer)gtype);
     870  
     871    if (cached != NULL)
     872      return gi_base_info_ref (cached);
     873  
     874    if (g_hash_table_contains (repository->priv->unknown_gtypes, (gpointer)gtype))
     875      return NULL;
     876  
     877    data.gtype_name = g_type_name (gtype);
     878    data.result_typelib = NULL;
     879  
     880    /* Inside each typelib, we include the "C prefix" which acts as
     881     * a namespace mechanism.  For GtkTreeView, the C prefix is Gtk.
     882     * Given the assumption that GTypes for a library also use the
     883     * C prefix, we know we can skip examining a typelib if our
     884     * target type does not have this typelib's C prefix. Use this
     885     * assumption as our first attempt at locating the DirEntry.
     886     */
     887    entry = find_by_gtype (repository->priv->typelibs, &data, TRUE);
     888    if (entry == NULL)
     889      entry = find_by_gtype (repository->priv->lazy_typelibs, &data, TRUE);
     890  
     891    /* Not ever class library necessarily specifies a correct c_prefix,
     892     * so take a second pass. This time we will try a global lookup,
     893     * ignoring prefixes.
     894     * See http://bugzilla.gnome.org/show_bug.cgi?id=564016
     895     */
     896    if (entry == NULL)
     897      entry = find_by_gtype (repository->priv->typelibs, &data, FALSE);
     898    if (entry == NULL)
     899      entry = find_by_gtype (repository->priv->lazy_typelibs, &data, FALSE);
     900  
     901    if (entry != NULL)
     902      {
     903        cached = gi_info_new_full (entry->blob_type,
     904                                   repository,
     905                                   NULL, data.result_typelib, entry->offset);
     906  
     907        g_hash_table_insert (repository->priv->info_by_gtype,
     908  			   (gpointer) gtype,
     909  			   gi_base_info_ref (cached));
     910        return cached;
     911      }
     912    else
     913      {
     914        g_hash_table_add (repository->priv->unknown_gtypes, (gpointer) gtype);
     915        return NULL;
     916      }
     917  }
     918  
     919  /**
     920   * gi_repository_find_by_name:
     921   * @repository: (nullable): A #GIRepository, or `NULL` for the singleton
     922   *   process-global default #GIRepository
     923   * @namespace_: Namespace which will be searched
     924   * @name: Entry name to find
     925   *
     926   * Searches for a particular entry in a namespace.
     927   *
     928   * Before calling this function for a particular namespace, you must call
     929   * [method@GIRepository.Repository.require] to load the namespace, or otherwise
     930   * ensure the namespace has already been loaded.
     931   *
     932   * Returns: (transfer full) (nullable): [class@GIRepository.BaseInfo]
     933   *   representing metadata about @name, or `NULL` if none found
     934   * Since: 2.80
     935   */
     936  GIBaseInfo *
     937  gi_repository_find_by_name (GIRepository *repository,
     938  			    const gchar  *namespace,
     939  			    const gchar  *name)
     940  {
     941    GITypelib *typelib;
     942    DirEntry *entry;
     943  
     944    g_return_val_if_fail (namespace != NULL, NULL);
     945  
     946    repository = get_repository (repository);
     947    typelib = get_registered (repository, namespace, NULL);
     948    g_return_val_if_fail (typelib != NULL, NULL);
     949  
     950    entry = gi_typelib_get_dir_entry_by_name (typelib, name);
     951    if (entry == NULL)
     952      return NULL;
     953    return gi_info_new_full (entry->blob_type,
     954                             repository,
     955                             NULL, typelib, entry->offset);
     956  }
     957  
     958  typedef struct {
     959    GIRepository *repository;
     960    GQuark domain;
     961  
     962    GITypelib *result_typelib;
     963    DirEntry *result;
     964  } FindByErrorDomainData;
     965  
     966  static void
     967  find_by_error_domain_foreach (gpointer key,
     968  			      gpointer value,
     969  			      gpointer datap)
     970  {
     971    GITypelib *typelib = (GITypelib*)value;
     972    FindByErrorDomainData *data = datap;
     973  
     974    if (data->result != NULL)
     975      return;
     976  
     977    data->result = gi_typelib_get_dir_entry_by_error_domain (typelib, data->domain);
     978    if (data->result)
     979      data->result_typelib = typelib;
     980  }
     981  
     982  /**
     983   * gi_repository_find_by_error_domain:
     984   * @repository: (nullable): A #GIRepository, or `NULL` for the singleton
     985   *   process-global default #GIRepository
     986   * @domain: a [type@GLib.Error] domain
     987   *
     988   * Searches for the enum type corresponding to the given [type@GLib.Error]
     989   * domain.
     990   *
     991   * Before calling this function for a particular namespace, you must call
     992   * [method@GIRepository.Repository.require] to load the namespace, or otherwise
     993   * ensure the namespace has already been loaded.
     994   *
     995   * Returns: (transfer full) (nullable): [class@GIRepository.EnumInfo]
     996   *   representing metadata about @domain’s enum type, or `NULL` if none found
     997   * Since: 2.80
     998   */
     999  GIEnumInfo *
    1000  gi_repository_find_by_error_domain (GIRepository *repository,
    1001  				    GQuark        domain)
    1002  {
    1003    FindByErrorDomainData data;
    1004    GIEnumInfo *cached;
    1005  
    1006    repository = get_repository (repository);
    1007  
    1008    cached = g_hash_table_lookup (repository->priv->info_by_error_domain,
    1009  				GUINT_TO_POINTER (domain));
    1010  
    1011    if (cached != NULL)
    1012      return (GIEnumInfo *) gi_base_info_ref ((GIBaseInfo *)cached);
    1013  
    1014    data.repository = repository;
    1015    data.domain = domain;
    1016    data.result_typelib = NULL;
    1017    data.result = NULL;
    1018  
    1019    g_hash_table_foreach (repository->priv->typelibs, find_by_error_domain_foreach, &data);
    1020    if (data.result == NULL)
    1021      g_hash_table_foreach (repository->priv->lazy_typelibs, find_by_error_domain_foreach, &data);
    1022  
    1023    if (data.result != NULL)
    1024      {
    1025        cached = (GIEnumInfo *) gi_info_new_full (data.result->blob_type,
    1026                                                  repository,
    1027                                                  NULL, data.result_typelib, data.result->offset);
    1028  
    1029        g_hash_table_insert (repository->priv->info_by_error_domain,
    1030  			   GUINT_TO_POINTER (domain),
    1031  			   gi_base_info_ref ((GIBaseInfo *) cached));
    1032        return cached;
    1033      }
    1034    return NULL;
    1035  }
    1036  
    1037  /**
    1038   * gi_repository_get_object_gtype_interfaces:
    1039   * @repository: (nullable): a #GIRepository, or `NULL` for the default repository
    1040   * @gtype: a [type@GObject.Type] whose fundamental type is `G_TYPE_OBJECT`
    1041   * @n_interfaces_out: (out): Number of interfaces
    1042   * @interfaces_out: (out) (transfer none) (array length=n_interfaces_out): Interfaces for @gtype
    1043   *
    1044   * Look up the implemented interfaces for @gtype.
    1045   *
    1046   * This function cannot fail per se; but for a totally ‘unknown’
    1047   * [type@GObject.Type], it may return 0 implemented interfaces.
    1048   *
    1049   * The semantics of this function are designed for a dynamic binding,
    1050   * where in certain cases (such as a function which returns an
    1051   * interface which may have ‘hidden’ implementation classes), not all
    1052   * data may be statically known, and will have to be determined from
    1053   * the [type@GObject.Type] of the object.  An example is
    1054   * [func@Gio.File.new_for_path] returning a concrete class of
    1055   * `GLocalFile`, which is a [type@GObject.Type] we see at runtime, but
    1056   * not statically.
    1057   *
    1058   * Since: 2.80
    1059   */
    1060  void
    1061  gi_repository_get_object_gtype_interfaces (GIRepository      *repository,
    1062                                             GType              gtype,
    1063                                             gsize             *n_interfaces_out,
    1064                                             GIInterfaceInfo ***interfaces_out)
    1065  {
    1066    GTypeInterfaceCache *cache;
    1067  
    1068    g_return_if_fail (g_type_fundamental (gtype) == G_TYPE_OBJECT);
    1069  
    1070    repository = get_repository (repository);
    1071  
    1072    cache = g_hash_table_lookup (repository->priv->interfaces_for_gtype,
    1073                                 (gpointer) gtype);
    1074    if (cache == NULL)
    1075      {
    1076        GType *interfaces;
    1077        guint n_interfaces;
    1078        guint i;
    1079        GList *interface_infos = NULL, *iter;
    1080  
    1081        interfaces = g_type_interfaces (gtype, &n_interfaces);
    1082        for (i = 0; i < n_interfaces; i++)
    1083          {
    1084            GIBaseInfo *base_info;
    1085  
    1086            base_info = gi_repository_find_by_gtype (repository, interfaces[i]);
    1087            if (base_info == NULL)
    1088              continue;
    1089  
    1090            if (gi_base_info_get_info_type (base_info) != GI_INFO_TYPE_INTERFACE)
    1091              {
    1092                /* FIXME - could this really happen? */
    1093                gi_base_info_unref (base_info);
    1094                continue;
    1095              }
    1096  
    1097            if (!g_list_find (interface_infos, base_info))
    1098              interface_infos = g_list_prepend (interface_infos, base_info);
    1099          }
    1100  
    1101        cache = g_malloc (sizeof (GTypeInterfaceCache)
    1102                          + sizeof (GIBaseInfo*) * g_list_length (interface_infos));
    1103        cache->n_interfaces = g_list_length (interface_infos);
    1104        for (iter = interface_infos, i = 0; iter; iter = iter->next, i++)
    1105          cache->interfaces[i] = iter->data;
    1106        g_list_free (interface_infos);
    1107  
    1108        g_hash_table_insert (repository->priv->interfaces_for_gtype, (gpointer) gtype,
    1109                             cache);
    1110  
    1111        g_free (interfaces);
    1112      }
    1113  
    1114    *n_interfaces_out = cache->n_interfaces;
    1115    *interfaces_out = (GIInterfaceInfo**)&cache->interfaces[0];
    1116  }
    1117  
    1118  static void
    1119  collect_namespaces (gpointer key,
    1120  		    gpointer value,
    1121  		    gpointer data)
    1122  {
    1123    GList **list = data;
    1124  
    1125    *list = g_list_append (*list, key);
    1126  }
    1127  
    1128  /**
    1129   * gi_repository_get_loaded_namespaces:
    1130   * @repository: (nullable): A #GIRepository, or `NULL` for the singleton
    1131   *   process-global default #GIRepository
    1132   *
    1133   * Return the list of currently loaded namespaces.
    1134   *
    1135   * Returns: (element-type utf8) (transfer full) (array zero-terminated=1): `NULL`-terminated
    1136   *   list of namespaces
    1137   * Since: 2.80
    1138   */
    1139  gchar **
    1140  gi_repository_get_loaded_namespaces (GIRepository *repository)
    1141  {
    1142    GList *l, *list = NULL;
    1143    gchar **names;
    1144    gint i;
    1145  
    1146    repository = get_repository (repository);
    1147  
    1148    g_hash_table_foreach (repository->priv->typelibs, collect_namespaces, &list);
    1149    g_hash_table_foreach (repository->priv->lazy_typelibs, collect_namespaces, &list);
    1150  
    1151    names = g_malloc0 (sizeof (gchar *) * (g_list_length (list) + 1));
    1152    i = 0;
    1153    for (l = list; l; l = l->next)
    1154      names[i++] = g_strdup (l->data);
    1155    g_list_free (list);
    1156  
    1157    return names;
    1158  }
    1159  
    1160  /**
    1161   * gi_repository_get_version:
    1162   * @repository: (nullable): A #GIRepository, or `NULL` for the singleton
    1163   *   process-global default #GIRepository
    1164   * @namespace_: Namespace to inspect
    1165   *
    1166   * This function returns the loaded version associated with the given
    1167   * namespace @namespace_.
    1168   *
    1169   * Note: The namespace must have already been loaded using a function
    1170   * such as [method@GIRepository.Repository.require] before calling this
    1171   * function.
    1172   *
    1173   * Returns: Loaded version
    1174   * Since: 2.80
    1175   */
    1176  const gchar *
    1177  gi_repository_get_version (GIRepository *repository,
    1178  			   const gchar  *namespace)
    1179  {
    1180    GITypelib *typelib;
    1181    Header *header;
    1182  
    1183    g_return_val_if_fail (namespace != NULL, NULL);
    1184  
    1185    repository = get_repository (repository);
    1186  
    1187    typelib = get_registered (repository, namespace, NULL);
    1188  
    1189    g_return_val_if_fail (typelib != NULL, NULL);
    1190  
    1191    header = (Header *) typelib->data;
    1192    return gi_typelib_get_string (typelib, header->nsversion);
    1193  }
    1194  
    1195  /**
    1196   * gi_repository_get_shared_library:
    1197   * @repository: (nullable): A #GIRepository, or `NULL` for the singleton
    1198   *   process-global default #GIRepository
    1199   * @namespace_: Namespace to inspect
    1200   *
    1201   * This function returns a comma-separated list of paths to the
    1202   * shared C libraries associated with the given namespace @namespace_.
    1203   *
    1204   * There may be no shared library path associated, in which case this
    1205   * function will return `NULL`.
    1206   *
    1207   * Note: The namespace must have already been loaded using a function
    1208   * such as [method@GIRepository.Repository.require] before calling this
    1209   * function.
    1210   *
    1211   * Returns: (nullable): Comma-separated list of paths to shared libraries,
    1212   *   or `NULL` if none are associated
    1213   * Since: 2.80
    1214   */
    1215  const gchar *
    1216  gi_repository_get_shared_library (GIRepository *repository,
    1217  				  const gchar  *namespace)
    1218  {
    1219    GITypelib *typelib;
    1220    Header *header;
    1221  
    1222    g_return_val_if_fail (namespace != NULL, NULL);
    1223  
    1224    repository = get_repository (repository);
    1225  
    1226    typelib = get_registered (repository, namespace, NULL);
    1227  
    1228    g_return_val_if_fail (typelib != NULL, NULL);
    1229  
    1230    header = (Header *) typelib->data;
    1231    if (header->shared_library)
    1232      return gi_typelib_get_string (typelib, header->shared_library);
    1233    else
    1234      return NULL;
    1235  }
    1236  
    1237  /**
    1238   * gi_repository_get_c_prefix:
    1239   * @repository: (nullable): A #GIRepository, or `NULL` for the singleton
    1240   *   process-global default #GIRepository
    1241   * @namespace_: Namespace to inspect
    1242   *
    1243   * This function returns the ‘C prefix’, or the C level namespace
    1244   * associated with the given introspection namespace.
    1245   *
    1246   * Each C symbol starts with this prefix, as well each [type@GObject.Type] in
    1247   * the library.
    1248   *
    1249   * Note: The namespace must have already been loaded using a function
    1250   * such as [method@GIRepository.Repository.require] before calling this
    1251   * function.
    1252   *
    1253   * Returns: (nullable): C namespace prefix, or `NULL` if none associated
    1254   * Since: 2.80
    1255   */
    1256  const gchar *
    1257  gi_repository_get_c_prefix (GIRepository *repository,
    1258                              const gchar  *namespace_)
    1259  {
    1260    GITypelib *typelib;
    1261    Header *header;
    1262  
    1263    g_return_val_if_fail (namespace_ != NULL, NULL);
    1264  
    1265    repository = get_repository (repository);
    1266  
    1267    typelib = get_registered (repository, namespace_, NULL);
    1268  
    1269    g_return_val_if_fail (typelib != NULL, NULL);
    1270  
    1271    header = (Header *) typelib->data;
    1272    if (header->c_prefix)
    1273      return gi_typelib_get_string (typelib, header->c_prefix);
    1274    else
    1275      return NULL;
    1276  }
    1277  
    1278  /**
    1279   * gi_repository_get_typelib_path:
    1280   * @repository: (nullable): A #GIRepository, or `NULL` for the singleton
    1281   *   process-global default #GIRepository
    1282   * @namespace_: GI namespace to use, e.g. `Gtk`
    1283   *
    1284   * If namespace @namespace_ is loaded, return the full path to the
    1285   * .typelib file it was loaded from.
    1286   *
    1287   * If the typelib for namespace @namespace_ was included in a shared library,
    1288   * return the special string `<builtin>`.
    1289   *
    1290   * Returns: (type filename) (nullable): Filesystem path (or `<builtin>`) if
    1291   *   successful, `NULL` if namespace is not loaded
    1292   * Since: 2.80
    1293   */
    1294  const gchar *
    1295  gi_repository_get_typelib_path (GIRepository *repository,
    1296  				const gchar  *namespace)
    1297  {
    1298    gpointer orig_key, value;
    1299  
    1300    repository = get_repository (repository);
    1301  
    1302    if (!g_hash_table_lookup_extended (repository->priv->typelibs, namespace,
    1303  				     &orig_key, &value))
    1304      {
    1305        if (!g_hash_table_lookup_extended (repository->priv->lazy_typelibs, namespace,
    1306  					 &orig_key, &value))
    1307  
    1308  	return NULL;
    1309      }
    1310    return ((char*)orig_key) + strlen ((char *) orig_key) + 1;
    1311  }
    1312  
    1313  /* This simple search function looks for a specified namespace-version;
    1314     it's faster than the full directory listing required for latest version. */
    1315  static GMappedFile *
    1316  find_namespace_version (const char          *namespace,
    1317                          const char          *version,
    1318                          const char * const  *search_paths,
    1319                          size_t               n_search_paths,
    1320                          char               **path_ret)
    1321  {
    1322    GError *error = NULL;
    1323    GMappedFile *mfile = NULL;
    1324    char *fname;
    1325  
    1326    fname = g_strdup_printf ("%s-%s.typelib", namespace, version);
    1327  
    1328    for (size_t i = 0; i < n_search_paths; ++i)
    1329      {
    1330        char *path = g_build_filename (search_paths[i], fname, NULL);
    1331  
    1332        mfile = g_mapped_file_new (path, FALSE, &error);
    1333        if (error)
    1334  	{
    1335  	  g_free (path);
    1336  	  g_clear_error (&error);
    1337  	  continue;
    1338  	}
    1339        *path_ret = path;
    1340        break;
    1341      }
    1342    g_free (fname);
    1343    return mfile;
    1344  }
    1345  
    1346  static gboolean
    1347  parse_version (const char *version,
    1348  	       int *major,
    1349  	       int *minor)
    1350  {
    1351    const char *dot;
    1352    char *end;
    1353  
    1354    *major = strtol (version, &end, 10);
    1355    dot = strchr (version, '.');
    1356    if (dot == NULL)
    1357      {
    1358        *minor = 0;
    1359        return TRUE;
    1360      }
    1361    if (dot != end)
    1362      return FALSE;
    1363    *minor = strtol (dot+1, &end, 10);
    1364    if (end != (version + strlen (version)))
    1365      return FALSE;
    1366    return TRUE;
    1367  }
    1368  
    1369  static int
    1370  compare_version (const char *v1,
    1371  		 const char *v2)
    1372  {
    1373    gboolean success;
    1374    int v1_major, v1_minor;
    1375    int v2_major, v2_minor;
    1376  
    1377    success = parse_version (v1, &v1_major, &v1_minor);
    1378    g_assert (success);
    1379  
    1380    success = parse_version (v2, &v2_major, &v2_minor);
    1381    g_assert (success);
    1382  
    1383    /* Avoid a compiler warning about `success` being unused with G_DISABLE_ASSERT */
    1384    (void) success;
    1385  
    1386    if (v1_major > v2_major)
    1387      return 1;
    1388    else if (v2_major > v1_major)
    1389      return -1;
    1390    else if (v1_minor > v2_minor)
    1391      return 1;
    1392    else if (v2_minor > v1_minor)
    1393      return -1;
    1394    return 0;
    1395  }
    1396  
    1397  struct NamespaceVersionCandidadate
    1398  {
    1399    GMappedFile *mfile;
    1400    int path_index;
    1401    char *path;
    1402    char *version;
    1403  };
    1404  
    1405  static int
    1406  compare_candidate_reverse (struct NamespaceVersionCandidadate *c1,
    1407  			   struct NamespaceVersionCandidadate *c2)
    1408  {
    1409    int result = compare_version (c1->version, c2->version);
    1410    /* First, check the version */
    1411    if (result > 0)
    1412      return -1;
    1413    else if (result < 0)
    1414      return 1;
    1415    else
    1416      {
    1417        /* Now check the path index, which says how early in the search path
    1418         * we found it.  This ensures that of equal version targets, we
    1419         * pick the earlier one.
    1420         */
    1421        if (c1->path_index == c2->path_index)
    1422  	return 0;
    1423        else if (c1->path_index > c2->path_index)
    1424  	return 1;
    1425        else
    1426  	return -1;
    1427      }
    1428  }
    1429  
    1430  static void
    1431  free_candidate (struct NamespaceVersionCandidadate *candidate)
    1432  {
    1433    g_mapped_file_unref (candidate->mfile);
    1434    g_free (candidate->path);
    1435    g_free (candidate->version);
    1436    g_slice_free (struct NamespaceVersionCandidadate, candidate);
    1437  }
    1438  
    1439  static GSList *
    1440  enumerate_namespace_versions (const char         *namespace,
    1441                                const char * const *search_paths,
    1442                                size_t              n_search_paths)
    1443  {
    1444    GSList *candidates = NULL;
    1445    GHashTable *found_versions = g_hash_table_new (g_str_hash, g_str_equal);
    1446    char *namespace_dash;
    1447    char *namespace_typelib;
    1448    GError *error = NULL;
    1449    int index;
    1450  
    1451    namespace_dash = g_strdup_printf ("%s-", namespace);
    1452    namespace_typelib = g_strdup_printf ("%s.typelib", namespace);
    1453  
    1454    index = 0;
    1455    for (size_t i = 0; i < n_search_paths; ++i)
    1456      {
    1457        GDir *dir;
    1458        const char *dirname;
    1459        const char *entry;
    1460  
    1461        dirname = search_paths[i];
    1462        dir = g_dir_open (dirname, 0, NULL);
    1463        if (dir == NULL)
    1464  	continue;
    1465        while ((entry = g_dir_read_name (dir)) != NULL)
    1466  	{
    1467  	  GMappedFile *mfile;
    1468  	  char *path, *version;
    1469  	  struct NamespaceVersionCandidadate *candidate;
    1470  
    1471  	  if (!g_str_has_suffix (entry, ".typelib"))
    1472  	    continue;
    1473  
    1474  	  if (g_str_has_prefix (entry, namespace_dash))
    1475  	    {
    1476  	      const char *last_dash;
    1477  	      const char *name_end;
    1478  	      int major, minor;
    1479  
    1480  	      name_end = strrchr (entry, '.');
    1481  	      last_dash = strrchr (entry, '-');
    1482  	      version = g_strndup (last_dash+1, name_end-(last_dash+1));
    1483  	      if (!parse_version (version, &major, &minor))
    1484  		{
    1485  		  g_free (version);
    1486  		  continue;
    1487  		}
    1488  	    }
    1489  	  else
    1490  	    continue;
    1491  
    1492  	  if (g_hash_table_lookup (found_versions, version) != NULL)
    1493  	    {
    1494  	      g_free (version);
    1495  	      continue;
    1496  	    }
    1497  
    1498  	  path = g_build_filename (dirname, entry, NULL);
    1499  	  mfile = g_mapped_file_new (path, FALSE, &error);
    1500  	  if (mfile == NULL)
    1501  	    {
    1502  	      g_free (path);
    1503  	      g_free (version);
    1504  	      g_clear_error (&error);
    1505  	      continue;
    1506  	    }
    1507  	  candidate = g_slice_new0 (struct NamespaceVersionCandidadate);
    1508  	  candidate->mfile = mfile;
    1509  	  candidate->path_index = index;
    1510  	  candidate->path = path;
    1511  	  candidate->version = version;
    1512  	  candidates = g_slist_prepend (candidates, candidate);
    1513  	  g_hash_table_add (found_versions, version);
    1514  	}
    1515        g_dir_close (dir);
    1516        index++;
    1517      }
    1518  
    1519    g_free (namespace_dash);
    1520    g_free (namespace_typelib);
    1521    g_hash_table_destroy (found_versions);
    1522  
    1523    return candidates;
    1524  }
    1525  
    1526  static GMappedFile *
    1527  find_namespace_latest (const char          *namespace,
    1528                         const char * const  *search_paths,
    1529                         size_t               n_search_paths,
    1530                         char               **version_ret,
    1531                         char               **path_ret)
    1532  {
    1533    GSList *candidates;
    1534    GMappedFile *result = NULL;
    1535  
    1536    *version_ret = NULL;
    1537    *path_ret = NULL;
    1538  
    1539    candidates = enumerate_namespace_versions (namespace, search_paths, n_search_paths);
    1540  
    1541    if (candidates != NULL)
    1542      {
    1543        struct NamespaceVersionCandidadate *elected;
    1544        candidates = g_slist_sort (candidates, (GCompareFunc) compare_candidate_reverse);
    1545  
    1546        elected = (struct NamespaceVersionCandidadate *) candidates->data;
    1547        /* Remove the elected one so we don't try to free its contents */
    1548        candidates = g_slist_delete_link (candidates, candidates);
    1549  
    1550        result = elected->mfile;
    1551        *path_ret = elected->path;
    1552        *version_ret = elected->version;
    1553        g_slice_free (struct NamespaceVersionCandidadate, elected); /* just free the container */
    1554        g_slist_foreach (candidates, (GFunc) (void *) free_candidate, NULL);
    1555        g_slist_free (candidates);
    1556      }
    1557    return result;
    1558  }
    1559  
    1560  /**
    1561   * gi_repository_enumerate_versions:
    1562   * @repository: (nullable): A #GIRepository, or `NULL` for the singleton
    1563   *   process-global default #GIRepository
    1564   * @namespace_: GI namespace, e.g. `Gtk`
    1565   * @n_versions_out: (optional) (out): The number of versions returned.
    1566   *
    1567   * Obtain an unordered list of versions (either currently loaded or
    1568   * available) for @namespace_ in this @repository.
    1569   *
    1570   * Returns: (element-type utf8) (transfer full) (array length=n_versions_out): the array of versions.
    1571   * Since: 2.80
    1572   */
    1573  char **
    1574  gi_repository_enumerate_versions (GIRepository *repository,
    1575                                    const gchar  *namespace_,
    1576                                    size_t       *n_versions_out)
    1577  {
    1578    GPtrArray *versions;
    1579    GSList *candidates, *link;
    1580    const gchar *loaded_version;
    1581    char **ret;
    1582  
    1583    init_globals ();
    1584    candidates = enumerate_namespace_versions (namespace_,
    1585                                               (const char * const *) typelib_search_path->pdata,
    1586                                               typelib_search_path->len);
    1587  
    1588    if (!candidates)
    1589      {
    1590        if (n_versions_out)
    1591          *n_versions_out = 0;
    1592        return g_strdupv ((char *[]) {NULL});
    1593      }
    1594  
    1595    versions = g_ptr_array_new_null_terminated (1, g_free, TRUE);
    1596    for (link = candidates; link; link = link->next)
    1597      {
    1598        struct NamespaceVersionCandidadate *candidate = link->data;
    1599        g_ptr_array_add (versions, g_steal_pointer (&candidate->version));
    1600        free_candidate (candidate);
    1601      }
    1602    g_slist_free (candidates);
    1603  
    1604    /* The currently loaded version of a namespace is also part of the
    1605     * available versions, as it could have been loaded using
    1606     * require_private().
    1607     */
    1608    if (gi_repository_is_registered (repository, namespace_, NULL))
    1609      {
    1610        loaded_version = gi_repository_get_version (repository, namespace_);
    1611        if (loaded_version &&
    1612            !g_ptr_array_find_with_equal_func (versions, loaded_version, g_str_equal, NULL))
    1613          g_ptr_array_add (versions, g_strdup (loaded_version));
    1614      }
    1615  
    1616    ret = (char **) g_ptr_array_steal (versions, n_versions_out);
    1617    g_ptr_array_unref (g_steal_pointer (&versions));
    1618  
    1619    return ret;
    1620  }
    1621  
    1622  static GITypelib *
    1623  require_internal (GIRepository           *repository,
    1624                    const char             *namespace,
    1625                    const char             *version,
    1626                    GIRepositoryLoadFlags   flags,
    1627                    const char * const     *search_paths,
    1628                    size_t                  n_search_paths,
    1629                    GError                **error)
    1630  {
    1631    GMappedFile *mfile;
    1632    GITypelib *ret = NULL;
    1633    Header *header;
    1634    GITypelib *typelib = NULL;
    1635    const gchar *typelib_namespace, *typelib_version;
    1636    gboolean allow_lazy = (flags & GI_REPOSITORY_LOAD_FLAG_LAZY) > 0;
    1637    gboolean is_lazy;
    1638    char *version_conflict = NULL;
    1639    char *path = NULL;
    1640    char *tmp_version = NULL;
    1641  
    1642    g_return_val_if_fail (namespace != NULL, FALSE);
    1643  
    1644    repository = get_repository (repository);
    1645  
    1646    typelib = get_registered_status (repository, namespace, version, allow_lazy,
    1647                                     &is_lazy, &version_conflict);
    1648    if (typelib)
    1649      return typelib;
    1650  
    1651    if (version_conflict != NULL)
    1652      {
    1653        g_set_error (error, GI_REPOSITORY_ERROR,
    1654  		   GI_REPOSITORY_ERROR_NAMESPACE_VERSION_CONFLICT,
    1655  		   "Requiring namespace '%s' version '%s', but '%s' is already loaded",
    1656  		   namespace, version, version_conflict);
    1657        return NULL;
    1658      }
    1659  
    1660    if (version != NULL)
    1661      {
    1662        mfile = find_namespace_version (namespace, version, search_paths,
    1663                                        n_search_paths, &path);
    1664        tmp_version = g_strdup (version);
    1665      }
    1666    else
    1667      {
    1668        mfile = find_namespace_latest (namespace, search_paths, n_search_paths,
    1669                                       &tmp_version, &path);
    1670      }
    1671  
    1672    if (mfile == NULL)
    1673      {
    1674        if (version != NULL)
    1675  	g_set_error (error, GI_REPOSITORY_ERROR,
    1676  		     GI_REPOSITORY_ERROR_TYPELIB_NOT_FOUND,
    1677  		     "Typelib file for namespace '%s', version '%s' not found",
    1678  		     namespace, version);
    1679        else
    1680  	g_set_error (error, GI_REPOSITORY_ERROR,
    1681  		     GI_REPOSITORY_ERROR_TYPELIB_NOT_FOUND,
    1682  		     "Typelib file for namespace '%s' (any version) not found",
    1683  		     namespace);
    1684        goto out;
    1685      }
    1686  
    1687    {
    1688      GError *temp_error = NULL;
    1689      typelib = gi_typelib_new_from_mapped_file (mfile, &temp_error);
    1690      if (!typelib)
    1691        {
    1692  	g_set_error (error, GI_REPOSITORY_ERROR,
    1693  		     GI_REPOSITORY_ERROR_TYPELIB_NOT_FOUND,
    1694  		     "Failed to load typelib file '%s' for namespace '%s': %s",
    1695  		     path, namespace, temp_error->message);
    1696  	g_clear_error (&temp_error);
    1697  	goto out;
    1698        }
    1699    }
    1700    header = (Header *) typelib->data;
    1701    typelib_namespace = gi_typelib_get_string (typelib, header->namespace);
    1702    typelib_version = gi_typelib_get_string (typelib, header->nsversion);
    1703  
    1704    if (strcmp (typelib_namespace, namespace) != 0)
    1705      {
    1706        g_set_error (error, GI_REPOSITORY_ERROR,
    1707  		   GI_REPOSITORY_ERROR_NAMESPACE_MISMATCH,
    1708  		   "Typelib file %s for namespace '%s' contains "
    1709  		   "namespace '%s' which doesn't match the file name",
    1710  		   path, namespace, typelib_namespace);
    1711        gi_typelib_free (typelib);
    1712        goto out;
    1713      }
    1714    if (version != NULL && strcmp (typelib_version, version) != 0)
    1715      {
    1716        g_set_error (error, GI_REPOSITORY_ERROR,
    1717  		   GI_REPOSITORY_ERROR_NAMESPACE_MISMATCH,
    1718  		   "Typelib file %s for namespace '%s' contains "
    1719  		   "version '%s' which doesn't match the expected version '%s'",
    1720  		   path, namespace, typelib_version, version);
    1721        gi_typelib_free (typelib);
    1722        goto out;
    1723      }
    1724  
    1725    if (!register_internal (repository, path, allow_lazy,
    1726  			  typelib, error))
    1727      {
    1728        gi_typelib_free (typelib);
    1729        goto out;
    1730      }
    1731    ret = typelib;
    1732   out:
    1733    g_free (tmp_version);
    1734    g_free (path);
    1735    return ret;
    1736  }
    1737  
    1738  /**
    1739   * gi_repository_require:
    1740   * @repository: (nullable): A #GIRepository, or `NULL` for the singleton
    1741   *   process-global default #GIRepository
    1742   * @namespace_: GI namespace to use, e.g. `Gtk`
    1743   * @version: (nullable): Version of namespace, may be `NULL` for latest
    1744   * @flags: Set of [flags@GIRepository.RepositoryLoadFlags], may be 0
    1745   * @error: a [type@GLib.Error].
    1746   *
    1747   * Force the namespace @namespace_ to be loaded if it isn’t already.
    1748   *
    1749   * If @namespace_ is not loaded, this function will search for a
    1750   * `.typelib` file using the repository search path.  In addition, a
    1751   * version @version of namespace may be specified.  If @version is
    1752   * not specified, the latest will be used.
    1753   *
    1754   * Returns: (transfer none): a pointer to the [type@GIRepository.Typelib] if
    1755   *   successful, `NULL` otherwise
    1756   * Since: 2.80
    1757   */
    1758  GITypelib *
    1759  gi_repository_require (GIRepository  *repository,
    1760  		       const gchar   *namespace,
    1761  		       const gchar   *version,
    1762  		       GIRepositoryLoadFlags flags,
    1763  		       GError       **error)
    1764  {
    1765    GITypelib *typelib;
    1766  
    1767    init_globals ();
    1768    typelib = require_internal (repository, namespace, version, flags,
    1769                                (const char * const *) typelib_search_path->pdata,
    1770                                typelib_search_path->len, error);
    1771  
    1772    return typelib;
    1773  }
    1774  
    1775  /**
    1776   * gi_repository_require_private:
    1777   * @repository: (nullable): A #GIRepository, or `NULL` for the singleton
    1778   *   process-global default #GIRepository
    1779   * @typelib_dir: (type filename): Private directory where to find the requested
    1780   *   typelib
    1781   * @namespace_: GI namespace to use, e.g. `Gtk`
    1782   * @version: (nullable): Version of namespace, may be `NULL` for latest
    1783   * @flags: Set of [flags@GIRepository.RepositoryLoadFlags], may be 0
    1784   * @error: a [type@GLib.Error].
    1785   *
    1786   * Force the namespace @namespace_ to be loaded if it isn’t already.
    1787   *
    1788   * If @namespace_ is not loaded, this function will search for a
    1789   * `.typelib` file within the private directory only. In addition, a
    1790   * version @version of namespace should be specified.  If @version is
    1791   * not specified, the latest will be used.
    1792   *
    1793   * Returns: (transfer none): a pointer to the [type@GIRepository.Typelib] if
    1794   *   successful, `NULL` otherwise
    1795   * Since: 2.80
    1796   */
    1797  GITypelib *
    1798  gi_repository_require_private (GIRepository  *repository,
    1799  			       const gchar   *typelib_dir,
    1800  			       const gchar   *namespace,
    1801  			       const gchar   *version,
    1802  			       GIRepositoryLoadFlags flags,
    1803  			       GError       **error)
    1804  {
    1805    const char * const search_path[] = { typelib_dir, NULL };
    1806  
    1807    return require_internal (repository, namespace, version, flags,
    1808                             search_path, 1, error);
    1809  }
    1810  
    1811  static gboolean
    1812  gi_repository_introspect_cb (const char *option_name,
    1813  			     const char *value,
    1814  			     gpointer data,
    1815  			     GError **error)
    1816  {
    1817    GError *tmp_error = NULL;
    1818    char **args;
    1819  
    1820    args = g_strsplit (value, ",", 2);
    1821  
    1822    if (!gi_repository_dump (args[0], args[1], &tmp_error))
    1823      {
    1824        g_error ("Failed to extract GType data: %s",
    1825  	       tmp_error->message);
    1826        exit (1);
    1827      }
    1828    exit (0);
    1829  }
    1830  
    1831  static const GOptionEntry introspection_args[] = {
    1832    { "introspect-dump", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK,
    1833      gi_repository_introspect_cb, "Dump introspection information",
    1834      "infile.txt,outfile.xml" },
    1835    G_OPTION_ENTRY_NULL
    1836  };
    1837  
    1838  /**
    1839   * gi_repository_get_option_group:
    1840   *
    1841   * Obtain the option group for girepository.
    1842   *
    1843   * It’s used by the dumper and for programs that want to provide introspection
    1844   * information
    1845   *
    1846   * Returns: (transfer full): the option group
    1847   * Since: 2.80
    1848   */
    1849  GOptionGroup *
    1850  gi_repository_get_option_group (void)
    1851  {
    1852    GOptionGroup *group;
    1853    group = g_option_group_new ("girepository", "Introspection Options", "Show Introspection Options", NULL, NULL);
    1854  
    1855    g_option_group_add_entries (group, introspection_args);
    1856    return group;
    1857  }
    1858  
    1859  GQuark
    1860  gi_repository_error_quark (void)
    1861  {
    1862    static GQuark quark = 0;
    1863    if (quark == 0)
    1864      quark = g_quark_from_static_string ("g-irepository-error-quark");
    1865    return quark;
    1866  }
    1867  
    1868  /**
    1869   * gi_type_tag_to_string:
    1870   * @type: the type_tag
    1871   *
    1872   * Obtain a string representation of @type
    1873   *
    1874   * Returns: the string
    1875   * Since: 2.80
    1876   */
    1877  const gchar*
    1878  gi_type_tag_to_string (GITypeTag type)
    1879  {
    1880    switch (type)
    1881      {
    1882      case GI_TYPE_TAG_VOID:
    1883        return "void";
    1884      case GI_TYPE_TAG_BOOLEAN:
    1885        return "gboolean";
    1886      case GI_TYPE_TAG_INT8:
    1887        return "gint8";
    1888      case GI_TYPE_TAG_UINT8:
    1889        return "guint8";
    1890      case GI_TYPE_TAG_INT16:
    1891        return "gint16";
    1892      case GI_TYPE_TAG_UINT16:
    1893        return "guint16";
    1894      case GI_TYPE_TAG_INT32:
    1895        return "gint32";
    1896      case GI_TYPE_TAG_UINT32:
    1897        return "guint32";
    1898      case GI_TYPE_TAG_INT64:
    1899        return "gint64";
    1900      case GI_TYPE_TAG_UINT64:
    1901        return "guint64";
    1902      case GI_TYPE_TAG_FLOAT:
    1903        return "gfloat";
    1904      case GI_TYPE_TAG_DOUBLE:
    1905        return "gdouble";
    1906      case GI_TYPE_TAG_UNICHAR:
    1907        return "gunichar";
    1908      case GI_TYPE_TAG_GTYPE:
    1909        return "GType";
    1910      case GI_TYPE_TAG_UTF8:
    1911        return "utf8";
    1912      case GI_TYPE_TAG_FILENAME:
    1913        return "filename";
    1914      case GI_TYPE_TAG_ARRAY:
    1915        return "array";
    1916      case GI_TYPE_TAG_INTERFACE:
    1917        return "interface";
    1918      case GI_TYPE_TAG_GLIST:
    1919        return "glist";
    1920      case GI_TYPE_TAG_GSLIST:
    1921        return "gslist";
    1922      case GI_TYPE_TAG_GHASH:
    1923        return "ghash";
    1924      case GI_TYPE_TAG_ERROR:
    1925        return "error";
    1926      default:
    1927        return "unknown";
    1928      }
    1929  }
    1930  
    1931  /**
    1932   * gi_info_type_to_string:
    1933   * @type: the info type
    1934   *
    1935   * Obtain a string representation of @type
    1936   *
    1937   * Returns: the string
    1938   * Since: 2.80
    1939   */
    1940  const gchar*
    1941  gi_info_type_to_string (GIInfoType type)
    1942  {
    1943    switch (type)
    1944      {
    1945      case GI_INFO_TYPE_INVALID:
    1946        return "invalid";
    1947      case GI_INFO_TYPE_FUNCTION:
    1948        return "function";
    1949      case GI_INFO_TYPE_CALLBACK:
    1950        return "callback";
    1951      case GI_INFO_TYPE_STRUCT:
    1952        return "struct";
    1953      case GI_INFO_TYPE_BOXED:
    1954        return "boxed";
    1955      case GI_INFO_TYPE_ENUM:
    1956        return "enum";
    1957      case GI_INFO_TYPE_FLAGS:
    1958        return "flags";
    1959      case GI_INFO_TYPE_OBJECT:
    1960        return "object";
    1961      case GI_INFO_TYPE_INTERFACE:
    1962        return "interface";
    1963      case GI_INFO_TYPE_CONSTANT:
    1964        return "constant";
    1965      case GI_INFO_TYPE_UNION:
    1966        return "union";
    1967      case GI_INFO_TYPE_VALUE:
    1968        return "value";
    1969      case GI_INFO_TYPE_SIGNAL:
    1970        return "signal";
    1971      case GI_INFO_TYPE_VFUNC:
    1972        return "vfunc";
    1973      case GI_INFO_TYPE_PROPERTY:
    1974        return "property";
    1975      case GI_INFO_TYPE_FIELD:
    1976        return "field";
    1977      case GI_INFO_TYPE_ARG:
    1978        return "arg";
    1979      case GI_INFO_TYPE_TYPE:
    1980        return "type";
    1981      case GI_INFO_TYPE_UNRESOLVED:
    1982        return "unresolved";
    1983      default:
    1984        return "unknown";
    1985    }
    1986  }