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