LCOV - code coverage report
Current view: top level - glib/girepository - girepository.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 423 691 61.2 %
Date: 2024-05-07 05:15:23 Functions: 43 55 78.2 %
Branches: 118 282 41.8 %

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

Generated by: LCOV version 1.14