Small fixes for testsuite/plugin
[platform/upstream/gstreamer.git] / gst / gstregistry.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstregistry.c: handle registry
6  * 
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include <glib.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <errno.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #include "gstinfo.h"
32 #include "gstregistry.h"
33
34 #define CLASS(registry)  GST_REGISTRY_CLASS (G_OBJECT_GET_CLASS (registry))
35
36 /* Element signals and args */
37 enum {
38   PLUGIN_ADDED,
39   LAST_SIGNAL
40 };
41
42
43 static GList *_gst_registry_pool = NULL;
44 static GList *_gst_registry_pool_plugins = NULL;
45
46 static void             gst_registry_class_init           (GstRegistryClass *klass);
47 static void             gst_registry_init                 (GstRegistry *registry);
48
49 static GObjectClass *parent_class = NULL;
50 static guint gst_registry_signals[LAST_SIGNAL] = { 0 }; 
51
52 GType
53 gst_registry_get_type (void)
54 {
55   static GType registry_type = 0;
56
57   if (!registry_type) {
58     static const GTypeInfo registry_info = {
59       sizeof (GstRegistryClass),
60       NULL,
61       NULL,
62       (GClassInitFunc) gst_registry_class_init,
63       NULL,
64       NULL,
65       sizeof (GstRegistry),
66       32,
67       (GInstanceInitFunc) gst_registry_init,
68       NULL
69     };
70     registry_type = g_type_register_static (G_TYPE_OBJECT, "GstRegistry",
71                                             &registry_info, G_TYPE_FLAG_ABSTRACT);
72   }
73   return registry_type;
74 }
75
76 static void
77 gst_registry_class_init (GstRegistryClass *klass)
78 {
79   GObjectClass *gobject_class;
80
81   gobject_class = (GObjectClass*) klass;
82
83   parent_class = g_type_class_ref (G_TYPE_OBJECT);
84
85   gst_registry_signals[PLUGIN_ADDED] =
86     g_signal_new ("plugin_added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
87                   G_STRUCT_OFFSET (GstRegistryClass, plugin_added), NULL, NULL,
88                   gst_marshal_VOID__POINTER, G_TYPE_NONE, 1,
89                   G_TYPE_POINTER);
90
91   gobject_class->dispose = NULL;
92 }
93
94 static void
95 gst_registry_init (GstRegistry *registry)
96 {
97   registry->priority = 0;
98   registry->loaded = FALSE;
99   registry->paths = NULL;
100 }
101
102 /**
103  * gst_registry_load:
104  * @registry: the registry to load
105  *
106  * Load the given registry
107  *
108  * Returns: TRUE on success.
109  */
110 gboolean
111 gst_registry_load (GstRegistry *registry)
112 {
113   g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
114
115   if (CLASS (registry)->load)
116     return CLASS (registry)->load (registry);
117
118   return FALSE;
119 }
120
121 /**
122  * gst_registry_is_loaded:
123  * @registry: the registry to check
124  *
125  * Check if the given registry is loaded
126  *
127  * Returns: TRUE if loaded.
128  */
129 gboolean
130 gst_registry_is_loaded (GstRegistry *registry)
131 {
132   g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
133
134   return registry->loaded;
135 }
136
137 /**
138  * gst_registry_save:
139  * @registry: the registry to save
140  *
141  * Save the contents of the given registry
142  *
143  * Returns: TRUE on success
144  */
145 gboolean
146 gst_registry_save (GstRegistry *registry)
147 {
148   g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
149
150   if (CLASS (registry)->save)
151     return CLASS (registry)->save (registry);
152
153   return FALSE;
154 }
155
156 /**
157  * gst_registry_rebuild:
158  * @registry: the registry to rebuild
159  *
160  * Rebuild the given registry
161  *
162  * Returns: TRUE on success
163  */
164 gboolean
165 gst_registry_rebuild (GstRegistry *registry)
166 {
167   g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
168
169   if (CLASS (registry)->rebuild)
170     return CLASS (registry)->rebuild (registry);
171
172   return FALSE;
173 }
174
175 /**
176  * gst_registry_unload:
177  * @registry: the registry to unload
178  *
179  * Unload the given registry
180  *
181  * Returns: TRUE on success
182  */
183 gboolean
184 gst_registry_unload (GstRegistry *registry)
185 {
186   g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
187
188   if (CLASS (registry)->unload)
189     return CLASS (registry)->unload (registry);
190
191   return FALSE;
192 }
193
194 /**
195  * gst_registry_add_path:
196  * @registry: the registry to add the path to
197  *
198  * Add the given pathstring to the registry. The syntax of the
199  * pathstring is specific to the registry.
200  */
201 void
202 gst_registry_add_path (GstRegistry *registry, const gchar *path)
203 {
204   g_return_if_fail (GST_IS_REGISTRY (registry));
205   g_return_if_fail (path != NULL);
206
207   registry->paths = g_list_append (registry->paths, g_strdup (path));
208 }
209
210 /**
211  * gst_registry_get_path_list:
212  * @registry: the registry to get the pathlist of
213  *
214  * Get the list of paths for the given registry.
215  *
216  * Returns: A Glist of paths as strings. g_list_free after use.
217  */
218 GList*
219 gst_registry_get_path_list (GstRegistry *registry)
220 {
221   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
222
223   return g_list_copy (registry->paths);
224 }
225
226
227 static void
228 free_list_strings_func (gpointer data, gpointer user_data)
229 {
230   g_free (data);
231 }
232
233 /**
234  * gst_registry_clear_paths:
235  * @registry: the registry to clear the paths of
236  *
237  * Clear the paths of the given registry
238  */
239 void
240 gst_registry_clear_paths (GstRegistry *registry)
241 {
242   g_return_if_fail (GST_IS_REGISTRY (registry));
243
244   g_list_foreach (registry->paths, free_list_strings_func, NULL);
245   g_list_free (registry->paths);
246
247   registry->paths = NULL;
248 }
249
250 /**
251  * gst_registry_add_plugin:
252  * @registry: the registry to add the plugin to
253  * @plugin: the plugin to add
254  *
255  * Add the plugin to the registry. The plugin-added signal 
256  * will be emitted.
257  *
258  * Returns: TRUE on success.
259  */
260 gboolean 
261 gst_registry_add_plugin (GstRegistry *registry, GstPlugin *plugin)
262 {
263   g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
264   
265   plugin->manager = registry;
266   registry->plugins = g_list_prepend (registry->plugins, plugin);
267
268   g_signal_emit (G_OBJECT (registry), gst_registry_signals[PLUGIN_ADDED], 0, plugin);
269
270   return TRUE;
271 }
272
273 /**
274  * gst_registry_remove_plugin:
275  * @registry: the registry to remove the plugin from
276  * @plugin: the plugin to remove
277  *
278  * Remove the plugin from the registry.
279  */
280 void
281 gst_registry_remove_plugin (GstRegistry *registry, GstPlugin *plugin)
282 {
283   g_return_if_fail (GST_IS_REGISTRY (registry));
284
285   registry->plugins = g_list_remove (registry->plugins, plugin);
286 }
287
288 static GstPluginFeature*
289 gst_plugin_list_find_feature (GList *plugins, const gchar *name, GType type)
290 {
291   GstPluginFeature *feature = NULL;
292
293   while (plugins) {
294     GstPlugin *plugin = (GstPlugin *) (plugins->data);
295
296     feature = gst_plugin_find_feature (plugin, name, type);
297     if (feature)
298       return feature;
299     
300     plugins = g_list_next (plugins);
301   }
302   return feature;
303 }
304
305 static GstPlugin*
306 gst_plugin_list_find_plugin (GList *plugins, const gchar *name)
307 {
308   while (plugins) {
309     GstPlugin *plugin = (GstPlugin *) (plugins->data);
310
311     if (plugin->name && !strcmp (plugin->name, name))
312       return plugin;
313     
314     plugins = g_list_next (plugins);
315   }
316   return NULL;
317 }
318
319 /**
320  * gst_registry_find_plugin:
321  * @registry: the registry to search
322  * @name: the plugin name to find
323  *
324  * Find the plugin with the given name in the registry.
325  *
326  * Returns: The plugin with the given name or NULL if the plugin was not found.
327  */
328 GstPlugin*
329 gst_registry_find_plugin (GstRegistry *registry, const gchar *name)
330 {
331   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
332   g_return_val_if_fail (name != NULL, NULL);
333   
334   return gst_plugin_list_find_plugin (registry->plugins, name);
335 }
336
337 /**
338  * gst_registry_find_feature:
339  * @registry: the registry to search
340  * @name: the pluginfeature name to find
341  * @type: the pluginfeature type to find
342  *
343  * Find the pluginfeature with the given name and type in the registry.
344  *
345  * Returns: The pluginfeature with the given name and type or NULL 
346  * if the plugin was not found.
347  */
348 GstPluginFeature*
349 gst_registry_find_feature (GstRegistry *registry, const gchar *name, GType type)
350 {
351   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
352   g_return_val_if_fail (name != NULL, NULL);
353   
354   return gst_plugin_list_find_feature (registry->plugins, name, type);
355 }
356
357
358 /**
359  * gst_registry_load_plugin:
360  * @registry: the registry to load the plugin from
361  * @plugin: the plugin to load
362  *
363  * Bring the plugin from the registry into memory.
364  *
365  * Returns: a value indicating the result 
366  */
367 GstRegistryReturn
368 gst_registry_load_plugin (GstRegistry *registry, GstPlugin *plugin)
369 {
370   g_return_val_if_fail (GST_IS_REGISTRY (registry), GST_REGISTRY_PLUGIN_LOAD_ERROR);
371
372   if (CLASS (registry)->load_plugin)
373     return CLASS (registry)->load_plugin (registry, plugin);
374
375   return GST_REGISTRY_PLUGIN_LOAD_ERROR;
376 }
377
378 /**
379  * gst_registry_unload_plugin:
380  * @registry: the registry to unload the plugin from
381  * @plugin: the plugin to unload
382  *
383  * Unload the plugin from the given registry.
384  *
385  * Returns: a value indicating the result 
386  */
387 GstRegistryReturn
388 gst_registry_unload_plugin (GstRegistry *registry, GstPlugin *plugin)
389 {
390   g_return_val_if_fail (GST_IS_REGISTRY (registry), GST_REGISTRY_PLUGIN_LOAD_ERROR);
391
392   if (CLASS (registry)->unload_plugin)
393     return CLASS (registry)->unload_plugin (registry, plugin);
394
395   return GST_REGISTRY_PLUGIN_LOAD_ERROR;
396 }
397
398 /**
399  * gst_registry_update_plugin:
400  * @registry: the registry to update
401  * @plugin: the plugin to update
402  *
403  * Update the plugin in the given registry.
404  *
405  * Returns: a value indicating the result 
406  */
407 GstRegistryReturn
408 gst_registry_update_plugin (GstRegistry *registry, GstPlugin *plugin)
409 {
410   g_return_val_if_fail (GST_IS_REGISTRY (registry), GST_REGISTRY_PLUGIN_LOAD_ERROR);
411
412   if (CLASS (registry)->update_plugin)
413     return CLASS (registry)->update_plugin (registry, plugin);
414
415   return GST_REGISTRY_PLUGIN_LOAD_ERROR;
416 }
417
418 /**
419  * gst_registry_pool_list:
420  *
421  * Get a list of all registries in the pool
422  *
423  * Returns: a Glist of GstRegistries, g_list_free after use.
424  */
425 GList*
426 gst_registry_pool_list (void)
427 {
428   return g_list_copy (_gst_registry_pool);
429 }
430
431 static gint
432 gst_registry_compare_func (gconstpointer a, gconstpointer b)
433 {
434   return GST_REGISTRY (a)->priority - GST_REGISTRY (b)->priority;
435 }
436
437 /**
438  * gst_registry_pool_add:
439  * @registry: the registry to add
440  * @priority: the priority of the registry
441  *
442  * Add the registry to the pool with the given priority.
443  */
444 void
445 gst_registry_pool_add (GstRegistry *registry, guint priority)
446 {
447   g_return_if_fail (GST_IS_REGISTRY (registry));
448
449   registry->priority = priority;
450
451   _gst_registry_pool = g_list_insert_sorted (_gst_registry_pool, registry, gst_registry_compare_func);
452 }
453
454 /**
455  * gst_registry_pool_remove:
456  * @registry: the registry to remove
457  *
458  * Remove the registry from the pool.
459  */
460 void
461 gst_registry_pool_remove (GstRegistry *registry)
462 {
463   g_return_if_fail (GST_IS_REGISTRY (registry));
464
465   _gst_registry_pool = g_list_remove (_gst_registry_pool, registry);
466 }
467
468 /**
469  * gst_registry_pool_add_plugin:
470  * @plugin: the plugin to add
471  *
472  * Add the plugin to the global pool of plugins.
473  */
474 void
475 gst_registry_pool_add_plugin (GstPlugin *plugin)
476 {
477   _gst_registry_pool_plugins = g_list_prepend (_gst_registry_pool_plugins, plugin);
478 }
479
480
481 /**
482  * gst_registry_pool_load_all:
483  *
484  * Load all the registries in the pool. Registries with the
485  * GST_REGISTRY_DELAYED_LOADING will not be loaded.
486  */
487 void
488 gst_registry_pool_load_all (void)
489 {
490   GList *walk = _gst_registry_pool;
491
492   while (walk) {
493     GstRegistry *registry = GST_REGISTRY (walk->data);
494
495     if (registry->flags & GST_REGISTRY_READABLE &&
496         !(registry->flags & GST_REGISTRY_DELAYED_LOADING)) {
497       gst_registry_load (registry);
498     }
499     
500     walk = g_list_next (walk);
501   }
502 }
503
504 /**
505  * gst_registry_pool_plugin_list:
506  *
507  * Get a list of all plugins in the pool.
508  * 
509  * Returns: a GList of plugins, g_list_free after use.
510  */
511 GList*
512 gst_registry_pool_plugin_list (void)
513 {
514   GList *result = NULL;
515   GList *walk = _gst_registry_pool;
516
517   while (walk) {
518     GstRegistry *registry = GST_REGISTRY (walk->data);
519
520     /* FIXME only include highest priority plugins */
521     result = g_list_concat (result, g_list_copy (registry->plugins));
522     
523     walk = g_list_next (walk);
524   }
525   
526   return result;
527 }
528
529 /**
530  * gst_registry_pool_feature_list:
531  * @type: the type of the features to list.
532  *
533  * Get a list of all pluginfeatures of the given type in the pool.
534  * 
535  * Returns: a GList of pluginfeatures, g_list_free after use.
536  */
537 GList*
538 gst_registry_pool_feature_list (GType type)
539 {
540   GList *result = NULL;
541   GList *plugins = gst_registry_pool_plugin_list ();
542
543   while (plugins) {
544     GstPlugin *plugin = GST_PLUGIN (plugins->data);
545     GList *features = plugin->features;
546       
547     while (features) {
548       GstPluginFeature *feature = GST_PLUGIN_FEATURE (features->data);
549
550       if (type == 0 || G_OBJECT_TYPE (feature) == type) {
551         result = g_list_prepend (result, feature);
552       }
553       features = g_list_next (features);
554     }
555     plugins = g_list_next (plugins);
556   }
557   result = g_list_reverse (result);
558   
559   return result;
560 }
561
562 /**
563  * gst_registry_pool_find_plugin:
564  * @name: the name of the plugin to find
565  *
566  * Get the named plugin from the registry pool
567  * 
568  * Returns: The plugin with the given name or NULL if the plugin 
569  * was not found.
570  */
571 GstPlugin*
572 gst_registry_pool_find_plugin (const gchar *name)
573 {
574   GstPlugin *result = NULL;
575   GList *walk;
576   
577   result =  gst_plugin_list_find_plugin (_gst_registry_pool_plugins, name);
578   if (result)
579     return result;
580
581   walk = _gst_registry_pool;
582
583   while (walk) {
584     GstRegistry *registry = GST_REGISTRY (walk->data);
585
586     /* FIXME only include highest priority plugins */
587     result = gst_registry_find_plugin (registry, name);
588     if (result)
589       return result;
590     
591     walk = g_list_next (walk);
592   }
593   return NULL;
594 }
595
596 /**
597  * gst_registry_pool_find_feature:
598  * @name: the name of the pluginfeature to find
599  * @type: the type of the pluginfeature to find
600  *
601  * Get the pluginfeature with the given name and type from the pool of
602  * registries.
603  * 
604  * Returns: A pluginfeature with the given name and type or NULL if the feature
605  * was not found.
606  */
607 GstPluginFeature*
608 gst_registry_pool_find_feature (const gchar *name, GType type)
609 {
610   GstPluginFeature *result = NULL;
611   GList *walk;
612   
613   result = gst_plugin_list_find_feature (_gst_registry_pool_plugins, name, type);
614   if (result)
615     return result;
616   
617   walk = _gst_registry_pool;
618
619   while (walk) {
620     GstRegistry *registry = GST_REGISTRY (walk->data);
621
622     /* FIXME only include highest priority plugins */
623     result = gst_registry_find_feature (registry, name, type);
624     if (result)
625       return result;
626     
627     walk = g_list_next (walk);
628   }
629   return NULL;
630 }
631
632 /**
633  * gst_registry_pool_get_prefered:
634  * @flags: The flags for the prefered registry
635  *
636  * Get the prefered registry with the given flags
637  * 
638  * Returns: The registry with the flags.
639  */
640 GstRegistry*
641 gst_registry_pool_get_prefered (GstRegistryFlags flags)
642 {
643   GList *walk = _gst_registry_pool;
644
645   while (walk) {
646     GstRegistry *registry = GST_REGISTRY (walk->data);
647
648     if (registry->flags & flags)
649       return registry;
650     
651     walk = g_list_next (walk);
652   }
653   return NULL;
654 }
655
656
657
658 static gchar *gst_registry_option = NULL;
659
660 /* save the registry specified as an option */
661 void
662 gst_registry_option_set (const gchar *registry)
663 {
664   gst_registry_option = g_strdup (registry);
665   return;
666 }
667
668 /* decide if we're going to use the global registry or not 
669  * - if root, use global
670  * - if not root :
671  *   - if user can write to global, use global
672  *   - else use local
673  */
674 gboolean
675 gst_registry_use_global (void)
676 {
677   /* struct stat reg_stat; */
678   FILE *reg;
679   
680   if (getuid () == 0) return TRUE;      /* root always uses global */
681
682   /* check if we can write to the global registry somehow */
683   reg = fopen (GLOBAL_REGISTRY_FILE, "a");
684   if (reg == NULL) { return FALSE; }
685   else
686   {
687     /* we can write to it, do so for kicks */
688     fclose (reg);
689   }
690   
691   /* we can write to it, so now see if we can write in the dir as well */ 
692   if (access (GLOBAL_REGISTRY_DIR, W_OK) == 0) return TRUE;
693
694   return FALSE;
695 }
696
697 /* get the data that tells us where we can write the registry
698  * Allocate, fill in the GstRegistryWrite struct according to 
699  * current situation, and return it */
700 GstRegistryWrite *
701 gst_registry_write_get ()
702 {
703   GstRegistryWrite *gst_reg = g_malloc (sizeof (GstRegistryWrite));
704   
705   /* if a registry is specified on command line, use that one */
706   if (gst_registry_option)
707   {
708     /* FIXME: maybe parse the dir from file ? */
709     gst_reg->dir = NULL;
710     gst_reg->file = gst_registry_option;
711     /* we cannot use the temp dir since the move needs to be on same device */
712     gst_reg->tmp_file = g_strdup_printf ("%s.tmp", gst_registry_option);
713   }
714   else if (g_getenv ("GST_REGISTRY"))
715   {
716     gst_reg->dir = NULL;
717     gst_reg->file = g_strdup (g_getenv ("GST_REGISTRY"));
718     gst_reg->tmp_file = g_strdup_printf ("%s.tmp", g_getenv ("GST_REGISTRY"));
719   }
720   else
721   {
722     if (gst_registry_use_global ())
723     {
724       gst_reg->dir      = g_strdup (GLOBAL_REGISTRY_DIR);
725       gst_reg->file     = g_strdup (GLOBAL_REGISTRY_FILE);
726       gst_reg->tmp_file = g_strdup (GLOBAL_REGISTRY_FILE_TMP);
727     }
728     else
729     {
730       gchar *homedir = (gchar *) g_get_home_dir ();
731       
732       gst_reg->dir = g_strjoin ("/", homedir, LOCAL_REGISTRY_DIR, NULL);
733       gst_reg->file = g_strjoin ("/", homedir, LOCAL_REGISTRY_FILE, NULL);
734       gst_reg->tmp_file = g_strjoin ("/", homedir, LOCAL_REGISTRY_FILE_TMP, NULL);
735     }
736   } 
737   return gst_reg;
738 }
739
740 /* fill in the GstRegistryRead struct according to current situation */
741 GstRegistryRead *
742 gst_registry_read_get ()
743 {
744   GstRegistryRead *gst_reg = g_new0 (GstRegistryRead, 1);
745   
746   /* if a registry is specified on command line, use that one */
747   if (gst_registry_option)
748   {
749     /* FIXME: maybe parse the dir from file ? */
750     gst_reg->local_reg = NULL;
751     gst_reg->global_reg = gst_registry_option;
752   } 
753   else if (g_getenv ("GST_REGISTRY"))
754   {
755     gst_reg->local_reg = NULL;
756     gst_reg->global_reg = g_strdup (g_getenv ("GST_REGISTRY"));
757   }
758   else
759   {
760     gchar *homedir = (gchar *) g_get_home_dir ();
761     gst_reg->local_reg = g_strjoin ("/", homedir, LOCAL_REGISTRY_FILE, NULL);
762     if (g_file_test (gst_reg->local_reg, G_FILE_TEST_EXISTS) == FALSE)
763     {
764       /* it does not exist, so don't read from it */
765       g_free (gst_reg->local_reg);
766       gst_reg->local_reg = NULL;
767     }
768     gst_reg->global_reg = g_strdup (GLOBAL_REGISTRY_FILE);
769   }
770   return gst_reg;
771 }