FIx memleak in save-thyself introduced by changing plugin_get_list to copy.
[platform/upstream/gstreamer.git] / gst / gstplugin.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstplugin.c: Plugin subsystem for loading elements, types, and libs
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 <sys/types.h>
24 #include <sys/stat.h>
25 #include <dirent.h>
26 #include <unistd.h>
27
28 #undef RTLD_GLOBAL
29
30 #include "gst_private.h"
31 #include "gstplugin.h"
32 #include "gstversion.h"
33 #include "config.h"
34
35
36 /* list of loaded modules and its sequence number */
37 GList *_gst_modules;
38 gint _gst_modules_seqno;
39 /* global list of plugins and its sequence number */
40 GList *_gst_plugins;
41 gint _gst_plugins_seqno;
42 gint _gst_plugin_elementfactories = 0;
43 gint _gst_plugin_types = 0;
44 /* list of paths to check for plugins */
45 GList *_gst_plugin_paths;
46
47 GList *_gst_libraries;
48 gint _gst_libraries_seqno;
49
50 /* whether or not to spew library load issues */
51 gboolean _gst_plugin_spew = FALSE;
52
53 /* whether or not to warn if registry needs rebuild (gstreamer-register sets
54  * this to false.) */
55 gboolean _gst_warn_old_registry = TRUE;
56
57 static gboolean plugin_times_older_than(time_t regtime);
58 static time_t get_time(const char * path);
59
60 void
61 _gst_plugin_initialize (void)
62 {
63   xmlDocPtr doc;
64   _gst_modules = NULL;
65   _gst_modules_seqno = 0;
66   _gst_plugins = NULL;
67   _gst_plugins_seqno = 0;
68   _gst_plugin_paths = NULL;
69   _gst_libraries = NULL;
70   _gst_libraries_seqno = 0;
71
72   /* add the main (installed) library path */
73   _gst_plugin_paths = g_list_prepend (_gst_plugin_paths, PLUGINS_DIR);
74
75   /* if this is set, we add build-directory paths to the list */
76 #ifdef PLUGINS_USE_SRCDIR
77   /* the catch-all plugins directory */
78   _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,
79                                       PLUGINS_SRCDIR "/plugins");
80   /* the libreary directory */
81   _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,
82                                       PLUGINS_SRCDIR "/libs");
83   /* location libgstelements.so */
84   _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,
85                                       PLUGINS_SRCDIR "/gst/elements");
86   _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,
87                                       PLUGINS_SRCDIR "/gst/types");
88   _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,
89                                       PLUGINS_SRCDIR "/gst/autoplug");
90 #endif /* PLUGINS_USE_SRCDIR */
91
92   doc = xmlParseFile (GST_CONFIG_DIR"/reg.xml");
93
94   if (!doc || 
95       !doc->xmlRootNode ||
96       doc->xmlRootNode->name == 0 ||
97       strcmp (doc->xmlRootNode->name, "GST-PluginRegistry") ||
98       !plugin_times_older_than(get_time(GST_CONFIG_DIR"/reg.xml"))) {
99     if (_gst_warn_old_registry)
100         g_warning ("gstplugin: registry needs rebuild: run gstreamer-register\n");
101     gst_plugin_load_all ();
102     return;
103   }
104   gst_plugin_load_thyself (doc->xmlRootNode);
105
106   xmlFreeDoc (doc);
107 }
108
109 /**
110  * gst_plugin_add_path:
111  * @path: the directory to add to the search path
112  *
113  * Add a directory to the path searched for plugins.
114  */
115 void
116 gst_plugin_add_path (const gchar *path)
117 {
118   _gst_plugin_paths = g_list_prepend (_gst_plugin_paths,g_strdup(path));
119 }
120
121 static time_t
122 get_time(const char * path)
123 {
124   struct stat statbuf;
125   if (stat(path, &statbuf)) return 0;
126   if (statbuf.st_mtime > statbuf.st_ctime) return statbuf.st_mtime;
127   return statbuf.st_ctime;
128 }
129
130 static gboolean
131 plugin_times_older_than_recurse(gchar *path, time_t regtime)
132 {
133   DIR *dir;
134   struct dirent *dirent;
135   gchar *pluginname;
136
137   time_t pathtime = get_time(path);
138
139   if (pathtime > regtime) {
140     GST_INFO (GST_CAT_PLUGIN_LOADING,
141                "time for %s was %ld; more recent than registry time of %ld\n",
142                path, (long)pathtime, (long)regtime);
143     return FALSE;
144   }
145
146   dir = opendir(path);
147   if (dir) {
148     while ((dirent = readdir(dir))) {
149       /* don't want to recurse in place or backwards */
150       if (strcmp(dirent->d_name,".") && strcmp(dirent->d_name,"..")) {
151         pluginname = g_strjoin("/",path,dirent->d_name,NULL);
152         if (!plugin_times_older_than_recurse(pluginname , regtime)) {
153           g_free (pluginname);
154           closedir(dir);
155           return FALSE;
156         }
157         g_free (pluginname);
158       }
159     }
160     closedir(dir);
161   }
162   return TRUE;
163 }
164
165 static gboolean
166 plugin_times_older_than(time_t regtime)
167 {
168   // return true iff regtime is more recent than the times of all the files
169   // in the plugin dirs.
170   GList *path;
171   path = _gst_plugin_paths;
172   while (path != NULL) {
173     GST_DEBUG (GST_CAT_PLUGIN_LOADING,
174                "comparing plugin times from %s with %ld\n",
175                (gchar *)path->data, (long) regtime);
176     if(!plugin_times_older_than_recurse(path->data, regtime))
177         return FALSE;
178     path = g_list_next(path);
179   }
180   return TRUE;
181 }
182
183 static gboolean
184 gst_plugin_load_recurse (gchar *directory, gchar *name)
185 {
186   DIR *dir;
187   struct dirent *dirent;
188   gboolean loaded = FALSE;
189   gchar *dirname;
190
191   //g_print("recursive load of '%s' in '%s'\n", name, directory);
192   dir = opendir(directory);
193   if (dir) {
194     while ((dirent = readdir(dir))) {
195       /* don't want to recurse in place or backwards */
196       if (strcmp(dirent->d_name,".") && strcmp(dirent->d_name,"..")) {
197         dirname = g_strjoin("/",directory,dirent->d_name,NULL);
198         loaded = gst_plugin_load_recurse(dirname,name);
199         g_free(dirname);
200         if (loaded && name) {
201           closedir(dir);
202           return TRUE;
203         }
204       }
205     }
206     closedir(dir);
207   } else {
208     if (strstr(directory,".so")) {
209       gchar *temp;
210       if (name) {
211         if ((temp = strstr(directory,name)) &&
212             (!strcmp(temp,name))) {
213           loaded = gst_plugin_load_absolute(directory);
214         }
215       } else if ((temp = strstr(directory,".so")) &&
216                  (!strcmp(temp,".so"))) {
217         loaded = gst_plugin_load_absolute(directory);
218       }
219     }
220   }
221   return loaded;
222 }
223
224 /**
225  * gst_plugin_load_all:
226  *
227  * Load all plugins in the path.
228  */
229 void
230 gst_plugin_load_all(void)
231 {
232   GList *path;
233
234   path = _gst_plugin_paths;
235   while (path != NULL) {
236     GST_INFO (GST_CAT_PLUGIN_LOADING,"loading plugins from %s",(gchar *)path->data);
237     gst_plugin_load_recurse(path->data,NULL);
238     path = g_list_next(path);
239   }
240   GST_INFO (GST_CAT_PLUGIN_LOADING,"loaded %d plugins with %d elements and %d types",
241        _gst_plugins_seqno,_gst_plugin_elementfactories,_gst_plugin_types);
242 }
243
244 /**
245  * gst_library_load:
246  * @name: name of library to load
247  *
248  * Load the named library.  Name should be given as
249  * &quot;liblibrary.so&quot;.
250  *
251  * Returns: whether the library was loaded or not
252  */
253 gboolean
254 gst_library_load (const gchar *name)
255 {
256   gboolean res;
257   GList *libraries = _gst_libraries;
258
259   while (libraries) {
260     if (!strcmp((gchar *)libraries->data, name)) return TRUE;
261
262     libraries = g_list_next(libraries);
263   }
264
265   // for now this is the same
266   res = gst_plugin_load(name);
267
268   if (res) {
269     _gst_libraries = g_list_prepend(_gst_libraries, g_strdup (name));
270   }
271
272   return res;
273 }
274
275 static void
276 gst_plugin_remove (GstPlugin *plugin)
277 {
278   GList *factories;
279
280   factories = plugin->elements;
281   while (factories) {
282     gst_elementfactory_destroy ((GstElementFactory*)(factories->data));
283     factories = g_list_next(factories);
284   }
285
286   _gst_plugins = g_list_remove(_gst_plugins, plugin);
287
288   // don't free the stuct because someone can have a handle to it
289 }
290
291 /**
292  * gst_plugin_load:
293  * @name: name of plugin to load
294  *
295  * Load the named plugin.  Name should be given as
296  * &quot;libplugin.so&quot;.
297  *
298  * Returns: whether the plugin was loaded or not
299  */
300 gboolean
301 gst_plugin_load (const gchar *name)
302 {
303   GList *path;
304   gchar *libspath;
305   GstPlugin *plugin;
306   gchar *pluginname;
307
308   //g_print("attempting to load plugin '%s'\n",name);
309
310   plugin = gst_plugin_find (name);
311
312   if (plugin && plugin->loaded) return TRUE;
313
314   path = _gst_plugin_paths;
315   while (path != NULL) {
316     pluginname = g_module_build_path(path->data,name);
317     if (gst_plugin_load_absolute(pluginname)) {
318       g_free(pluginname);
319       return TRUE;
320     }
321     g_free(pluginname);
322     libspath = g_strconcat(path->data,"/.libs",NULL);
323     //g_print("trying to load '%s'\n",g_module_build_path(libspath,name));
324     pluginname = g_module_build_path(libspath,name);
325     g_free(libspath);
326     if (gst_plugin_load_absolute(pluginname)) {
327       g_free(pluginname);
328       return TRUE;
329     }
330     g_free(pluginname);
331     //g_print("trying to load '%s' from '%s'\n",name,path->data);
332     pluginname = g_module_build_path("",name);
333     if (gst_plugin_load_recurse(path->data,pluginname)) {
334       g_free(pluginname);
335       return TRUE;
336     }
337     g_free(pluginname);
338     path = g_list_next(path);
339   }
340   return FALSE;
341 }
342
343 /**
344  * gst_plugin_load_absolute:
345  * @name: name of plugin to load
346  *
347  * Returns: whether or not the plugin loaded
348  */
349 gboolean
350 gst_plugin_load_absolute (const gchar *name)
351 {
352   GModule *module;
353   GstPluginDesc *desc;
354   GstPlugin *plugin;
355   struct stat file_status;
356
357   GST_INFO (GST_CAT_PLUGIN_LOADING,"plugin \"%s\" loading", name);
358
359   if (g_module_supported() == FALSE) {
360     g_warning("gstplugin: wow, you built this on a platform without dynamic loading???\n");
361     return FALSE;
362   }
363
364   if (stat(name,&file_status)) {
365     //g_print("problem opening file %s\n",name);
366     return FALSE;
367   }
368
369   module = g_module_open(name,G_MODULE_BIND_LAZY);
370   if (module != NULL) {
371     if (g_module_symbol(module,"plugin_desc",(gpointer *)&desc)) {
372       GST_INFO (GST_CAT_PLUGIN_LOADING,"loading plugin \"%s\"...", name);
373       plugin = gst_plugin_new(desc->name, desc->major_version, desc->minor_version);
374       if (plugin != NULL) {
375         plugin->filename = g_strdup(name);
376         if (!((desc->plugin_init)(module, plugin))) {
377           GST_INFO (GST_CAT_PLUGIN_LOADING,"plugin \"%s\" failed to initialise",
378              plugin->name);
379           g_free(plugin);
380           plugin = NULL;
381         }
382       }
383
384       if (plugin != NULL) {
385         GST_INFO (GST_CAT_PLUGIN_LOADING,"plugin \"%s\" loaded: %d elements, %d types",
386              plugin->name,plugin->numelements,plugin->numtypes);
387         plugin->loaded = TRUE;
388         _gst_modules = g_list_prepend(_gst_modules,module);
389         _gst_modules_seqno++;
390         _gst_plugins = g_list_prepend(_gst_plugins,plugin);
391         _gst_plugins_seqno++;
392         _gst_plugin_elementfactories += plugin->numelements;
393         _gst_plugin_types += plugin->numtypes;
394         return TRUE;
395       }
396     }
397     return TRUE;
398   } else if (_gst_plugin_spew) {
399     // FIXME this should be some standard gst mechanism!!!
400     g_printerr ("error loading plugin %s, reason: %s\n", name, g_module_error());
401   }
402   else {
403     GST_INFO (GST_CAT_PLUGIN_LOADING, "error loading plugin %s, reason: %s\n", name, g_module_error());
404   }
405
406   return FALSE;
407 }
408
409 /**
410  * gst_plugin_new:
411  * @name: name of new plugin
412  * @major: major version number of core that plugin is compatible with
413  * @minor: minor version number of core that plugin is compatible with
414  *
415  * Create a new plugin with given name.
416  *
417  * Returns: new plugin, or NULL if plugin couldn't be created, due to
418  * incompatible version number, or name already being allocated)
419  */
420 GstPlugin*
421 gst_plugin_new (const gchar *name, gint major, gint minor)
422 {
423   GstPlugin *plugin;
424
425   // return NULL if the major and minor version numbers are not compatible
426   // with ours.
427   if (major != GST_VERSION_MAJOR || minor != GST_VERSION_MINOR) return NULL;
428
429   // return NULL if the plugin is allready loaded
430   plugin = gst_plugin_find (name);
431   if (plugin) return NULL;
432
433   plugin = (GstPlugin *)g_malloc(sizeof(GstPlugin));
434
435   plugin->name = g_strdup(name);
436   plugin->longname = NULL;
437   plugin->elements = NULL;
438   plugin->numelements = 0;
439   plugin->types = NULL;
440   plugin->numtypes = 0;
441   plugin->autopluggers = NULL;
442   plugin->numautopluggers = 0;
443   plugin->loaded = TRUE;
444
445   return plugin;
446 }
447
448 /**
449  * gst_plugin_get_name:
450  * @plugin: plugin to get the name of
451  *
452  * Get the short name of the plugin
453  *
454  * Returns: the name of the plugin
455  */
456 const gchar*
457 gst_plugin_get_name (GstPlugin *plugin)
458 {
459   g_return_val_if_fail (plugin != NULL, NULL);
460
461   return plugin->name;
462 }
463
464 /**
465  * gst_plugin_set_name:
466  * @plugin: plugin to set name of
467  * @name: new name
468  *
469  * Sets the name (should be short) of the plugin.
470  */
471 void
472 gst_plugin_set_name (GstPlugin *plugin, const gchar *name)
473 {
474   g_return_if_fail (plugin != NULL);
475
476   if (plugin->name)
477     g_free (plugin->name);
478
479   plugin->name = g_strdup (name);
480 }
481
482 /**
483  * gst_plugin_set_longname:
484  * @plugin: plugin to set long name of
485  * @longname: new long name
486  *
487  * Sets the long name (should be descriptive) of the plugin.
488  */
489 void
490 gst_plugin_set_longname (GstPlugin *plugin, const gchar *longname)
491 {
492   g_return_if_fail(plugin != NULL);
493
494   if (plugin->longname)
495     g_free(plugin->longname);
496
497   plugin->longname = g_strdup(longname);
498 }
499
500 /**
501  * gst_plugin_get_longname:
502  * @plugin: plugin to get long name of
503  *
504  * Get the long descriptive name of the plugin
505  *
506  * Returns: the long name of the plugin
507  */
508 const gchar*
509 gst_plugin_get_longname (GstPlugin *plugin)
510 {
511   g_return_val_if_fail (plugin != NULL, NULL);
512
513   return plugin->longname;
514 }
515
516 /**
517  * gst_plugin_get_filename:
518  * @plugin: plugin to get the filename of
519  *
520  * get the filename of the plugin
521  *
522  * Returns: the filename of the plugin
523  */
524 const gchar*
525 gst_plugin_get_filename (GstPlugin *plugin)
526 {
527   g_return_val_if_fail (plugin != NULL, NULL);
528
529   return plugin->filename;
530 }
531
532 /**
533  * gst_plugin_is_loaded:
534  * @plugin: plugin to query
535  *
536  * queries if the plugin is loaded into memory
537  *
538  * Returns: TRUE is loaded, FALSE otherwise
539  */
540 gboolean
541 gst_plugin_is_loaded (GstPlugin *plugin)
542 {
543   g_return_val_if_fail (plugin != NULL, FALSE);
544
545   return plugin->loaded;
546 }
547
548
549 /**
550  * gst_plugin_find:
551  * @name: name of plugin to find
552  *
553  * Search the list of registered plugins for one of the given name
554  *
555  * Returns: pointer to the #GstPlugin if found, NULL otherwise
556  */
557 GstPlugin*
558 gst_plugin_find (const gchar *name)
559 {
560   GList *plugins = _gst_plugins;
561
562   g_return_val_if_fail(name != NULL, NULL);
563
564   while (plugins) {
565     GstPlugin *plugin = (GstPlugin *)plugins->data;
566 //    g_print("plugin name is '%s'\n",plugin->name);
567     if (plugin->name) {
568       if (!strcmp(plugin->name,name)) {
569         return plugin;
570       }
571     }
572     plugins = g_list_next(plugins);
573   }
574   return NULL;
575 }
576
577 static GstElementFactory*
578 gst_plugin_find_elementfactory (const gchar *name)
579 {
580   GList *plugins, *factories;
581   GstElementFactory *factory;
582
583   g_return_val_if_fail(name != NULL, NULL);
584
585   plugins = _gst_plugins;
586   while (plugins) {
587     factories = ((GstPlugin *)(plugins->data))->elements;
588     while (factories) {
589       factory = (GstElementFactory*)(factories->data);
590       if (!strcmp(factory->name, name))
591         return (GstElementFactory*)(factory);
592       factories = g_list_next(factories);
593     }
594     plugins = g_list_next(plugins);
595   }
596
597   return NULL;
598 }
599
600 /**
601  * gst_plugin_load_elementfactory:
602  * @name: name of elementfactory to load
603  *
604  * Load a registered elementfactory by name.
605  *
606  * Returns: @GstElementFactory if loaded, NULL if not
607  */
608 GstElementFactory*
609 gst_plugin_load_elementfactory (const gchar *name)
610 {
611   GList *plugins, *factories;
612   GstElementFactory *factory = NULL;
613   GstPlugin *plugin;
614
615   g_return_val_if_fail(name != NULL, NULL);
616
617   plugins = _gst_plugins;
618   while (plugins) {
619     plugin = (GstPlugin *)plugins->data;
620     factories = plugin->elements;
621
622     while (factories) {
623       factory = (GstElementFactory*)(factories->data);
624
625       if (!strcmp(factory->name,name)) {
626         if (!plugin->loaded) {
627           gchar *filename = g_strdup (plugin->filename);
628           gchar *pluginname = g_strdup (plugin->name);
629
630           GST_INFO (GST_CAT_PLUGIN_LOADING,"loaded elementfactory %s from plugin %s",name,plugin->name);
631           gst_plugin_remove(plugin);
632           if (!gst_plugin_load_absolute(filename)) {
633             GST_DEBUG (0,"gstplugin: error loading element factory %s from plugin %s\n", name, pluginname);
634           }
635           g_free (pluginname);
636           g_free (filename);
637         }
638         factory = gst_plugin_find_elementfactory(name);
639         return factory;
640       }
641       factories = g_list_next(factories);
642     }
643     plugins = g_list_next(plugins);
644   }
645
646   return factory;
647 }
648
649 static GstAutoplugFactory*
650 gst_plugin_find_autoplugfactory (const gchar *name)
651 {
652   GList *plugins, *factories;
653   GstAutoplugFactory *factory;
654
655   g_return_val_if_fail(name != NULL, NULL);
656
657   plugins = _gst_plugins;
658   while (plugins) {
659     factories = ((GstPlugin *)(plugins->data))->autopluggers;
660     while (factories) {
661       factory = (GstAutoplugFactory*)(factories->data);
662       if (!strcmp(factory->name, name))
663         return (GstAutoplugFactory*)(factory);
664       factories = g_list_next(factories);
665     }
666     plugins = g_list_next(plugins);
667   }
668
669   return NULL;
670 }
671 /**
672  * gst_plugin_load_autoplugfactory:
673  * @name: name of autoplugfactory to load
674  *
675  * Load a registered autoplugfactory by name.
676  *
677  * Returns: @GstAutoplugFactory if loaded, NULL if not
678  */
679 GstAutoplugFactory*
680 gst_plugin_load_autoplugfactory (const gchar *name)
681 {
682   GList *plugins, *factories;
683   GstAutoplugFactory *factory = NULL;
684   GstPlugin *plugin;
685
686   g_return_val_if_fail(name != NULL, NULL);
687
688   plugins = _gst_plugins;
689   while (plugins) {
690     plugin = (GstPlugin *)plugins->data;
691     factories = plugin->autopluggers;
692
693     while (factories) {
694       factory = (GstAutoplugFactory*)(factories->data);
695
696       if (!strcmp(factory->name,name)) {
697         if (!plugin->loaded) {
698           gchar *filename = g_strdup (plugin->filename);
699           gchar *pluginname = g_strdup (plugin->name);
700
701           GST_INFO (GST_CAT_PLUGIN_LOADING,"loaded autoplugfactory %s from plugin %s",name,plugin->name);
702           gst_plugin_remove(plugin);
703           if (!gst_plugin_load_absolute(filename)) {
704             GST_DEBUG (0,"gstplugin: error loading autoplug factory %s from plugin %s\n", name, pluginname);
705           }
706           g_free (pluginname);
707           g_free (filename);
708         }
709         factory = gst_plugin_find_autoplugfactory(name);
710         return factory;
711       }
712       factories = g_list_next(factories);
713     }
714     plugins = g_list_next(plugins);
715   }
716
717   return factory;
718 }
719
720 /**
721  * gst_plugin_load_typefactory:
722  * @mime: name of typefactory to load
723  *
724  * Load a registered typefactory by mime type.
725  */
726 void
727 gst_plugin_load_typefactory (const gchar *mime)
728 {
729   GList *plugins, *factories;
730   GstTypeFactory *factory;
731   GstPlugin *plugin;
732
733   g_return_if_fail (mime != NULL);
734
735   plugins = g_list_copy (_gst_plugins);
736   while (plugins) {
737     plugin = (GstPlugin *)plugins->data;
738     factories = g_list_copy (plugin->types);
739
740     while (factories) {
741       factory = (GstTypeFactory*)(factories->data);
742
743       if (!strcmp(factory->mime,mime)) {
744         if (!plugin->loaded) {
745           gchar *filename = g_strdup (plugin->filename);
746           gchar *pluginname = g_strdup (plugin->name);
747
748           GST_INFO (GST_CAT_PLUGIN_LOADING,"loading type factory for \"%s\" from plugin %s",mime,plugin->name);
749           plugin->loaded = TRUE;
750           gst_plugin_remove(plugin);
751           if (!gst_plugin_load_absolute(filename)) {
752             GST_DEBUG (0,"gstplugin: error loading type factory \"%s\" from plugin %s\n", mime, pluginname);
753           }
754           g_free (filename);
755           g_free (pluginname);
756         }
757         //return;
758       }
759       factories = g_list_next(factories);
760     }
761
762     g_list_free (factories);
763     plugins = g_list_next(plugins);
764   }
765   g_list_free (plugins);
766
767   return;
768 }
769
770 /**
771  * gst_plugin_add_factory:
772  * @plugin: plugin to add factory to
773  * @factory: factory to add
774  *
775  * Add factory to the list of those provided by the plugin.
776  */
777 void
778 gst_plugin_add_factory (GstPlugin *plugin, GstElementFactory *factory)
779 {
780   g_return_if_fail (plugin != NULL);
781   g_return_if_fail (factory != NULL);
782
783 //  g_print("adding factory to plugin\n");
784   plugin->elements = g_list_prepend (plugin->elements, factory);
785   plugin->numelements++;
786 }
787
788 /**
789  * gst_plugin_add_type:
790  * @plugin: plugin to add type to
791  * @factory: the typefactory to add
792  *
793  * Add a typefactory to the list of those provided by the plugin.
794  */
795 void
796 gst_plugin_add_type (GstPlugin *plugin, GstTypeFactory *factory)
797 {
798   g_return_if_fail (plugin != NULL);
799   g_return_if_fail (factory != NULL);
800
801 //  g_print("adding factory to plugin\n");
802   plugin->types = g_list_prepend (plugin->types, factory);
803   plugin->numtypes++;
804   gst_type_register (factory);
805 }
806
807 /**
808  * gst_plugin_add_autoplugger:
809  * @plugin: plugin to add the autoplugger to
810  * @factory: the autoplugfactory to add
811  *
812  * Add an autoplugfactory to the list of those provided by the plugin.
813  */
814 void
815 gst_plugin_add_autoplugger (GstPlugin *plugin, GstAutoplugFactory *factory)
816 {
817   g_return_if_fail (plugin != NULL);
818   g_return_if_fail (factory != NULL);
819
820 //  g_print("adding factory to plugin\n");
821   plugin->autopluggers = g_list_prepend (plugin->autopluggers, factory);
822   plugin->numautopluggers++;
823 }
824
825 /**
826  * gst_plugin_get_list:
827  *
828  * get the currently loaded plugins
829  *
830  * Returns; a GList of GstPlugin elements
831  */
832 GList*
833 gst_plugin_get_list (void)
834 {
835   return g_list_copy (_gst_plugins);
836 }
837
838 /**
839  * gst_plugin_save_thyself:
840  * @parent: the parent node to save the plugin to
841  *
842  * saves the plugin into an XML representation
843  *
844  * Returns: the new XML node
845  */
846 xmlNodePtr
847 gst_plugin_save_thyself (xmlNodePtr parent)
848 {
849   xmlNodePtr tree, subtree;
850   GList *plugins = NULL, *elements = NULL, *types = NULL, *autopluggers = NULL;
851
852   plugins = g_list_copy (_gst_plugins);
853   while (plugins) {
854     GstPlugin *plugin = (GstPlugin *)plugins->data;
855
856     tree = xmlNewChild (parent, NULL, "plugin", NULL);
857     xmlNewChild (tree, NULL, "name", plugin->name);
858     xmlNewChild (tree, NULL, "longname", plugin->longname);
859     xmlNewChild (tree, NULL, "filename", plugin->filename);
860
861     types = plugin->types;
862     while (types) {
863       GstTypeFactory *factory = (GstTypeFactory *)types->data;
864       subtree = xmlNewChild(tree, NULL, "typefactory", NULL);
865
866       gst_typefactory_save_thyself (factory, subtree);
867
868       types = g_list_next (types);
869     }
870     elements = plugin->elements;
871     while (elements) {
872       GstElementFactory *factory = (GstElementFactory *)elements->data;
873       subtree = xmlNewChild (tree, NULL, "elementfactory", NULL);
874
875       gst_elementfactory_save_thyself (factory, subtree);
876
877       elements = g_list_next (elements);
878     }
879     autopluggers = plugin->autopluggers;
880     while (autopluggers) {
881       GstAutoplugFactory *factory = (GstAutoplugFactory *)autopluggers->data;
882       subtree = xmlNewChild (tree, NULL, "autoplugfactory", NULL);
883
884       gst_autoplugfactory_save_thyself (factory, subtree);
885
886       autopluggers = g_list_next (autopluggers);
887     }
888     plugins = g_list_next (plugins);
889   }
890   g_list_free (plugins);
891   return parent;
892 }
893
894 /**
895  * gst_plugin_load_thyself:
896  * @parent: the parent node to load the plugin from
897  *
898  * load the plugin from an XML representation
899  */
900 void
901 gst_plugin_load_thyself (xmlNodePtr parent)
902 {
903   xmlNodePtr kinderen;
904   gint elementcount = 0;
905   gint autoplugcount = 0;
906   gint typecount = 0;
907   gchar *pluginname;
908
909   kinderen = parent->xmlChildrenNode; // Dutch invasion :-)
910   while (kinderen) {
911     if (!strcmp (kinderen->name, "plugin")) {
912       xmlNodePtr field = kinderen->xmlChildrenNode;
913       GstPlugin *plugin = g_new0 (GstPlugin, 1);
914
915       plugin->elements = NULL;
916       plugin->types = NULL;
917       plugin->loaded = FALSE;
918
919       while (field) {
920         if (!strcmp (field->name, "name")) {
921           pluginname = xmlNodeGetContent (field);
922           if (gst_plugin_find (pluginname)) {
923             g_free (pluginname);
924             g_free (plugin);
925             plugin = NULL;
926             break;
927           } else {
928             plugin->name = pluginname;
929           }
930         }
931         else if (!strcmp (field->name, "longname")) {
932           plugin->longname = xmlNodeGetContent (field);
933         }
934         else if (!strcmp (field->name, "filename")) {
935           plugin->filename = xmlNodeGetContent (field);
936         }
937         else if (!strcmp (field->name, "elementfactory")) {
938           GstElementFactory *factory = gst_elementfactory_load_thyself (field);
939           gst_plugin_add_factory (plugin, factory);
940           elementcount++;
941         }
942         else if (!strcmp (field->name, "autoplugfactory")) {
943           GstAutoplugFactory *factory = gst_autoplugfactory_load_thyself (field);
944           gst_plugin_add_autoplugger (plugin, factory);
945           autoplugcount++;
946         }
947         else if (!strcmp (field->name, "typefactory")) {
948           GstTypeFactory *factory = gst_typefactory_load_thyself (field);
949           gst_plugin_add_type (plugin, factory);
950           elementcount++;
951           typecount++;
952         }
953
954         field = field->next;
955       }
956
957       if (plugin) {
958         _gst_plugins = g_list_prepend (_gst_plugins, plugin);
959       }
960     }
961
962     kinderen = kinderen->next;
963   }
964   GST_INFO (GST_CAT_PLUGIN_LOADING, "added %d registered factories, %d autopluggers and %d types",
965                   elementcount, autoplugcount, typecount);
966 }
967
968
969 /**
970  * gst_plugin_get_factory_list:
971  * @plugin: the plugin to get the factories from
972  *
973  * get a list of all the factories that this plugin provides
974  *
975  * Returns: a GList of factories
976  */
977 GList*
978 gst_plugin_get_factory_list (GstPlugin *plugin)
979 {
980   g_return_val_if_fail (plugin != NULL, NULL);
981
982   return plugin->elements;
983 }
984
985 /**
986  * gst_plugin_get_type_list:
987  * @plugin: the plugin to get the typefactories from
988  *
989  * get a list of all the typefactories that this plugin provides
990  *
991  * Returns: a GList of factories
992  */
993 GList*
994 gst_plugin_get_type_list (GstPlugin *plugin)
995 {
996   g_return_val_if_fail (plugin != NULL, NULL);
997
998   return plugin->types;
999 }
1000
1001 /**
1002  * gst_plugin_get_autoplug_list:
1003  * @plugin: the plugin to get the autoplugfactories from
1004  *
1005  * get a list of all the autoplugfactories that this plugin provides
1006  *
1007  * Returns: a GList of factories
1008  */
1009 GList*
1010 gst_plugin_get_autoplug_list (GstPlugin *plugin)
1011 {
1012   g_return_val_if_fail (plugin != NULL, NULL);
1013
1014   return plugin->autopluggers;
1015 }