Plug memory leak and avoid using freed memory. Resolve the whole module
[platform/upstream/gobject-introspection.git] / girepository / girepository.c
1 /* -*- Mode: C; c-file-style: "gnu"; -*- */
2 /* GObject introspection: Repository implementation
3  *
4  * Copyright (C) 2005 Matthias Clasen
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include <stdio.h>
23 #include <string.h>
24
25 #include <glib.h>
26 #include <glib/gprintf.h>
27 #include <gmodule.h>
28 #include "girepository.h"
29 #include "gtypelib.h"
30
31 static GStaticMutex globals_lock = G_STATIC_MUTEX_INIT;
32 static GIRepository *default_repository = NULL;
33 static GHashTable *default_typelib = NULL;
34 static GSList *search_path = NULL;
35
36 struct _GIRepositoryPrivate 
37 {
38   GHashTable *typelib; /* (string) namespace -> GTypelib */
39 };
40
41 G_DEFINE_TYPE (GIRepository, g_irepository, G_TYPE_OBJECT);
42
43 static void 
44 g_irepository_init (GIRepository *repository)
45 {
46   repository->priv = G_TYPE_INSTANCE_GET_PRIVATE (repository, G_TYPE_IREPOSITORY,
47                                                   GIRepositoryPrivate);
48 }
49
50 static void
51 g_irepository_finalize (GObject *object)
52 {
53   GIRepository *repository = G_IREPOSITORY (object);
54
55   g_hash_table_destroy (repository->priv->typelib);
56   
57   (* G_OBJECT_CLASS (g_irepository_parent_class)->finalize) (G_OBJECT (repository));
58 }
59
60 static void
61 g_irepository_class_init (GIRepositoryClass *class)
62 {
63   GObjectClass *gobject_class;
64
65   gobject_class = G_OBJECT_CLASS (class);
66
67   gobject_class->finalize = g_irepository_finalize;
68
69   g_type_class_add_private (class, sizeof (GIRepositoryPrivate)); 
70 }
71
72 static void
73 init_globals ()
74 {
75   g_static_mutex_lock (&globals_lock);
76
77   if (default_repository == NULL) 
78     { 
79       default_repository = g_object_new (G_TYPE_IREPOSITORY, NULL);
80       if (default_typelib == NULL)
81         default_typelib = g_hash_table_new_full (g_str_hash, g_str_equal,
82                                                   (GDestroyNotify) NULL,
83                                                   (GDestroyNotify) g_typelib_free);
84       default_repository->priv->typelib = default_typelib;
85     }
86
87   if (search_path == NULL)
88     {
89       const gchar *const *datadirs;
90       const gchar *const *dir;
91       
92       datadirs = g_get_system_data_dirs ();
93       
94       search_path = NULL;
95       for (dir = datadirs; *dir; dir++) {
96         char *path = g_build_filename (*dir, "gitypelibs", NULL);
97         search_path = g_slist_prepend (search_path, path);
98       }
99       search_path = g_slist_reverse (search_path);
100     }
101
102   g_static_mutex_unlock (&globals_lock);
103 }
104
105 static char *
106 build_typelib_key (const char *name, const char *source)
107 {
108   GString *str = g_string_new (name);
109   g_string_append_c (str, '\0');
110   g_string_append (str, source);
111   return g_string_free (str, FALSE);
112 }
113
114 static const gchar *
115 register_internal (GIRepository *repository,
116                    const char   *source,
117                    GTypelib     *typelib)
118 {
119   Header *header;
120   const gchar *name;
121   GHashTable *table;
122   GError *error = NULL;
123   
124   g_return_val_if_fail (typelib != NULL, NULL);
125   
126   header = (Header *)typelib->data;
127
128   g_return_val_if_fail (header != NULL, NULL);
129
130   if (repository != NULL)
131     {
132       if (repository->priv->typelib == NULL)
133         repository->priv->typelib = g_hash_table_new_full (g_str_hash, g_str_equal,
134                                                             (GDestroyNotify) NULL,
135                                                             (GDestroyNotify) g_typelib_free);
136       table = repository->priv->typelib;
137     }
138   else 
139     {
140       init_globals ();
141       table = default_typelib;
142     }
143
144   name = g_typelib_get_string (typelib, header->namespace);
145
146   if (g_hash_table_lookup (table, name))
147     {
148       g_printerr ("typelib (%p) for '%s' already registered\n",
149                  typelib, name);
150
151       return NULL;
152     }
153   g_hash_table_insert (table, build_typelib_key (name, source), (void *)typelib);
154
155   if (typelib->module == NULL)
156       typelib->module = g_module_open (NULL, 0); 
157
158   return name;
159 }
160
161 const gchar *
162 g_irepository_register (GIRepository *repository,
163                         GTypelib     *typelib)
164 {
165   return register_internal (repository, "<builtin>", typelib);
166 }
167
168 void
169 g_irepository_unregister (GIRepository *repository,
170                           const gchar  *namespace)
171 {
172   GHashTable *table;
173
174   if (repository != NULL)
175     table = repository->priv->typelib;
176   else 
177     {
178       init_globals ();
179       table = default_typelib;
180     }
181
182   if (!g_hash_table_remove (table, namespace))
183     {
184       g_printerr ("namespace '%s' not registered\n", namespace);
185     }
186 }
187
188 gboolean
189 g_irepository_is_registered (GIRepository *repository, 
190                              const gchar *namespace)
191 {
192   GHashTable *table;
193
194   if (repository != NULL)
195     table = repository->priv->typelib;
196   else
197     {
198       init_globals ();
199       table = default_typelib;
200     }
201
202   return g_hash_table_lookup (table, namespace) != NULL;
203 }
204
205 GIRepository * 
206 g_irepository_get_default (void)
207 {
208   init_globals ();
209   return default_repository; 
210 }
211
212 static void 
213 count_interfaces (gpointer key,
214                   gpointer value,
215                   gpointer data)
216 {
217   guchar *typelib = ((GTypelib *) value)->data;
218   gint *n_interfaces = (gint *)data;
219   
220   *n_interfaces += ((Header *)typelib)->n_local_entries;
221 }
222
223 gint                   
224 g_irepository_get_n_infos (GIRepository *repository,
225                            const gchar  *namespace)
226 {
227   gint n_interfaces = 0;
228   
229   if (namespace)
230     {
231       GTypelib *typelib;
232
233       typelib = g_hash_table_lookup (repository->priv->typelib, namespace);
234
235       if (typelib)
236         n_interfaces = ((Header *)typelib->data)->n_local_entries;
237     }
238   else
239     {
240       g_hash_table_foreach (repository->priv->typelib, 
241                             count_interfaces, &n_interfaces);
242     }
243
244   return n_interfaces;
245 }
246
247 typedef struct
248 {
249   gint index;
250   const gchar *name;
251   const gchar *type;
252   GIBaseInfo *iface;
253 } IfaceData;
254
255 static void
256 find_interface (gpointer key,
257                 gpointer value,
258                 gpointer data)
259 {
260   gint i;
261   GTypelib *typelib = (GTypelib *)value;
262   IfaceData *iface_data = (IfaceData *)data;
263   gint index;
264   gint n_entries;
265   guint32 offset;
266   const gchar *name;
267   const gchar *type;
268   DirEntry *entry;    
269
270   index = 0;
271   n_entries = ((Header *)typelib->data)->n_local_entries;
272
273   if (iface_data->name)
274     {
275       for (i = 1; i <= n_entries; i++)
276         {
277           entry = g_typelib_get_dir_entry (typelib, i);
278           name = g_typelib_get_string (typelib, entry->name);
279           if (strcmp (name, iface_data->name) == 0)
280             {
281               index = i;
282               break;
283             }
284         }
285     }
286   else if (iface_data->type)
287     {
288       for (i = 1; i <= n_entries; i++)
289         {
290           entry = g_typelib_get_dir_entry (typelib, i);
291           if (entry->blob_type < 4)
292             continue;
293           
294           offset = *(guint32*)&typelib->data[entry->offset + 8];
295           type = g_typelib_get_string (typelib, offset);
296           if (strcmp (type, iface_data->type) == 0)
297             {
298               index = i;
299               break;
300             }
301         }
302     }
303   else if (iface_data->index > n_entries)
304     iface_data->index -= n_entries;
305   else if (iface_data->index > 0)
306     {
307       index = iface_data->index;
308       iface_data->index = 0;
309     }
310
311   if (index != 0)
312     {
313       entry = g_typelib_get_dir_entry (typelib, index);
314       iface_data->iface = g_info_new (entry->blob_type, NULL,
315                                       typelib, entry->offset);
316     }
317 }
318
319 GIBaseInfo * 
320 g_irepository_get_info (GIRepository *repository,
321                         const gchar  *namespace,
322                         gint          index)
323 {
324   IfaceData data;
325
326   data.name = NULL;
327   data.type = NULL;
328   data.index = index + 1;
329   data.iface = NULL;
330
331   if (namespace)
332     {
333       GTypelib *typelib;
334       
335       typelib = g_hash_table_lookup (repository->priv->typelib, namespace);
336       
337       if (typelib)
338         find_interface ((void *)namespace, typelib, &data);
339     }
340   else
341     g_hash_table_foreach (repository->priv->typelib, find_interface, &data);
342
343   return data.iface;  
344 }
345
346 GIBaseInfo * 
347 g_irepository_find_by_gtype (GIRepository *repository,
348                              GType         type)
349 {
350   IfaceData data;
351
352   data.name = NULL;
353   data.type = g_type_name (type);
354   data.index = -1;
355   data.iface = NULL;
356
357   g_hash_table_foreach (repository->priv->typelib, find_interface, &data);
358
359   return data.iface;
360 }
361
362 /**
363  * g_irepository_find_by_name
364  * @repository: A #GIRepository, may be %NULL for the default
365  * @namespace: Namespace to search in, may be %NULL for all
366  * @name: Name to find
367  *
368  * Searches for a particular name in one or all namespaces.
369  * See #g_irepository_require to load metadata for namespaces.
370
371  * Returns: #GIBaseInfo representing metadata about @name, or %NULL
372  */
373 GIBaseInfo * 
374 g_irepository_find_by_name (GIRepository *repository,
375                             const gchar  *namespace,
376                             const gchar  *name)
377 {
378   IfaceData data;
379
380   data.name = name;
381   data.type = NULL;
382   data.index = -1;
383   data.iface = NULL;
384
385   if (namespace)
386     {
387       GTypelib *typelib;
388       
389       typelib = g_hash_table_lookup (repository->priv->typelib, namespace);
390       
391       if (typelib)
392         find_interface ((void *)namespace, typelib, &data);
393     }
394   else
395     g_hash_table_foreach (repository->priv->typelib, find_interface, &data);
396
397   return data.iface;
398 }
399
400 static void
401 collect_namespaces (gpointer key,
402                     gpointer value,
403                     gpointer data)
404 {
405   GList **list = data;
406
407   *list = g_list_append (*list, key);
408 }
409
410 /**
411  * g_irepository_get_namespaces
412  * @repository: A #GIRepository, may be %NULL for the default
413  *
414  * Return the list of currently known namespaces.  Normally
415  * if you want a particular namespace, you should call 
416  * #g_irepository_require to load it in.
417
418  * Returns: List of namespaces
419  */
420 gchar ** 
421 g_irepository_get_namespaces (GIRepository *repository)
422 {
423   GList *l, *list = NULL;
424   gchar **names;
425   gint i;
426
427   g_hash_table_foreach (repository->priv->typelib, collect_namespaces, &list);
428
429   names = g_malloc0 (sizeof (gchar *) * (g_list_length (list) + 1));
430   i = 0;
431   for (l = list; l; l = l->next)
432     names[i++] = g_strdup (l->data); 
433   g_list_free (list);
434
435   return names;
436 }
437
438 const gchar *
439 g_irepository_get_shared_library (GIRepository *repository,
440                                    const gchar  *namespace)
441 {
442   GTypelib *typelib;
443   Header *header;
444
445   typelib = g_hash_table_lookup (repository->priv->typelib, namespace);
446   if (!typelib)
447     return NULL;
448   header = (Header *) typelib->data;
449   if (header->shared_library)
450     return g_typelib_get_string (typelib, header->shared_library);
451   else
452     return NULL;
453 }
454
455 /**
456  * g_irepository_get_typelib_path
457  * @repository: Repository, may be %NULL for the default
458  * @namespace: GI namespace to use, e.g. "Gtk"
459  *
460  * If namespace @namespace is loaded, return the full path to the
461  * .typelib file it was loaded from.  If the typelib for 
462  * namespace @namespace was included in a shared library, return
463  * the special string "<builtin>".
464  *
465  * Returns: Filesystem path (or <builtin>) if successful, %NULL otherwise
466  */
467
468 const gchar * 
469 g_irepository_get_typelib_path (GIRepository *repository,
470                                 const gchar  *namespace)
471 {
472   gpointer orig_key, value;
473
474   if (!g_hash_table_lookup_extended (repository->priv->typelib, namespace,
475                                      &orig_key, &value))
476     return NULL;
477   return ((char*)orig_key) + strlen ((char *) orig_key) + 1;
478 }
479
480 /**
481  * g_irepository_require
482  * @repository: Repository, may be %NULL for the default
483  * @namespace: GI namespace to use, e.g. "Gtk"
484  * @error: a #GError.
485  *
486  * Force the namespace @namespace to be loaded if it isn't
487  * already.  If @namespace is not loaded, this function will
488  * search for a ".typelib" file using the repository search 
489  * path.
490  *
491  * Returns: Namespace if successful, NULL otherwise
492  */
493 const gchar *
494 g_irepository_require (GIRepository  *repository,
495                        const gchar   *namespace,
496                        GError       **error)
497 {
498   GSList *ldir;
499   const char *dir;
500   gchar *fname, *full_path;
501   GMappedFile *mfile;
502   GError *error1 = NULL;
503   GTypelib *typelib = NULL;
504   const gchar *typelib_namespace, *shlib_fname;
505   GModule *module;
506   guint32 shlib;
507   GHashTable *table;
508
509   if (repository != NULL)
510     table = repository->priv->typelib;
511   else
512     {
513       init_globals ();
514       table = default_typelib;
515     }
516
517   /* don't bother loading a namespace if already registered */
518   if (g_hash_table_lookup (table, namespace))
519     return namespace;
520
521   fname = g_strconcat (namespace, ".typelib", NULL);
522
523   for (ldir = search_path; ldir; ldir = ldir->next)
524     {
525       Header *header;
526       
527       full_path = g_build_filename (ldir->data, fname, NULL);
528       mfile = g_mapped_file_new (full_path, FALSE, &error1);
529       if (error1)
530         {
531           g_clear_error (&error1);
532           continue;
533         }
534
535       typelib = g_typelib_new_from_mapped_file (mfile);
536       header = (Header *) typelib->data;
537       typelib_namespace = g_typelib_get_string (typelib, header->namespace);
538
539       if (strcmp (typelib_namespace, namespace) != 0)
540         {
541           g_set_error (error, G_IREPOSITORY_ERROR,
542                        G_IREPOSITORY_ERROR_NAMESPACE_MISMATCH,
543                        "Typelib file %s for namespace '%s' contains "
544                        "namespace '%s' which doesn't match the file name",
545                        full_path, namespace, typelib_namespace);
546           g_free (full_path);
547           return NULL; 
548         }
549       break;
550   }
551
552   if (typelib == NULL)
553     {
554       g_set_error (error, G_IREPOSITORY_ERROR,
555                    G_IREPOSITORY_ERROR_TYPELIB_NOT_FOUND,
556                    "Typelib file for namespace '%s' was not found in search"
557                    " path or could not be openened", namespace);
558       g_free (full_path);
559       return NULL;
560     }
561
562   g_free (fname);
563   
564   /* optionally load shared library and attach it to the typelib */
565   shlib = ((Header *) typelib->data)->shared_library;
566   if (shlib)
567     {
568       gchar *resolved_shlib;
569
570       shlib_fname = g_typelib_get_string (typelib, shlib);
571       resolved_shlib = g_module_build_path (NULL, shlib_fname);
572
573       module = g_module_open (resolved_shlib,
574                               G_MODULE_BIND_LAZY|G_MODULE_BIND_LOCAL);
575       if (module == NULL)
576         {
577           g_set_error (error, G_IREPOSITORY_ERROR,
578                        G_IREPOSITORY_ERROR_TYPELIB_NOT_FOUND,
579                        "Typelib for namespace '%s' references shared library "
580                        "%s, but it could not be openened (%s)",
581                        namespace, resolved_shlib, g_module_error ());
582           g_free (full_path);
583           g_free (resolved_shlib);
584           return NULL;
585         }
586       g_free (resolved_shlib);
587     }
588
589   g_hash_table_remove (table, namespace);
590   register_internal (repository, full_path, typelib);
591   g_free (full_path);
592   return namespace; 
593 }
594
595
596 GQuark
597 g_irepository_error_quark (void)
598 {
599   static GQuark quark = 0;
600   if (quark == 0)
601     quark = g_quark_from_static_string ("g-irepository-error-quark");
602   return quark;
603 }
604
605 const gchar*
606 g_type_tag_to_string (GITypeTag type)
607 {
608   switch (type)
609     {
610     case GI_TYPE_TAG_VOID:
611       return "void";
612     case GI_TYPE_TAG_BOOLEAN:
613       return "boolean";
614     case GI_TYPE_TAG_INT8:
615       return "int8";
616     case GI_TYPE_TAG_UINT8:
617       return "uint8";
618     case GI_TYPE_TAG_INT16:
619       return "int16";
620     case GI_TYPE_TAG_UINT16:
621       return "uint16";
622     case GI_TYPE_TAG_INT32:
623       return "int32";
624     case GI_TYPE_TAG_UINT32:
625       return "uint32";
626     case GI_TYPE_TAG_INT64:
627       return "int64";
628     case GI_TYPE_TAG_UINT64:
629       return "uint64";
630     case GI_TYPE_TAG_INT:
631       return "int";
632     case GI_TYPE_TAG_UINT:
633       return "uint";
634     case GI_TYPE_TAG_LONG:
635       return "long";
636     case GI_TYPE_TAG_ULONG:
637       return "ulong";
638     case GI_TYPE_TAG_SSIZE:
639       return "ssize";
640     case GI_TYPE_TAG_SIZE:
641       return "size";
642     case GI_TYPE_TAG_FLOAT:
643       return "float";
644     case GI_TYPE_TAG_DOUBLE:
645       return "double";
646     case GI_TYPE_TAG_UTF8:
647       return "utf8";
648     case GI_TYPE_TAG_FILENAME:
649       return "filename";
650     case GI_TYPE_TAG_ARRAY:
651       return "array";
652     case GI_TYPE_TAG_INTERFACE:
653       return "interface";
654     case GI_TYPE_TAG_GLIST:
655       return "glist";
656     case GI_TYPE_TAG_GSLIST:
657       return "gslist";
658     case GI_TYPE_TAG_GHASH:
659       return "ghash";
660     case GI_TYPE_TAG_ERROR:
661       return "error";
662     default:
663       return "unknown";
664     }
665 }