1 /*
2  * Copyright (C) 2000-2020 the xine project
3  *
4  * This file is part of xine, a free video player.
5  *
6  * xine is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * xine 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
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19  *
20  *
21  * Load input/demux/audio_out/video_out/codec plugins
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 
28 #include <inttypes.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32 #include <pthread.h>
33 #ifdef HAVE_DIRENT_H
34 #include <dirent.h>
35 #endif
36 #include <dlfcn.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <ctype.h>
42 #include <signal.h>
43 
44 #include <basedir.h>
45 
46 #define LOG_MODULE "load_plugins"
47 #define LOG_VERBOSE
48 
49 /*
50 #define LOG
51 #define DEBUG
52 */
53 
54 #define XINE_ENABLE_EXPERIMENTAL_FEATURES 1
55 
56 /* save 1 lookup per entry by caching entry pointers not keys. */
57 #define FAST_SCAN_PLUGINS
58 
59 #include <xine/xine_internal.h>
60 #include <xine/xine_plugin.h>
61 #include <xine/plugin_catalog.h>
62 #include <xine/demux.h>
63 #include <xine/input_plugin.h>
64 #include <xine/video_out.h>
65 #include <xine/post.h>
66 #include <xine/xine_module.h>
67 #include <xine/metronom.h>
68 #include <xine/configfile.h>
69 #include <xine/xineutils.h>
70 #include <xine/compat.h>
71 
72 #include "xine_private.h"
73 
74 #ifdef XINE_MAKE_BUILTINS
75 #include "builtins.h"
76 #endif
77 
78 #if 0
79 
80 static char *plugin_name;
81 
82 #if DONT_CATCH_SIGSEGV
83 
84 #define install_segv_handler()
85 #define remove_segv_handler()
86 
87 #else
88 
89 void (*old_segv_handler)(int);
90 
91 static void segv_handler (int hubba) {
92   printf ("\nload_plugins: Initialization of plugin '%s' failed (segmentation fault).\n",plugin_name);
93   printf ("load_plugins: You probably need to remove the offending file.\n");
94   printf ("load_plugins: (This error is usually due an incorrect plugin version)\n");
95   _x_abort();
96 }
97 
98 static void install_segv_handler(void){
99   old_segv_handler = signal (SIGSEGV, segv_handler);
100 }
101 
102 static void remove_segv_handler(void){
103   signal (SIGSEGV, old_segv_handler );
104 }
105 
106 #endif
107 #endif /* 0 */
108 
109 #define CACHE_CATALOG_VERSION 4
110 #define CACHE_CATALOG_VERSION_STR "4"
111 
112 #define __Max(a,b) ((a) > (b) ? (a) : (b))
113 static const uint8_t plugin_iface_versions[__Max(PLUGIN_TYPE_MAX, PLUGIN_XINE_MODULE) + 1] = {
114   [PLUGIN_INPUT]         = INPUT_PLUGIN_IFACE_VERSION,
115   [PLUGIN_DEMUX]         = DEMUXER_PLUGIN_IFACE_VERSION,
116   [PLUGIN_AUDIO_DECODER] = AUDIO_DECODER_IFACE_VERSION,
117   [PLUGIN_VIDEO_DECODER] = VIDEO_DECODER_IFACE_VERSION,
118   [PLUGIN_SPU_DECODER]   = SPU_DECODER_IFACE_VERSION,
119   [PLUGIN_AUDIO_OUT]     = AUDIO_OUT_IFACE_VERSION,
120   [PLUGIN_VIDEO_OUT]     = VIDEO_OUT_DRIVER_IFACE_VERSION,
121   [PLUGIN_POST]          = POST_PLUGIN_IFACE_VERSION,
122   [PLUGIN_XINE_MODULE]   = XINE_MODULE_IFACE_VERSION,
123 };
124 
125 typedef union {
126   vo_info_t      vo_info;
127   ao_info_t      ao_info;
128   demuxer_info_t demuxer_info;
129   input_info_t   input_info;
130   decoder_info_t decoder_info;
131   post_info_t    post_info;
132   xine_module_info_t module_info;
133 } all_info_t;
134 
135 typedef struct fat_node_st {
136   plugin_node_t  node;
137   plugin_info_t  info[2];
138   all_info_t     ainfo;
139   plugin_file_t  file;
140   struct fat_node_st *nextplugin, *lastplugin;
141   xine_t        *xine;
142   uint32_t       supported_types[1];
143 } fat_node_t;
144 /* effectively next:
145   uint32_t       supported_types[num_supported_types];
146   char           id[idlen + 1];
147   char           filename[fnlen + 1];
148 */
149 
150 #define IS_FAT_NODE(_node) (_node->node.info == &_node->info[0])
151 
_fat_node_init(fat_node_t * node)152 static void _fat_node_init (fat_node_t *node) {
153 #ifdef HAVE_ZERO_SAFE_MEM
154   memset (node, 0, sizeof (*node));
155 #else
156   node->node.file              = NULL;
157   node->node.info              = NULL;
158   node->node.plugin_class      = NULL;
159   node->node.config_entry_list = NULL;
160   node->node.ref               = 0;
161   node->node.priority          = 0;
162   node->info[0].type         = 0;
163   node->info[0].API          = 0;
164   node->info[0].id           = NULL;
165   node->info[0].version      = 0;
166   node->info[0].special_info = NULL;
167   node->info[0].init         = NULL;
168   node->info[1].type         = 0;
169   node->ainfo.decoder_info.supported_types = NULL;
170   node->ainfo.decoder_info.priority        = 0;
171   node->file.filename    = NULL;
172   node->file.filesize    = 0;
173   node->file.filemtime   = 0;
174   node->file.lib_handle  = NULL;
175   node->file.ref         = 0;
176   node->file.no_unload   = 0;
177   node->supported_types[0] = 0;
178   node->nextplugin         = NULL;
179   node->xine               = NULL;
180 #endif
181   node->lastplugin = node;
182 }
183 
_fat_node_file_cmp(void * a_gen,void * b_gen)184 static int _fat_node_file_cmp (void *a_gen, void *b_gen) {
185   fat_node_t *a = a_gen, *b = b_gen;
186   if (a->file.filesize != b->file.filesize)
187     return a->file.filesize < b->file.filesize ? -1 : 1;
188   if (a->file.filemtime != b->file.filemtime)
189     return a->file.filemtime < b->file.filemtime ? -1 : 1;
190   return strcmp (a->file.filename, b->file.filename);
191 }
192 
193 
194 /* Note const char * --> void * is ok here as the strings are never written to. */
195 typedef int (_cmp_func_t) (void *a, void *b);
196 
_build_list_typed_plugins(xine_t * xine,int type)197 static const char * const *_build_list_typed_plugins (xine_t *xine, int type) {
198   plugin_catalog_t *catalog = xine->plugin_catalog;
199   xine_sarray_t    *a, *list;
200   plugin_node_t    *node;
201   int               list_id, list_size, i;
202 
203   pthread_mutex_lock (&catalog->lock);
204   list = catalog->plugin_lists[type - 1];
205   list_size = xine_sarray_size (list);
206   a = xine_sarray_new (list_size, (_cmp_func_t *)strcmp);
207   if (!a) {
208     catalog->ids[0] = NULL;
209     pthread_mutex_unlock (&catalog->lock);
210     return catalog->ids;
211   }
212   xine_sarray_set_mode (a, XINE_SARRAY_MODE_UNIQUE);
213   for (list_id = 0, i = 0; list_id < list_size; list_id++) {
214     node = xine_sarray_get (list, list_id);
215     /* add only unique ids to the list */
216     if (xine_sarray_add (a, (void *)node->info->id) >= 0)
217       catalog->ids[i++] = node->info->id;
218   }
219   catalog->ids[i] = NULL;
220   pthread_mutex_unlock (&catalog->lock);
221 
222   xine_sarray_delete (a);
223   return catalog->ids;
224 }
225 
inc_file_ref(plugin_file_t * file)226 static void inc_file_ref(plugin_file_t *file) {
227 /* all users do dereference "file" before calling this
228   _x_assert(file); */
229   file->ref++;
230 }
231 
dec_file_ref(plugin_file_t * file)232 static void dec_file_ref(plugin_file_t *file) {
233 /* all users do test "file" before calling this
234   _x_assert(file); */
235   _x_assert(file->ref > 0);
236 
237   file->ref--;
238   lprintf("file %s referenced %d time(s)\n", file->filename, file->ref);
239 }
240 
inc_node_ref(plugin_node_t * node)241 static void inc_node_ref(plugin_node_t *node) {
242 /* all users do dereference "node" before calling this
243   _x_assert(node); */
244   node->ref++;
245 }
246 
dec_node_ref(plugin_node_t * node)247 static void dec_node_ref(plugin_node_t *node) {
248 /* all users do test "node" before calling this
249   _x_assert(node); */
250   _x_assert(node->ref > 0);
251 
252   node->ref--;
253   lprintf("node %s referenced %d time(s)\n", node->info->id, node->ref);
254 }
255 
256 #ifndef FAST_SCAN_PLUGINS
_free_string_list(xine_list_t ** plist)257 static void _free_string_list(xine_list_t **plist) {
258   xine_list_t *list = *plist;
259 
260   if (list) {
261     char *key;
262     xine_list_iterator_t ite = NULL;
263     while ((key = xine_list_next_value (list, &ite)))
264       free (key);
265     xine_list_delete(list);
266     *plist = NULL;
267   }
268 }
269 #endif
270 
271 /*
272  * plugin list/catalog management functions
273  */
274 
map_decoder_list(xine_t * this,xine_sarray_t * decoder_list,plugin_node_t * decoder_map[DECODER_MAX][PLUGINS_PER_TYPE])275 static void map_decoder_list (xine_t *this,
276 			      xine_sarray_t *decoder_list,
277 			      plugin_node_t *decoder_map[DECODER_MAX][PLUGINS_PER_TYPE]) {
278   int i;
279   int list_id, list_size;
280 
281   /* init */
282   for (i = 0; i < DECODER_MAX; i++) {
283     decoder_map[i][0] = NULL;
284   }
285 
286   /*
287    * map decoders
288    */
289   list_size = xine_sarray_size(decoder_list);
290   /* this is sorted by falling priorities */
291   for (list_id = 0; list_id < list_size; list_id++) {
292 
293     plugin_node_t *node = xine_sarray_get(decoder_list, list_id);
294     const uint32_t *type = ((const decoder_info_t *)node->info->special_info)->supported_types;
295 
296     lprintf ("mapping decoder %s\n", node->info->id);
297 
298     while (type && (*type)) {
299 
300       int pos;
301       int streamtype = ((*type)>>16) & 0xFF;
302 
303       lprintf ("load_plugins: decoder handles stream type %02x, priority %d\n", streamtype, node->priority);
304 
305       /* find the right place based on the priority */
306       for (pos = 0; pos < PLUGINS_PER_TYPE; pos++) {
307         if (!decoder_map[streamtype][pos])
308           break;
309       }
310 
311       if ( pos == PLUGINS_PER_TYPE ) {
312 	xine_log (this, XINE_LOG_PLUGIN,
313 		  _("map_decoder_list: no space for decoder, skipped.\n"));
314 	type++;
315 	continue;
316       }
317 
318       /* shift the decoder list for this type by one to make room for new decoder */
319       if (pos < PLUGINS_PER_TYPE - 1)
320         decoder_map[streamtype][pos + 1] = NULL;
321 
322       /* insert new decoder */
323       decoder_map[streamtype][pos] = node;
324 
325       lprintf("decoder inserted in decoder map at %d\n", pos);
326 
327       type++;
328     }
329   }
330 }
331 
map_decoders(xine_t * this)332 static void map_decoders (xine_t *this) {
333 
334   plugin_catalog_t *catalog = this->plugin_catalog;
335 
336   lprintf ("map_decoders\n");
337 
338   /*
339    * map audio decoders
340    */
341   map_decoder_list(this, catalog->plugin_lists[PLUGIN_AUDIO_DECODER - 1], catalog->audio_decoder_map);
342   map_decoder_list(this, catalog->plugin_lists[PLUGIN_VIDEO_DECODER - 1], catalog->video_decoder_map);
343   map_decoder_list(this, catalog->plugin_lists[PLUGIN_SPU_DECODER - 1], catalog->spu_decoder_map);
344 
345 }
346 
347 /* Decoder priority callback */
_decoder_priority_cb(void * data,xine_cfg_entry_t * cfg)348 static void _decoder_priority_cb (void *data, xine_cfg_entry_t *cfg) {
349   /* sort decoders by priority */
350   xine_sarray_t *list;
351   int type;
352   fat_node_t *node = data;
353 
354   if (!node)
355     return;
356 
357   type = node->info->type & PLUGIN_TYPE_MASK;
358   list = node->xine->plugin_catalog->plugin_lists[type - 1];
359 
360   if (xine_sarray_remove_ptr (list, node) == ~0)
361     /* callback was triggered before the entry was added to plugin list */
362     return;
363   {
364     int user_prio = cfg->num_value;
365     /* user given priorities should definitely override defaults, so multiply them */
366     node->node.priority = user_prio ? user_prio * 100 : node->ainfo.decoder_info.priority;
367   }
368   xine_sarray_add (list, node);
369   map_decoder_list (node->xine, list,
370       type == PLUGIN_AUDIO_DECODER ? node->xine->plugin_catalog->audio_decoder_map
371     : type == PLUGIN_VIDEO_DECODER ? node->xine->plugin_catalog->video_decoder_map
372     : node->xine->plugin_catalog->spu_decoder_map);
373 }
374 
375 
_insert_file(xine_list_t * list,const char * filename,const struct stat * statbuffer,void * lib)376 static plugin_file_t *_insert_file (xine_list_t *list,
377                                     const char *filename,
378                                     const struct stat *statbuffer,
379                                     void *lib) {
380   size_t name_len = strlen(filename);
381   plugin_file_t *entry;
382   char *p;
383 
384   /* create the file entry */
385   p = malloc(sizeof(*entry) + name_len + 1);
386   if (!p)
387     return NULL;
388   entry = (plugin_file_t *)p;
389   entry->filename  = p + sizeof(*entry);
390   entry->filesize  = statbuffer->st_size;
391   entry->filemtime = statbuffer->st_mtime;
392   entry->lib_handle = lib;
393   entry->ref = 0;
394   entry->no_unload = 0;
395   xine_small_memcpy (entry->filename, filename, name_len + 1);
396 
397   xine_list_push_back (list, entry);
398   return entry;
399 }
400 
_insert_node(xine_t * this,plugin_file_t * file,fat_node_t * node_cache,const plugin_info_t * info)401 static int _insert_node (xine_t *this, plugin_file_t *file, fat_node_t *node_cache, const plugin_info_t *info) {
402 
403   fat_node_t       *entry;
404   const all_info_t *ainfo;
405   unsigned int num_supported_types = 0;
406   unsigned int plugin_type = info->type & PLUGIN_TYPE_MASK;
407   int          left;
408   const char  *what;
409 
410   /* sanity test */
411   left = PLUGIN_MAX - this->plugin_catalog->plugin_count;
412   do {
413     unsigned int flag;
414     if ((plugin_type <= 0) || ((plugin_type > PLUGIN_TYPE_MAX) && plugin_type != PLUGIN_XINE_MODULE)) {
415       if (file)
416         xine_log (this, XINE_LOG_PLUGIN,
417           _("load_plugins: unknown plugin type %d in %s\n"), plugin_type, file->filename);
418       else
419         xine_log (this, XINE_LOG_PLUGIN,
420           _("load_plugins: unknown statically linked plugin type %d\n"), plugin_type);
421       return 1;
422     }
423     if (!info->id) {
424       what = "id";
425       break;
426     }
427     if (info->API != plugin_iface_versions[plugin_type]) {
428       xine_log (this, XINE_LOG_PLUGIN,
429         _("load_plugins: ignoring plugin %s, wrong iface version %d (should be %d)\n"),
430         info->id, info->API, plugin_iface_versions[plugin_type]);
431       return 1;
432     }
433     if (!node_cache && !info->init) {
434       what = "init";
435       break;
436     }
437     ainfo = info->special_info;
438     flag = 1u << plugin_type;
439     if (flag & ((1u << PLUGIN_VIDEO_OUT) | (1u << PLUGIN_AUDIO_OUT) | (1u << PLUGIN_POST) |
440                 (1u << PLUGIN_AUDIO_DECODER) | (1u << PLUGIN_VIDEO_DECODER) |
441                 (1u << PLUGIN_SPU_DECODER) | (1u << PLUGIN_XINE_MODULE))) {
442       if (!ainfo) {
443         what = "special_info";
444         break;
445       }
446     }
447     if (flag & ((1u << PLUGIN_AUDIO_DECODER) | (1u << PLUGIN_VIDEO_DECODER) | (1u << PLUGIN_SPU_DECODER))) {
448       if (!ainfo->decoder_info.supported_types) {
449         what = "supported_types";
450         break;
451       }
452       if (!node_cache) {
453         while (ainfo->decoder_info.supported_types[num_supported_types])
454           num_supported_types++;
455       }
456       if (left > DECODER_MAX - this->plugin_catalog->decoder_count)
457         left = DECODER_MAX - this->plugin_catalog->decoder_count;
458     }
459     what = NULL;
460   } while (0);
461   if (what) {
462     xine_log (this, XINE_LOG_PLUGIN,
463       "load_plugins: plugin %s from %s is broken: %s = NULL\n",
464       info->id ? info->id : "??", file ? file->filename : "user", what);
465     return 1;
466   }
467   if (left <= 0) {
468     if (file)
469       xine_log (this, XINE_LOG_PLUGIN,
470         _("load_plugins: plugin limit reached, %s could not be loaded\n"), file->filename);
471     else
472       xine_log (this, XINE_LOG_PLUGIN,
473         _("load_plugins: plugin limit reached, static plugin could not be loaded\n"));
474     return 2;
475   }
476 
477   /* get target */
478   if (node_cache) {
479     entry = node_cache;
480   } else {
481     size_t idlen = strlen (info->id) + 1;
482     char *q;
483     entry = malloc (sizeof (*entry) + num_supported_types * sizeof (uint32_t) + idlen);
484     if (!entry)
485       return 2;
486     _fat_node_init (entry);
487     entry->node.info  = &entry->info[0];
488     entry->info[0]    = *info;
489     q = (char *)entry + sizeof (*entry) + num_supported_types * sizeof (uint32_t);
490     entry->info[0].id = q;
491     xine_small_memcpy (q, info->id, idlen);
492   }
493   entry->lastplugin = entry;
494   entry->xine       = this;
495   entry->node.file  = file;
496 
497   /* type specific stuff */
498   switch (plugin_type) {
499 
500   case PLUGIN_VIDEO_OUT:
501     entry->node.priority = entry->ainfo.vo_info.priority = ainfo->vo_info.priority;
502     entry->ainfo.vo_info.visual_type = ainfo->vo_info.visual_type;
503     break;
504 
505   case PLUGIN_AUDIO_OUT:
506     entry->node.priority = entry->ainfo.ao_info.priority = ainfo->ao_info.priority;
507     break;
508 
509   case PLUGIN_AUDIO_DECODER:
510   case PLUGIN_VIDEO_DECODER:
511   case PLUGIN_SPU_DECODER:
512     if (num_supported_types)
513       memcpy (&entry->supported_types[0], ainfo->decoder_info.supported_types, (num_supported_types + 1) * sizeof (uint32_t));
514     entry->ainfo.decoder_info.supported_types = &entry->supported_types[0];
515     entry->ainfo.decoder_info.priority = ainfo->decoder_info.priority;
516 
517     {
518       /* cnfig does dup all strings. no need to keep them here. */
519       char key[128], desc[256];
520       int user_prio;
521       snprintf (key, sizeof (key) - 1, "engine.decoder_priorities.%s", info->id);
522       snprintf (desc, sizeof (desc) - 1, _("priority for %s decoder"), info->id);
523       user_prio = this->config->register_num (this->config, key, 0, desc,
524         _("The priority provides a ranking in case some media "
525           "can be handled by more than one decoder.\n"
526           "A priority of 0 enables the decoder's default priority."), 20,
527         _decoder_priority_cb, entry);
528       /* reset priority on old config files */
529       if (this->config->current_version < 1) {
530         this->config->update_num (this->config, key, 0);
531         user_prio = 0;
532       }
533       entry->node.priority = user_prio ? user_prio * 100 : entry->ainfo.decoder_info.priority;
534     }
535     this->plugin_catalog->decoder_count++;
536     break;
537 
538   case PLUGIN_POST:
539     entry->ainfo.post_info.type = ainfo->post_info.type;
540     break;
541 
542   case PLUGIN_DEMUX:
543     if (ainfo) {
544       entry->node.priority = entry->ainfo.demuxer_info.priority = ainfo->demuxer_info.priority;
545       lprintf("demux: %s, priority: %d\n", info->id, entry->node.priority);
546     } else {
547       xprintf(this, XINE_VERBOSITY_LOG,
548               _("load_plugins: demuxer plugin %s does not provide a priority,"
549                 " xine-lib will use the default priority.\n"),
550               info->id);
551       entry->node.priority = entry->ainfo.demuxer_info.priority = 0;
552     }
553     break;
554 
555   case PLUGIN_INPUT:
556     if (ainfo) {
557       entry->node.priority = entry->ainfo.input_info.priority = ainfo->input_info.priority;
558       lprintf("input: %s, priority: %d\n", info->id, entry->node.priority);
559     } else {
560       xprintf(this, XINE_VERBOSITY_LOG,
561               _("load_plugins: input plugin %s does not provide a priority,"
562                 " xine-lib will use the default priority.\n"),
563               info->id);
564       entry->node.priority = entry->ainfo.input_info.priority = 0;
565     }
566     break;
567   case PLUGIN_XINE_MODULE:
568     entry->node.priority = ainfo->module_info.priority;
569     entry->ainfo.module_info = ainfo->module_info;
570     break;
571   }
572   entry->info[0].special_info = &entry->ainfo;
573 
574   if (file && (info->type & PLUGIN_NO_UNLOAD)) {
575     file->no_unload = 1;
576   }
577 
578   if (plugin_type == PLUGIN_XINE_MODULE)
579     xine_sarray_add (this->plugin_catalog->modules_list, &entry->node);
580   else
581     xine_sarray_add (this->plugin_catalog->plugin_lists[plugin_type - 1], &entry->node);
582   this->plugin_catalog->plugin_count++;
583   return 0;
584 }
585 
586 
_plugin_node_comparator(void * a,void * b)587 static int _plugin_node_comparator(void *a, void *b) {
588   const plugin_node_t *node_a = (const plugin_node_t *)a;
589   const plugin_node_t *node_b = (const plugin_node_t *)b;
590 
591   return (node_a->priority < node_b->priority) - (node_a->priority > node_b->priority);
592 }
593 
594 /* xine-ui simply makes a user config enum from post plugin list, and assumes the first one
595  * as the default. This effectively becomes a random choice, depending on the presence of
596  * other plugins, and of the order the file system returns them. So lets sort them by name
597  * as well here. */
_post_plugin_node_comparator(void * a,void * b)598 static int _post_plugin_node_comparator (void *a, void *b) {
599   const plugin_node_t *node_a = (const plugin_node_t *)a;
600   const plugin_node_t *node_b = (const plugin_node_t *)b;
601 
602   if (node_a->priority != node_b->priority)
603     return node_a->priority < node_b->priority ? 1 : -1;
604   return strcmp (node_a->info->id, node_b->info->id);
605 }
606 
_new_catalog(void)607 static plugin_catalog_t *_new_catalog(void){
608   plugin_catalog_t *catalog;
609 
610   catalog = calloc (1, sizeof (plugin_catalog_t));
611   if (catalog) {
612     int i;
613     for (i = 0; i < PLUGIN_TYPE_MAX; i++) {
614       catalog->plugin_lists[i] = xine_sarray_new (0,
615         i == PLUGIN_POST - 1 ? _post_plugin_node_comparator : _plugin_node_comparator);
616       if (!catalog->plugin_lists[i])
617         break;
618     }
619     if (i == PLUGIN_TYPE_MAX) {
620       catalog->cache_list = xine_sarray_new (0, _fat_node_file_cmp);
621       if (catalog->cache_list) {
622         xine_sarray_set_mode (catalog->cache_list, XINE_SARRAY_MODE_UNIQUE);
623         catalog->file_list = xine_list_new ();
624         if (catalog->file_list) {
625           catalog->modules_list = xine_sarray_new (0, _plugin_node_comparator);
626           if (catalog->modules_list) {
627           pthread_mutexattr_t attr;
628           pthread_mutexattr_init (&attr);
629           pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
630           pthread_mutex_init (&catalog->lock, &attr);
631           pthread_mutexattr_destroy (&attr);
632           return catalog;
633           }
634           xine_list_delete (catalog->file_list);
635         }
636         xine_sarray_delete (catalog->cache_list);
637       }
638     }
639     for (--i; i >= 0; i--)
640       xine_sarray_delete (catalog->plugin_lists[i]);
641     free (catalog);
642   }
643   return NULL;
644 }
645 
_register_plugins_internal(xine_t * this,plugin_file_t * file,fat_node_t * node_cache,const plugin_info_t * info)646 static void _register_plugins_internal (xine_t *this, plugin_file_t *file,
647   fat_node_t *node_cache, const plugin_info_t *info) {
648   /* user supplied xine_register_plugins () */
649   static const char * const st_names[10] = {
650     "user/none",
651     "user/input",
652     "user/demux",
653     "user/audio_decoder",
654     "user/video_decoder",
655     "user/spu_decoder",
656     "user/audio_out",
657     "user/video_out",
658     "user/post",
659     "user"
660   };
661   const char * const *names = st_names;
662 #ifdef XINE_MAKE_BUILTINS
663   static const char * const builtin_names[10] = {
664     "libxine/builtins/none",
665     "libxine/builtins/input",
666     "libxine/builtins/demux",
667     "libxine/builtins/audio_decoder",
668     "libxine/builtins/video_decoder",
669     "libxine/builtins/spu_decoder",
670     "libxine/builtins/audio_out",
671     "libxine/builtins/video_out",
672     "libxine/builtins/post",
673     "libxine/builtins"
674   };
675   if (info == xine_builtin_plugin_info)
676     names = builtin_names;
677 #endif
678 /* we had worse NOPs before ;-)
679   _x_assert(info); */
680 
681   while ( info && info->type != PLUGIN_NONE ) {
682     fat_node_t *cache_next = node_cache ? node_cache->nextplugin : NULL;
683     const char *fn;
684     int status;
685     if (file) {
686       fn = file->filename;
687     } else {
688       int n = info->type & PLUGIN_TYPE_MASK;
689       if (n > 9)
690         n = 9;
691       fn = names[n];
692     }
693     xine_log (this, XINE_LOG_PLUGIN, _("load_plugins: plugin %s:%s found\n"), fn, info->id);
694     status = _insert_node (this, file, node_cache, info);
695     /* get next info */
696     if( file && !file->lib_handle ) {
697       lprintf("get cached info\n");
698       if (status)
699         free (node_cache);
700       node_cache = cache_next;
701       info = node_cache ? node_cache->node.info : NULL;
702     } else {
703       info++;
704     }
705   }
706 }
707 
xine_register_plugins(xine_t * self,const plugin_info_t * info)708 void xine_register_plugins(xine_t *self, const plugin_info_t *info) {
709   if (self)
710     _register_plugins_internal (self, NULL, NULL, info);
711 }
712 
713 /*
714  * First stage plugin loader (catalog builder)
715  *
716  ***************************************************************************/
717 
collect_plugins(xine_t * this,const char * path,char * stop,char * pend)718 static void collect_plugins (xine_t *this, const char *path, char *stop, char *pend) {
719 
720   char          *adds[5];
721   DIR           *dirs[5];
722   struct stat    statbuf;
723   int            level;
724 
725   lprintf ("collect_plugins in %s\n", path);
726 
727   /* we need a dir to start */
728   if (stat (path, &statbuf))
729     return;
730   if (!S_ISDIR (statbuf.st_mode))
731     return;
732 
733   adds[0] = stop;
734   dirs[0] = NULL;
735   level   = 0;
736   while (1) {
737     struct dirent *dent;
738 
739     /* enter dir */
740     if (!dirs[level]) {
741       dirs[level] = opendir (path);
742       if (!dirs[level]) {
743         xine_log (this, XINE_LOG_PLUGIN,
744           _("load_plugins: skipping unreadable plugin directory %s.\n"), path);
745         level--;
746         if (level < 0)
747           break;
748         continue;
749       }
750     }
751 
752     /* get entry */
753     dent = readdir (dirs[level]);
754     if (!dent) {
755       closedir (dirs[level]);
756       level--;
757       if (level < 0)
758         break;
759       continue;
760     }
761 
762     {
763       void                *lib   = NULL;
764       const plugin_info_t *info  = NULL;
765       fat_node_t          *fatn_found;
766       char                *part  = adds[level], *q;
767 
768       *part++ = '/';
769       q = part + strlcpy (part, dent->d_name, pend - part);
770       if (q >= pend)
771         continue;
772 
773       if (stat (path, &statbuf)) {
774         xine_log (this, XINE_LOG_PLUGIN, _("load_plugins: unable to stat %s\n"), path);
775         continue;
776       }
777       switch (statbuf.st_mode & S_IFMT) {
778 
779 	case S_IFREG:
780 	  /* regular file, ie. plugin library, found => load it */
781 
782 	  /* this will fail whereever shared libs are called *.dll or such
783 	   * better solutions:
784            * a) don't install .la files on user's system
785            * b) also cache negative hits, ie. files that failed to dlopen()
786 	   */
787 #if defined(__hpux)
788           if (!strstr (part, ".sl")
789 #elif defined(__CYGWIN__) || defined(WIN32)
790           if (!strstr (part, ".dll") || strstr (part, ".dll.a")
791 #else
792           if (!strstr (part, ".so")
793 #endif
794 #ifdef HOST_OS_DARWIN
795              && !strcasestr (part, ".xineplugin")
796 #endif
797             )
798 	    break;
799 
800 	  lib = NULL;
801 
802 	  /* get the first plugin_info_t */
803           {
804             fat_node_t fatn_try;
805             int index;
806             fatn_try.file.filename = (char *)path; /* will not be written to */
807             fatn_try.file.filesize = statbuf.st_size;
808             fatn_try.file.filemtime = statbuf.st_mtime;
809             index = xine_sarray_binary_search (this->plugin_catalog->cache_list, &fatn_try);
810             if (index >= 0) {
811               fatn_found = xine_sarray_get (this->plugin_catalog->cache_list, index);
812               xine_sarray_remove (this->plugin_catalog->cache_list, index);
813             } else {
814               fatn_found = NULL;
815             }
816           }
817           info = fatn_found ? fatn_found->node.info : NULL;
818 #ifdef LOG
819 	  if( info )
820             printf ("load_plugins: using cached %s\n", path);
821 	  else
822             printf ("load_plugins: %s not cached\n", path);
823 #endif
824 
825           if (!info && (lib = dlopen (path, RTLD_LAZY | RTLD_GLOBAL)) == NULL) {
826 	    const char *error = dlerror();
827 	    /* too noisy -- but good to catch unresolved references */
828             xprintf (this, XINE_VERBOSITY_LOG,
829               _("load_plugins: cannot open plugin lib %s:\n%s\n"), path, error);
830 
831 	  } else {
832 
833 	    if (info || (info = dlsym(lib, "xine_plugin_info"))) {
834 	      plugin_file_t *file;
835 
836               file = _insert_file (this->plugin_catalog->file_list, path, &statbuf, lib);
837               if (file) {
838                 _register_plugins_internal (this, file, fatn_found, info);
839               } else {
840                 if (lib != NULL)
841                   dlclose(lib);
842               }
843 	    }
844 	    else {
845 	      const char *error = dlerror();
846 
847               xine_log (this, XINE_LOG_PLUGIN,
848                 _("load_plugins: can't get plugin info from %s:\n%s\n"), path, error);
849               dlclose(lib);
850 	    }
851 	  }
852 	  break;
853 	case S_IFDIR:
854 
855 	  /* unless ".", "..", ".hidden" or vidix driver dirs */
856           if ((part[0] != '.') && strcmp (part, "vidix")) {
857             if (level < 4) {
858               level++;
859               adds[level] = q;
860               dirs[level] = NULL;
861             }
862 	  }
863       } /* switch */
864     }
865   } /* while */
866 } /* collect_plugins */
867 
868 /*
869  * generic 2nd stage plugin loader
870  */
871 
_plugin_info_equal(const plugin_info_t * a,const plugin_info_t * b)872 static inline int _plugin_info_equal(const plugin_info_t *a,
873                                      const plugin_info_t *b) {
874   if (a->type != b->type ||
875       a->API != b->API ||
876       strcasecmp(a->id, b->id) ||
877       a->version != b->version)
878     return 0;
879 
880   switch (a->type & PLUGIN_TYPE_MASK) {
881     case PLUGIN_VIDEO_OUT:
882       /* FIXME: Could special_info be NULL? */
883       if (a->special_info && b->special_info) {
884         return (((const vo_info_t*)a->special_info)->visual_type ==
885                 ((const vo_info_t*)b->special_info)->visual_type);
886       }
887       /* if special info is missing, plugin file is broken ... */
888       return 0; /* skip it */
889     case PLUGIN_XINE_MODULE:
890       if (a->special_info && b->special_info) {
891         return !strcmp(((const xine_module_info_t*)a->special_info)->type,
892                        ((const xine_module_info_t*)b->special_info)->type);
893       }
894       return !(!a->special_info - !b->special_info);
895     default:
896       break;
897   }
898 
899   return 1;
900 }
901 
902 #ifdef FAST_SCAN_PLUGINS
903 typedef struct {
904   config_values_t *v;
905   plugin_node_t   *node;
906 } new_entry_data_t;
907 #else
_attach_entry_to_node(plugin_node_t * node,char * key)908 static void _attach_entry_to_node (plugin_node_t *node, char *key) {
909 
910   if (!node->config_entry_list) {
911     node->config_entry_list = xine_list_new();
912   }
913 
914   xine_list_push_back(node->config_entry_list, key);
915 }
916 #endif
917 
918 /*
919  * This callback is called by the config entry system when a plugin register a
920  * new config entry.
921  */
_new_entry_cb(void * user_data,xine_cfg_entry_t * entry)922 static void _new_entry_cb (void *user_data, xine_cfg_entry_t *entry) {
923 #ifdef FAST_SCAN_PLUGINS
924   new_entry_data_t *d = user_data;
925   if (!d->node->config_entry_list)
926     d->node->config_entry_list = xine_list_new ();
927   if (d->node->config_entry_list && d->v->cur && !xine_list_find (d->node->config_entry_list, d->v->cur))
928     xine_list_push_back (d->node->config_entry_list, d->v->cur);
929   (void)entry;
930 #else
931   plugin_node_t *node = (plugin_node_t *)user_data;
932 
933   _attach_entry_to_node(node, strdup(entry->key));
934 #endif
935 }
936 
_load_plugin_class(xine_t * this,plugin_node_t * node,const void * data)937 static int _load_plugin_class(xine_t *this,
938 			      plugin_node_t *node,
939                               const void *data) {
940   if (node->file) {
941     const char *filename = node->file->filename;
942     const plugin_info_t *target = node->info;
943     const plugin_info_t *info;
944     void *lib;
945 
946     /* load the dynamic library if needed */
947     if (!node->file->lib_handle) {
948       lprintf("dlopen %s\n", filename);
949       if ((lib = dlopen (filename, RTLD_LAZY | RTLD_GLOBAL)) == NULL) {
950 	const char *error = dlerror();
951 
952 	xine_log (this, XINE_LOG_PLUGIN,
953 		  _("load_plugins: cannot (stage 2) open plugin lib %s:\n%s\n"), filename, error);
954 	return 0;
955       } else {
956 	node->file->lib_handle = lib;
957       }
958     } else {
959       lprintf("%s already loaded\n", filename);
960     }
961 
962     if ((info = dlsym(node->file->lib_handle, "xine_plugin_info"))) {
963       /* TODO: use sigsegv handler */
964       while (info->type != PLUGIN_NONE) {
965 	if (_plugin_info_equal(info, target)) {
966           config_values_t *config = this->config;
967 #ifdef FAST_SCAN_PLUGINS
968           new_entry_data_t d;
969           d.v = config;
970           d.node = node;
971 #endif
972 	  /* the callback is called for each entry registered by this plugin */
973           lprintf("plugin init %s\n", node->info->id);
974           if (info->init) {
975 #ifdef FAST_SCAN_PLUGINS
976             config->set_new_entry_callback (config, _new_entry_cb, &d);
977 #else
978             config->set_new_entry_callback (config, _new_entry_cb, node);
979 #endif
980             node->plugin_class = info->init(this, data);
981             config->unset_new_entry_callback (config);
982           }
983 
984 	  if (node->plugin_class) {
985 	    inc_file_ref(node->file);
986 	    return 1;
987 	  } else {
988 	    return 0;
989 	  }
990 	}
991 	info++;
992       }
993       lprintf("plugin not found\n");
994 
995     } else {
996       xine_log (this, XINE_LOG_PLUGIN,
997 		_("load_plugins: Yikes! %s doesn't contain plugin info.\n"), filename);
998     }
999   } else {
1000     /* statically linked plugin */
1001     lprintf("statically linked plugin\n");
1002     if (node->info->init) {
1003       node->plugin_class = node->info->init(this, data);
1004       return 1;
1005     }
1006   }
1007   return 0; /* something failed if we came here... */
1008 }
1009 
_dispose_plugin_class(plugin_node_t * node)1010 static void _dispose_plugin_class(plugin_node_t *node) {
1011 
1012   if (node->plugin_class) {
1013     void *cls = node->plugin_class;
1014 
1015     _x_assert(node->info);
1016     /* dispose of plugin class */
1017     switch (node->info->type & PLUGIN_TYPE_MASK) {
1018     case PLUGIN_INPUT:
1019       if (((input_class_t *)cls)->dispose)
1020         ((input_class_t *)cls)->dispose ((input_class_t *)cls);
1021       break;
1022     case PLUGIN_DEMUX:
1023       if (((demux_class_t *)cls)->dispose)
1024         ((demux_class_t *)cls)->dispose ((demux_class_t *)cls);
1025       break;
1026     case PLUGIN_SPU_DECODER:
1027       if (((spu_decoder_class_t *)cls)->dispose)
1028         ((spu_decoder_class_t *)cls)->dispose ((spu_decoder_class_t *)cls);
1029       break;
1030     case PLUGIN_AUDIO_DECODER:
1031       if (((audio_decoder_class_t *)cls)->dispose)
1032         ((audio_decoder_class_t *)cls)->dispose ((audio_decoder_class_t *)cls);
1033       break;
1034     case PLUGIN_VIDEO_DECODER:
1035       if (((video_decoder_class_t *)cls)->dispose)
1036         ((video_decoder_class_t *)cls)->dispose ((video_decoder_class_t *)cls);
1037       break;
1038     case PLUGIN_AUDIO_OUT:
1039       if (((audio_driver_class_t *)cls)->dispose)
1040         ((audio_driver_class_t *)cls)->dispose ((audio_driver_class_t *)cls);
1041       break;
1042     case PLUGIN_VIDEO_OUT:
1043       if (((video_driver_class_t *)cls)->dispose)
1044         ((video_driver_class_t *)cls)->dispose ((video_driver_class_t *)cls);
1045       break;
1046     case PLUGIN_POST:
1047       if (((post_class_t *)cls)->dispose)
1048         ((post_class_t *)cls)->dispose ((post_class_t *)cls);
1049       break;
1050     case PLUGIN_XINE_MODULE:
1051       if (((xine_module_class_t *)cls)->dispose)
1052         ((xine_module_class_t *)cls)->dispose (cls);
1053       break;
1054     }
1055     node->plugin_class = NULL;
1056     if (node->file)
1057       dec_file_ref(node->file);
1058   }
1059 }
1060 
1061 /*
1062  *  load input+demuxer plugins
1063  *  load plugins that asked to be initialized
1064  */
_load_required_plugins(xine_t * this,xine_sarray_t * list)1065 static void _load_required_plugins(xine_t *this, xine_sarray_t *list) {
1066 
1067   int list_id = 0;
1068   int list_size;
1069 
1070   list_size = xine_sarray_size(list);
1071   while (list_id < list_size) {
1072     plugin_node_t *node = xine_sarray_get(list, list_id);
1073 
1074     /*
1075      * preload plugins if not cached
1076      */
1077     do {
1078       if (!(node->info->type & PLUGIN_MUST_PRELOAD)) /* no preload needed */
1079         break;
1080       if (node->plugin_class) /* is already loaded */
1081         break;
1082       if (node->file && !node->file->lib_handle) /* lib unavailable */
1083         break;
1084 
1085       lprintf ("preload plugin %s from %s\n", node->info->id, node->file ? node->file->filename : "libxine/builtins");
1086 
1087       if (! _load_plugin_class (this, node, NULL)) {
1088 	/* in case of failure remove from list */
1089 
1090 	xine_sarray_remove(list, list_id);
1091 	list_size = xine_sarray_size(list);
1092         list_id--;
1093       }
1094     } while (0);
1095     list_id++;
1096   }
1097 }
1098 
load_required_plugins(xine_t * this)1099 static void load_required_plugins(xine_t *this) {
1100   int i;
1101 
1102   for (i = 0; i < PLUGIN_TYPE_MAX; i++) {
1103     _load_required_plugins (this, this->plugin_catalog->plugin_lists[i]);
1104   }
1105 }
1106 
1107 /*
1108  *  save plugin list information to file (cached catalog)
1109  */
save_plugin_list(xine_t * this,FILE * fp,xine_sarray_t * list)1110 static void save_plugin_list(xine_t *this, FILE *fp, xine_sarray_t *list) {
1111 
1112   int list_id = 0;
1113   int list_size;
1114 #define SAVE_PLUGIN_BUF_SIZE 4096
1115   char b[SAVE_PLUGIN_BUF_SIZE];
1116   char *e = b + SAVE_PLUGIN_BUF_SIZE - 78 - 2 * XINE_MAX_INT64_STR - 5 * XINE_MAX_INT32_STR;
1117 
1118   list_size = xine_sarray_size (list);
1119   while (list_id < list_size) {
1120     int pri;
1121     char *q = b;
1122     const plugin_node_t *node = xine_sarray_get (list, list_id);
1123     const plugin_file_t *file = node->file;
1124     if (file) {
1125       *q++ = '[';
1126       q += strlcpy (q, file->filename, e - q);
1127       if (q >= e)
1128         q = e - 1;
1129       memcpy (q, "]\nsize=", 7); q += 7;
1130       xine_uint2str (&q, file->filesize);
1131       memcpy (q, "\nmtime=", 7); q += 7;
1132       xine_uint2str (&q, file->filemtime);
1133       *q++ = '\n';
1134     } else {
1135       /* dump builtins for debugging */
1136       memcpy (q, "[libxine/builtins]\n", 20); q += 19;
1137     }
1138     memcpy (q, "type=", 5); q += 5;
1139     xine_uint32_2str (&q, node->info->type);
1140     memcpy (q, "\napi=", 5); q += 5;
1141     xine_uint32_2str (&q, node->info->API);
1142     memcpy (q, "\nid=", 4); q += 4;
1143     q += strlcpy (q, node->info->id, e - q);
1144     if (q >= e)
1145       q = e - 1;
1146     memcpy (q, "\nversion=", 9); q += 9;
1147     xine_uint32_2str (&q, node->info->version);
1148     *q++ = '\n';
1149 
1150     switch (node->info->type & PLUGIN_TYPE_MASK){
1151 
1152       case PLUGIN_VIDEO_OUT: {
1153         const vo_info_t *vo_info = node->info->special_info;
1154         memcpy (q, "visual_type=", 12); q += 12;
1155         xine_int32_2str (&q, vo_info->visual_type);
1156         memcpy (q, "\nvo_priority=", 13); q += 13;
1157         pri = vo_info->priority;
1158         goto write_pri;
1159       }
1160       case PLUGIN_AUDIO_OUT: {
1161         const ao_info_t *ao_info = node->info->special_info;
1162         memcpy (q, "ao_priority=", 12); q += 12;
1163         pri = ao_info->priority;
1164         goto write_pri;
1165       }
1166       case PLUGIN_AUDIO_DECODER:
1167       case PLUGIN_VIDEO_DECODER:
1168       case PLUGIN_SPU_DECODER: {
1169         const decoder_info_t *decoder_info = node->info->special_info;
1170         const uint32_t *t;
1171         memcpy (q, "supported_types=", 16); q += 16;
1172         t = decoder_info->supported_types;
1173         while (*t) {
1174           xine_uint32_2str (&q, *t++);
1175           if (q >= e) {
1176             fwrite (b, 1, q - b, fp);
1177             q = b;
1178           }
1179           *q++ = ' ';
1180         }
1181         q[-1] = '\n';
1182         memcpy (q, "decoder_priority=", 17); q += 17;
1183         pri = decoder_info->priority;
1184         goto write_pri;
1185       }
1186       case PLUGIN_DEMUX: {
1187         const demuxer_info_t *demuxer_info = node->info->special_info;
1188         memcpy (q, "demuxer_priority=", 17); q += 17;
1189         pri = demuxer_info->priority;
1190         goto write_pri;
1191       }
1192       case PLUGIN_INPUT: {
1193         const input_info_t *input_info = node->info->special_info;
1194         memcpy (q, "input_priority=", 15); q += 15;
1195         pri = input_info->priority;
1196         goto write_pri;
1197       }
1198       case PLUGIN_POST: {
1199         const post_info_t *post_info = node->info->special_info;
1200         memcpy (q, "post_type=", 10); q += 10;
1201         xine_uint32_2str (&q, post_info->type);
1202         *q++ = '\n';
1203         break;
1204       }
1205       case PLUGIN_XINE_MODULE: {
1206         const xine_module_info_t *module_info = node->info->special_info;
1207         size_t type_len = strlen(module_info->type);
1208         memcpy (q, "module_type=", 12); q += 12;
1209         memcpy (q, module_info->type, type_len); q += type_len;
1210         memcpy (q, "\nmodule_sub_type=", 17); q += 17;
1211         xine_int32_2str (&q, module_info->sub_type);
1212         memcpy (q, "\nmodule_priority=", 17); q += 17;
1213         pri = module_info->priority;
1214         goto write_pri;
1215       }
1216       write_pri:
1217         xine_int32_2str (&q, pri);
1218         *q++ = '\n';
1219     }
1220     fwrite (b, 1, q - b, fp);
1221 
1222     /* config entries */
1223     if (node->config_entry_list) {
1224       xine_list_iterator_t ite = NULL;
1225 #ifdef FAST_SCAN_PLUGINS
1226       cfg_entry_t *entry;
1227 #else
1228       const char *entry;
1229 #endif
1230       while ((entry = xine_list_next_value (node->config_entry_list, &ite))) {
1231         char *key_value;
1232 #ifdef FAST_SCAN_PLUGINS
1233         pthread_mutex_lock (&this->config->config_lock);
1234         this->config->cur = entry;
1235         key_value = this->config->get_serialized_entry (this->config, NULL);
1236         pthread_mutex_unlock (&this->config->config_lock);
1237 #else
1238         /* now serialize the config key */
1239         key_value = this->config->get_serialized_entry (this->config, entry);
1240 #endif
1241         if (key_value) {
1242           size_t slen = strlen (key_value);
1243 #ifdef FAST_SCAN_PLUGINS
1244           lprintf ("  config key: %s, serialization: %zu bytes\n", entry->key, slen);
1245 #else
1246           lprintf ("  config key: %s, serialization: %zu bytes\n", entry, slen);
1247 #endif
1248           fwrite ("config_key=", 1, 11, fp);
1249           key_value[slen] = '\n';
1250           fwrite (key_value, 1, slen + 1, fp);
1251           free (key_value);
1252         }
1253       }
1254     }
1255 
1256     fwrite ("\n", 1, 1, fp);
1257     list_id++;
1258   }
1259 }
1260 
1261 /*
1262  *  load plugin list information from file (cached catalog)
1263  */
load_plugin_list(xine_t * this,FILE * fp,xine_sarray_t * plugins)1264 static void load_plugin_list (xine_t *this, FILE *fp, xine_sarray_t *plugins) {
1265 
1266   fat_node_t node;
1267   size_t stlen, fnlen, idlen;
1268   /* We dont have that many types yet ;-) */
1269   uint32_t supported_types[256];
1270   char *cfgentries[256];
1271   int numcfgs;
1272 
1273   char *buf, *line, *nextline, *stop;
1274   int version_ok = 0;
1275   int skip = 0;
1276 
1277   {
1278     long int flen;
1279     fseek (fp, 0, SEEK_END);
1280     flen = ftell (fp);
1281     if (flen < 0)
1282       return;
1283     /* TJ. I got far less than 100k, so > 2M is probably insane. */
1284     if (flen > (2 << 20))
1285       flen = 2 << 20;
1286     buf = malloc (flen + 22);
1287     if (!buf)
1288       return;
1289     fseek (fp, 0, SEEK_SET);
1290     flen = fread (buf, 1, flen, fp);
1291     /* HACK: provoke clean exit */
1292     stop = buf + flen;
1293     memcpy (stop, "\n[libxine/builtins]\n\n", 22);
1294   }
1295 
1296   _fat_node_init (&node);
1297   stlen = 0;
1298   idlen = 0;
1299   fnlen = 0;
1300   numcfgs = 0;
1301 
1302   for (line = buf; line[0]; line = nextline) {
1303     char *value;
1304     /* make string from line */
1305     char *lend = strchr (line, '\n');
1306     if (!lend) { /* should not happen ('\0' in file) */
1307       nextline = stop;
1308       continue;
1309     }
1310     nextline = lend + 1;
1311     if ((lend > line) && (lend[-1] == '\r'))
1312       lend--;
1313     lend[0] = 0;
1314 
1315     /* skip comments */
1316     if (line[0] == '#')
1317       continue;
1318     /* skip (almost) empty lines */
1319     if (lend - line < 3)
1320       continue;
1321 
1322     /* file name */
1323     if (line[0] == '[' && version_ok) {
1324 
1325       if (node.file.filename) {
1326         fat_node_t *n;
1327         char *q;
1328         /* get mem for new node */
1329         n = malloc (sizeof (node) + stlen + idlen + fnlen);
1330         if (!n)
1331           break;
1332         /* fill in */
1333         *n = node;
1334         n->node.info = &n->info[0];
1335         q = (char *)n + sizeof (*n);
1336         if (stlen) {
1337           memcpy (&n->supported_types[0], &supported_types[0], stlen);
1338           q += stlen;
1339           n->ainfo.decoder_info.supported_types = &n->supported_types[0];
1340         }
1341         if (node.info[0].id) {
1342           xine_small_memcpy (q, node.info[0].id, idlen);
1343           n->info[0].id = q;
1344           q += idlen;
1345         }
1346         xine_small_memcpy (q, node.file.filename, fnlen);
1347         n->file.filename = q;
1348         n->node.file = &n->file;
1349         n->info[0].special_info = &n->ainfo;
1350         /* register */
1351         {
1352           int index = xine_sarray_add (plugins, n);
1353           if (index >= 0) { /* new file */
1354             n->lastplugin = n;
1355           } else {
1356             fat_node_t *first_in_file = xine_sarray_get (plugins, ~index);
1357             first_in_file->lastplugin->nextplugin = n;
1358             first_in_file->lastplugin = n;
1359           }
1360         }
1361         if (numcfgs) {
1362           char **cfgentry;
1363 #ifdef FAST_SCAN_PLUGINS
1364           new_entry_data_t ned;
1365           ned.v = this->config;
1366           ned.node = &n->node;
1367           this->config->set_new_entry_callback (this->config, _new_entry_cb, &ned);
1368 #endif
1369           cfgentries[numcfgs] = NULL;
1370           for (cfgentry = cfgentries; *cfgentry; cfgentry++) {
1371             char *cfg_key = this->config->register_serialized_entry (this->config, *cfgentry);
1372             if (cfg_key) {
1373               /* this node is a cached node */
1374 #ifdef FAST_SCAN_PLUGINS
1375               free (cfg_key);
1376 #else
1377               _attach_entry_to_node (&n->node, cfg_key);
1378 #endif
1379             } else {
1380               lprintf("failed to deserialize config entry key\n");
1381             }
1382           }
1383 #ifdef FAST_SCAN_PLUGINS
1384           this->config->unset_new_entry_callback (this->config);
1385 #endif
1386         }
1387         /* reset */
1388         _fat_node_init (&node);
1389         stlen = 0;
1390         numcfgs = 0;
1391       }
1392 
1393       value = strchr (line, ']');
1394       if (value)
1395         lend = value;
1396       lend[0] = 0;
1397       fnlen = lend - line /* - 1 + 1 */;
1398       line++;
1399 
1400       if (!strcmp (line, "libxine/builtins")) {
1401         skip = 1;
1402         continue;
1403       }
1404       skip = 0;
1405 
1406       node.file.filename = line;
1407       continue;
1408     }
1409 
1410     if (skip)
1411       continue;
1412 
1413     if ((value = strchr (line, '='))) {
1414       unsigned int index = 0;
1415       const char *val;
1416       *value++ = 0;
1417       val = value;
1418       /* get known key */
1419       {
1420         static const char * const known_keys[] = {
1421           "\x0b""ao_priority",
1422           "\x05""api",
1423           "\x01""cache_catalog_version",
1424           "\x10""config_key",
1425           "\x0c""decoder_priority",
1426           "\x0d""demuxer_priority",
1427           "\x06""id",
1428           "\x0e""input_priority",
1429           "\x11""module_priority",
1430           "\x12""module_sub_type",
1431           "\x13""module_type",
1432           "\x03""mtime",
1433           "\x0f""post_type",
1434           "\x02""size",
1435           "\x09""supported_types",
1436           "\x04""type",
1437           "\x07""version",
1438           "\x08""visual_type",
1439           "\x0a""vo_priority"
1440         };
1441         unsigned int b = 0, e = sizeof (known_keys) / sizeof (known_keys[0]), m = e >> 1;
1442         do {
1443           int d = strcmp (line, known_keys[m] + 1);
1444           if (d == 0) {
1445             index = known_keys[m][0];
1446             break;
1447           }
1448           if (d < 0)
1449             e = m;
1450           else
1451             b = m + 1;
1452           m = (b + e) >> 1;
1453         } while (b != e);
1454       }
1455       if( !version_ok ) {
1456         if (index == 1) { /* "cache_catalog_version" */
1457           if (xine_str2uint32 (&val) == CACHE_CATALOG_VERSION)
1458             version_ok = 1;
1459           else {
1460             free (buf);
1461             return;
1462           }
1463         }
1464       } else if (node.file.filename) {
1465         union {
1466           uint64_t llu;
1467           unsigned int u;
1468           int i;
1469         } v = {0};
1470         unsigned int mask = 1u << index;
1471         if (0x027d30 & mask) /* 17,14,13,12,11,10,8,5,4 */
1472           v.i = xine_str2int32 (&val);
1473         else if (0x048080 & mask) /* 18,15,7 */
1474           v.u = xine_str2uint32 (&val);
1475         else if (0x0000c & mask) /* 3,2 */
1476           v.llu = xine_str2uint64 (&val);
1477         switch (index) {
1478           case  2: /* "size" */
1479             node.file.filesize = v.llu;
1480             break;
1481           case  3: /* "mtime" */
1482             node.file.filemtime = v.llu;
1483             break;
1484           case  4: /* "type" */
1485             node.info[0].type = v.i;
1486             break;
1487           case  5: /* "api" */
1488             node.info[0].API = v.i;
1489             break;
1490           case  6: /* "id" */
1491             node.info[0].id = value;
1492             idlen = lend - value + 1;
1493             break;
1494           case  7: /* "version" */
1495             node.info[0].version = v.u;
1496             break;
1497           case  8: /* "visual_type" */
1498             node.ainfo.vo_info.visual_type = v.i;
1499             break;
1500           case  9: { /* "supported_types" */
1501             int i;
1502             for (i = 0; i < 255; i++) {
1503               if ((supported_types[i] = xine_str2uint32 (&val)) == 0)
1504                 break;
1505             }
1506             supported_types[i++] = 0;
1507             stlen = i * sizeof (*supported_types);
1508             break;
1509           }
1510           case 10: /* "vo_priority" */
1511             node.ainfo.vo_info.priority = v.i;
1512             break;
1513           case 11: /* "ao_priority" */
1514             node.ainfo.ao_info.priority = v.i;
1515             break;
1516           case 12: /* "decoder_priority" */
1517             node.ainfo.decoder_info.priority = v.i;
1518             break;
1519           case 13: /* "demuxer_priority" */
1520             node.ainfo.demuxer_info.priority = v.i;
1521             break;
1522           case 14: /* "input_priority" */
1523             node.ainfo.input_info.priority = v.i;
1524             break;
1525           case 15: /* "post_type" */
1526             node.ainfo.post_info.type = v.u;
1527             break;
1528           case 16: /* "config_key" */
1529             if (numcfgs < 255)
1530               cfgentries[numcfgs++] = value;
1531             break;
1532           case 17: /* "module_priority" */
1533             node.ainfo.module_info.priority = v.i;
1534             break;
1535           case 18: /* "module_sub_type" */
1536             node.ainfo.module_info.sub_type = v.u;
1537             break;
1538           case 19: /* "module_type" */
1539             strlcpy(node.ainfo.module_info.type, value, sizeof(node.ainfo.module_info.type));
1540           default: ;
1541         }
1542       }
1543     }
1544   }
1545 
1546   free (buf);
1547 }
1548 
1549 /**
1550  * @brief Returns the complete filename for the plugins' cache file
1551  * @param this Instance pointer, used for logging and libxdg-basedir.
1552  * @param createdir If not zero, create the directory structure in which
1553  *        the file has to reside.
1554  * @return If createdir was not zero, returns NULL if the directory hasn't
1555  *         been created; otherwise always returns a new string with the
1556  *         name of the cachefile.
1557  * @internal
1558  *
1559  * @see XDG Base Directory specification:
1560  *      http://standards.freedesktop.org/basedir-spec/latest/index.html
1561  */
catalog_filename(xine_t * this,int createdir)1562 static char *catalog_filename(xine_t *this, int createdir) {
1563   const char *const xdg_cache_home = xdgCacheHome(&this->basedir_handle);
1564   char *cachefile;
1565 
1566   if (!xdg_cache_home)
1567     return NULL;
1568 
1569   cachefile = malloc( strlen(xdg_cache_home) + sizeof("/"PACKAGE"/plugins.cache") );
1570   if (!cachefile)
1571     return NULL;
1572   strcpy(cachefile, xdg_cache_home);
1573 
1574   /* If we're going to create the directory structure, we concatenate
1575    * piece by piece the path, so that we can try to create all the
1576    * directories.
1577    * If we don't need to create anything, we just concatenate the
1578    * whole path at once.
1579    */
1580   if ( createdir ) {
1581     int result = 0;
1582 
1583     result = mkdir( cachefile, 0700 );
1584     if ( result != 0 && errno != EEXIST ) {
1585       xprintf (this, XINE_VERBOSITY_LOG, _("Unable to create %s directory: %s\n"), cachefile, strerror(errno));
1586       free(cachefile);
1587       return NULL;
1588     }
1589 
1590     strcat(cachefile, "/"PACKAGE);
1591     result = mkdir( cachefile, 0700 );
1592     if ( result != 0 && errno != EEXIST ) {
1593       xprintf (this, XINE_VERBOSITY_LOG, _("Unable to create %s directory: %s\n"), cachefile, strerror(errno));
1594       free(cachefile);
1595       return NULL;
1596     }
1597 
1598     strcat(cachefile, "/plugins.cache");
1599 
1600   } else
1601     strcat(cachefile, "/"PACKAGE"/plugins.cache");
1602 
1603   return cachefile;
1604 }
1605 
1606 /*
1607  * save catalog to cache file
1608  */
save_catalog(xine_t * this)1609 static void save_catalog (xine_t *this) {
1610   FILE       *fp;
1611   char *const cachefile = catalog_filename(this, 1);
1612   char *cachefile_new;
1613 
1614   if ( ! cachefile ) return;
1615 
1616   cachefile_new = _x_asprintf("%s.new", cachefile);
1617 
1618   if ((fp = fopen (cachefile_new, "wb")) != NULL) {
1619     int i;
1620 
1621     fwrite ("# this file is automatically created by xine, do not edit.\n\n"
1622             "cache_catalog_version=" CACHE_CATALOG_VERSION_STR "\n\n", 1, 85, fp);
1623 
1624     for (i = 0; i < PLUGIN_TYPE_MAX; i++) {
1625       save_plugin_list (this, fp, this->plugin_catalog->plugin_lists[i]);
1626     }
1627     save_plugin_list (this, fp, this->plugin_catalog->modules_list);
1628     if (fclose(fp))
1629     {
1630       const char *err = strerror (errno);
1631       xine_log (this, XINE_LOG_MSG,
1632 		_("failed to save catalogue cache: %s\n"), err);
1633       goto do_unlink;
1634     }
1635     else if (rename (cachefile_new, cachefile))
1636     {
1637       const char *err = strerror (errno);
1638       xine_log (this, XINE_LOG_MSG,
1639 		_("failed to replace catalogue cache: %s\n"), err);
1640       do_unlink:
1641       if (unlink (cachefile_new) && errno != ENOENT)
1642       {
1643 	err = strerror (errno);
1644 	xine_log (this, XINE_LOG_MSG,
1645 		  _("failed to remove new catalogue cache: %s\n"), err);
1646       }
1647     }
1648   }
1649   free(cachefile);
1650   free(cachefile_new);
1651 }
1652 
1653 /*
1654  * load cached catalog from file
1655  */
load_cached_catalog(xine_t * this)1656 static void load_cached_catalog (xine_t *this) {
1657 
1658   FILE *fp;
1659   char *const cachefile = catalog_filename(this, 0);
1660   /* It can't return NULL without creating directories */
1661 
1662   if ((fp = fopen (cachefile, "rb")) != NULL) {
1663     load_plugin_list (this, fp, this->plugin_catalog->cache_list);
1664     fclose(fp);
1665   }
1666   free(cachefile);
1667 }
1668 
1669 
1670 /*
1671  *  initialize catalog, load all plugins into new catalog
1672  */
_x_scan_plugins(xine_t * this_gen)1673 int _x_scan_plugins (xine_t *this_gen) {
1674 #define XSP_BUFSIZE 4096
1675   xine_private_t *this = (xine_private_t *)this_gen;
1676   char buf[XSP_BUFSIZE], *homeend, *bufend = buf + XSP_BUFSIZE - 16;
1677   const char *pluginpath = NULL;
1678   const char *homedir;
1679 
1680   lprintf("_x_scan_plugins()\n");
1681 
1682   _x_assert(this);
1683   _x_assert (this->x.config);
1684   _x_assert (!this->x.plugin_catalog);
1685 
1686   homedir = xine_get_homedir ();
1687   if (!homedir)
1688     return -1;
1689   {
1690     size_t len = strlen (homedir);
1691     if (len > XSP_BUFSIZE - 16)
1692       len = XSP_BUFSIZE - 16;
1693     xine_small_memcpy (buf, homedir, len);
1694     homeend = buf + len;
1695   }
1696 
1697   this->x.plugin_catalog = _new_catalog();
1698   if (!this->x.plugin_catalog)
1699     return -1;
1700 
1701   XINE_PROFILE (load_cached_catalog (&this->x));
1702 
1703 #ifdef XINE_MAKE_BUILTINS
1704   lprintf ("collect_plugins in libxine\n");
1705   _register_plugins_internal (&this->x, NULL, NULL , xine_builtin_plugin_info);
1706 #endif
1707 
1708   if ((pluginpath = getenv("XINE_PLUGIN_PATH")) != NULL && *pluginpath) {
1709 
1710     const char *start = pluginpath, *stop, *try;
1711     char *q;
1712     size_t len;
1713     while (1) {
1714       try = homeend;
1715       q   = homeend;
1716       if ((start[0] == '~') && (start[1] == '/')) {
1717         start += 1;
1718         try = buf;
1719       }
1720       stop = strchr (start, XINE_PATH_SEPARATOR_CHAR);
1721       if (!stop)
1722         break;
1723       len = stop - start;
1724       if (len > (size_t)(bufend - q))
1725         len = bufend - q;
1726       xine_small_memcpy (q, start, len); q += len;
1727       q[0] = 0;
1728       start = stop + 1;
1729       collect_plugins (&this->x, try, q, bufend);
1730     }
1731     len = strlen (start);
1732     if (len > (size_t)(bufend - q))
1733       len = bufend - q;
1734     xine_small_memcpy (q, start, len); q += len;
1735     q[0] = 0;
1736     collect_plugins (&this->x, try, q, bufend);
1737 
1738   } else {
1739 
1740     const char *p;
1741     size_t len;
1742     int i;
1743 
1744     memcpy (homeend, "/.xine/plugins", 15);
1745     collect_plugins (&this->x, buf, homeend + 15, bufend);
1746 
1747     p = XINE_PLUGINROOT;
1748     len = strlen (p);
1749     xine_small_memcpy (buf, p, len);
1750     buf[len++] = '.';
1751     for (i = XINE_LT_AGE; i >= 0; i--) {
1752       char *q = buf + len;
1753       xine_uint32_2str (&q, i);
1754       collect_plugins (&this->x, buf, q, bufend);
1755     }
1756   }
1757 
1758   load_required_plugins (&this->x);
1759 
1760   if ((this->flags & XINE_FLAG_NO_WRITE_CACHE) == 0)
1761     XINE_PROFILE (save_catalog (&this->x));
1762 
1763   map_decoders (&this->x);
1764 
1765   return 0;
1766 }
1767 
1768 /*
1769  * generic module loading
1770  */
_x_find_module(xine_t * xine,const char * type,const char * id,unsigned sub_type,const void * params)1771 xine_module_t *_x_find_module(xine_t *xine, const char *type, const char *id,
1772                               unsigned sub_type, const void *params) {
1773 
1774   plugin_catalog_t *catalog = xine->plugin_catalog;
1775   plugin_node_t    *node;
1776   xine_module_t    *plugin = NULL;
1777   int               list_id, list_size;
1778   const xine_module_info_t *info;
1779 
1780   pthread_mutex_lock (&catalog->lock);
1781 
1782   list_size = xine_sarray_size(catalog->modules_list);
1783   for (list_id = 0; list_id < list_size; list_id++) {
1784     node = xine_sarray_get (catalog->modules_list, list_id);
1785 
1786     if (id && strcmp (node->info->id, id))
1787       continue;
1788 
1789     info = node->info->special_info;
1790     if (sub_type != info->sub_type)
1791       continue;
1792     if (type && strcmp (info->type, type))
1793       continue;
1794 
1795     if (node->plugin_class || _load_plugin_class(xine, node, params)) {
1796       if ((plugin = ((xine_module_class_t *)node->plugin_class)->get_instance(node->plugin_class, params))) {
1797         inc_node_ref(node);
1798         plugin->node = node;
1799         break;
1800       }
1801     }
1802   }
1803 
1804   pthread_mutex_unlock (&catalog->lock);
1805 
1806   return plugin;
1807 }
1808 
_x_free_module(xine_t * xine,xine_module_t ** pmodule)1809 void _x_free_module(xine_t *xine, xine_module_t **pmodule) {
1810 
1811   xine_module_t    *module = *pmodule;
1812   plugin_catalog_t *catalog = xine->plugin_catalog;
1813   plugin_node_t    *node = module->node;
1814 
1815   *pmodule = NULL;
1816 
1817   module->dispose(module);
1818 
1819   if (node) {
1820     pthread_mutex_lock(&catalog->lock);
1821     dec_node_ref(node);
1822     pthread_mutex_unlock(&catalog->lock);
1823   }
1824 }
1825 
1826 /*
1827  * input / demuxer plugin loading
1828  */
1829 
_x_find_input_plugin(xine_stream_t * stream,const char * mrl)1830 input_plugin_t *_x_find_input_plugin (xine_stream_t *stream, const char *mrl) {
1831 
1832   xine_stream_private_t *s;
1833   xine_t *xine;
1834   plugin_catalog_t *catalog;
1835   input_plugin_t *plugin;
1836   uint32_t n;
1837 
1838   if (!stream || !mrl)
1839     return NULL;
1840 
1841   s = (xine_stream_private_t *)stream;
1842   xine = s->s.xine;
1843   catalog = xine->plugin_catalog;
1844   plugin = NULL;
1845 
1846   pthread_mutex_lock (&catalog->lock);
1847 
1848   n = !s->query_input_plugins[0] ? 0
1849     : !s->query_input_plugins[1] ? 1 : 2;
1850   if (n != 2) {
1851     int list_id, list_size;
1852     list_size = xine_sarray_size (catalog->plugin_lists[PLUGIN_INPUT - 1]);
1853     for (list_id = 0; list_id < list_size; list_id++) {
1854       plugin_node_t *node = xine_sarray_get (catalog->plugin_lists[PLUGIN_INPUT - 1], list_id);
1855       input_class_t *class = (input_class_t *)node->plugin_class;
1856       if (!class) {
1857         _load_plugin_class (xine, node, NULL);
1858         class = (input_class_t *)node->plugin_class;
1859       }
1860       if (class) {
1861         s->query_input_plugins[n] = class;
1862         if (s->query_input_plugins[0] != s->query_input_plugins[1]) {
1863           plugin = class->get_instance (class, stream, mrl);
1864           if (plugin) {
1865             inc_node_ref (node);
1866             plugin->node = node;
1867             break;
1868           }
1869         }
1870       }
1871     }
1872     s->query_input_plugins[n] = NULL;
1873   }
1874 
1875   pthread_mutex_unlock (&catalog->lock);
1876 
1877   return plugin;
1878 }
1879 
1880 
_x_free_input_plugin(xine_stream_t * stream,input_plugin_t * input)1881 void _x_free_input_plugin (xine_stream_t *stream, input_plugin_t *input) {
1882   plugin_catalog_t *catalog;
1883   plugin_node_t    *node;
1884 
1885   if (!input)
1886     return;
1887   node = input->node;
1888   input->dispose (input);
1889 
1890   if (!stream)
1891     return;
1892   catalog = stream->xine->plugin_catalog;
1893   if (node) {
1894     pthread_mutex_lock(&catalog->lock);
1895     dec_node_ref(node);
1896     pthread_mutex_unlock(&catalog->lock);
1897   }
1898 }
1899 
probe_mime_type(xine_t * self,plugin_node_t * node,const char * mime_type)1900 static int probe_mime_type (xine_t *self, plugin_node_t *node, const char *mime_type)
1901 {
1902   /* catalog->lock is expected to be locked */
1903   if (node->plugin_class || _load_plugin_class(self, node, NULL))
1904   {
1905     const unsigned int mime_type_len = strlen (mime_type);
1906     demux_class_t *cls = (demux_class_t *)node->plugin_class;
1907     const char *mime = cls->mimetypes;
1908     while (mime)
1909     {
1910       while (*mime == ';' || isspace (*mime))
1911         ++mime;
1912       if (!strncasecmp (mime, mime_type, mime_type_len) &&
1913           (!mime[mime_type_len] || mime[mime_type_len] == ':' || mime[mime_type_len] == ';'))
1914         return 1;
1915       mime = strchr (mime, ';');
1916     }
1917   }
1918   return 0;
1919 }
1920 
probe_demux(xine_stream_t * stream,int method1,int method2,input_plugin_t * input)1921 static demux_plugin_t *probe_demux (xine_stream_t *stream, int method1, int method2,
1922 				    input_plugin_t *input) {
1923 
1924   int               i;
1925   int               methods[3];
1926   plugin_catalog_t *catalog = stream->xine->plugin_catalog;
1927   demux_plugin_t   *plugin = NULL;
1928 
1929   methods[0] = method1;
1930   methods[1] = method2;
1931   methods[2] = -1;
1932 
1933   i = 0;
1934   while (methods[i] != -1 && !plugin) {
1935     int list_id, list_size;
1936 
1937     pthread_mutex_lock (&catalog->lock);
1938 
1939     list_size = xine_sarray_size(catalog->plugin_lists[PLUGIN_DEMUX - 1]);
1940     for(list_id = 0; list_id < list_size; list_id++) {
1941       plugin_node_t *node;
1942 
1943       node = xine_sarray_get (catalog->plugin_lists[PLUGIN_DEMUX - 1], list_id);
1944 
1945       xprintf(stream->xine, XINE_VERBOSITY_DEBUG, "load_plugins: probing demux '%s'\n", node->info->id);
1946 
1947       if (node->plugin_class || _load_plugin_class(stream->xine, node, NULL)) {
1948         const char *mime_type;
1949 
1950         /* If detecting by MRL, try the MIME type first (but not text/plain)... */
1951         stream->content_detection_method = METHOD_EXPLICIT;
1952         if (methods[i] == METHOD_BY_MRL &&
1953             stream->input_plugin->get_optional_data &&
1954             stream->input_plugin->get_optional_data (stream->input_plugin, NULL, INPUT_OPTIONAL_DATA_DEMUX_MIME_TYPE) != INPUT_OPTIONAL_UNSUPPORTED &&
1955             stream->input_plugin->get_optional_data (stream->input_plugin, &mime_type, INPUT_OPTIONAL_DATA_MIME_TYPE) != INPUT_OPTIONAL_UNSUPPORTED &&
1956             mime_type && strcasecmp (mime_type, "text/plain") &&
1957             probe_mime_type (stream->xine, node, mime_type) &&
1958             (plugin = ((demux_class_t *)node->plugin_class)->open_plugin (node->plugin_class, stream, input)))
1959         {
1960           inc_node_ref(node);
1961           plugin->node = node;
1962           break;
1963         }
1964 
1965         /* ... then try the extension */
1966         stream->content_detection_method = methods[i];
1967 	if ( stream->content_detection_method == METHOD_BY_MRL &&
1968 	     ! _x_demux_check_extension(input->get_mrl(input),
1969 					 ((demux_class_t *)node->plugin_class)->extensions)
1970 	     )
1971 	  continue;
1972 
1973         if ((plugin = ((demux_class_t *)node->plugin_class)->open_plugin(node->plugin_class, stream, input))) {
1974 	  inc_node_ref(node);
1975 	  plugin->node = node;
1976 	  break;
1977         }
1978       }
1979     }
1980 
1981     pthread_mutex_unlock (&catalog->lock);
1982 
1983     i++;
1984   }
1985 
1986   return plugin;
1987 }
1988 
_x_find_demux_plugin(xine_stream_t * stream,input_plugin_t * input)1989 demux_plugin_t *_x_find_demux_plugin (xine_stream_t *stream, input_plugin_t *input) {
1990 
1991   switch (stream->xine->demux_strategy) {
1992 
1993   default:
1994     xprintf (stream->xine, XINE_VERBOSITY_LOG,
1995              _("load_plugins: unknown content detection strategy %d\n"),
1996              stream->xine->demux_strategy);
1997     /* fall through */
1998   case XINE_DEMUX_DEFAULT_STRATEGY:
1999     return probe_demux (stream, METHOD_BY_CONTENT, METHOD_BY_MRL, input);
2000 
2001   case XINE_DEMUX_REVERT_STRATEGY:
2002     return probe_demux (stream, METHOD_BY_MRL, METHOD_BY_CONTENT, input);
2003 
2004   case XINE_DEMUX_CONTENT_STRATEGY:
2005     return probe_demux (stream, METHOD_BY_CONTENT, -1, input);
2006 
2007   case XINE_DEMUX_EXTENSION_STRATEGY:
2008     return probe_demux (stream, METHOD_BY_MRL, -1, input);
2009   }
2010 
2011   return NULL;
2012 }
2013 
_x_find_demux_plugin_by_name(xine_stream_t * stream,const char * name,input_plugin_t * input)2014 demux_plugin_t *_x_find_demux_plugin_by_name(xine_stream_t *stream, const char *name, input_plugin_t *input) {
2015 
2016   plugin_catalog_t  *catalog = stream->xine->plugin_catalog;
2017   plugin_node_t     *node;
2018   demux_plugin_t    *plugin = NULL;
2019   int                list_id, list_size;
2020 
2021   pthread_mutex_lock(&catalog->lock);
2022 
2023   stream->content_detection_method = METHOD_EXPLICIT;
2024 
2025   list_size = xine_sarray_size(catalog->plugin_lists[PLUGIN_DEMUX - 1]);
2026   for (list_id = 0; list_id < list_size; list_id++) {
2027 
2028     node = xine_sarray_get(catalog->plugin_lists[PLUGIN_DEMUX - 1], list_id);
2029 
2030     if (strcasecmp(node->info->id, name) == 0) {
2031       if (node->plugin_class || _load_plugin_class(stream->xine, node, NULL)) {
2032 #if 0
2033         /* never triggered (method is set to EXPLICIT few lines earlier) */
2034 	if ( stream->content_detection_method == METHOD_BY_MRL &&
2035 	     ! _x_demux_check_extension(input->get_mrl(input),
2036 					 ((demux_class_t *)node->plugin_class)->extensions)
2037 	     )
2038 	  continue;
2039 #endif
2040         if ((plugin = ((demux_class_t *)node->plugin_class)->open_plugin(node->plugin_class, stream, input))) {
2041 	  inc_node_ref(node);
2042 	  plugin->node = node;
2043 	  break;
2044         }
2045       }
2046     }
2047   }
2048 
2049   pthread_mutex_unlock(&catalog->lock);
2050   return plugin;
2051 }
2052 
2053 /*
2054  * this is a special test mode for content detection: all demuxers are probed
2055  * by content and extension except last_demux_name which is tested after
2056  * every other demuxer.
2057  *
2058  * this way we can make sure no demuxer will interfere on probing of a
2059  * known stream.
2060  */
2061 
_x_find_demux_plugin_last_probe(xine_stream_t * stream,const char * last_demux_name,input_plugin_t * input)2062 demux_plugin_t *_x_find_demux_plugin_last_probe(xine_stream_t *stream, const char *last_demux_name, input_plugin_t *input) {
2063 
2064   int               i;
2065   int               methods[3];
2066   xine_t           *xine = stream->xine;
2067   plugin_catalog_t *catalog = xine->plugin_catalog;
2068   plugin_node_t    *last_demux = NULL;
2069   demux_plugin_t   *plugin = NULL;
2070 
2071   methods[0] = METHOD_BY_CONTENT;
2072   methods[1] = METHOD_BY_MRL;
2073   methods[2] = -1;
2074 
2075   i = 0;
2076   while (methods[i] != -1 && !plugin) {
2077     int list_id, list_size;
2078 
2079     stream->content_detection_method = methods[i];
2080 
2081     pthread_mutex_lock (&catalog->lock);
2082 
2083     list_size = xine_sarray_size(catalog->plugin_lists[PLUGIN_DEMUX - 1]);
2084     for (list_id = 0; list_id < list_size; list_id++) {
2085       plugin_node_t *node;
2086 
2087       node = xine_sarray_get (catalog->plugin_lists[PLUGIN_DEMUX - 1], list_id);
2088 
2089       lprintf ("probing demux '%s'\n", node->info->id);
2090 
2091       if (strcasecmp(node->info->id, last_demux_name) == 0) {
2092         last_demux = node;
2093       } else {
2094 	xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2095 		"load_plugin: probing '%s' (method %d)...\n", node->info->id, stream->content_detection_method );
2096 	if (node->plugin_class || _load_plugin_class(xine, node, NULL)) {
2097 
2098 	  if ( stream->content_detection_method == METHOD_BY_MRL &&
2099 	       ! _x_demux_check_extension(input->get_mrl(input),
2100 					   ((demux_class_t *)node->plugin_class)->extensions)
2101 	       )
2102 	    continue;
2103 
2104 
2105           if ((plugin = ((demux_class_t *)node->plugin_class)->open_plugin(node->plugin_class, stream, input))) {
2106 	    xprintf (stream->xine, XINE_VERBOSITY_DEBUG,
2107 		     "load_plugins: using demuxer '%s' (instead of '%s')\n", node->info->id, last_demux_name);
2108 	    inc_node_ref(node);
2109 	    plugin->node = node;
2110 	    break;
2111           }
2112         }
2113       }
2114     }
2115 
2116     pthread_mutex_unlock (&catalog->lock);
2117 
2118     i++;
2119   }
2120 
2121   if( plugin )
2122     return plugin;
2123 
2124   if( !last_demux )
2125     return NULL;
2126 
2127   stream->content_detection_method = METHOD_BY_CONTENT;
2128 
2129   pthread_mutex_lock (&catalog->lock);
2130   if (last_demux->plugin_class || _load_plugin_class(xine, last_demux, NULL)) {
2131 
2132   if ((plugin = ((demux_class_t *)last_demux->plugin_class)->open_plugin(last_demux->plugin_class, stream, input))) {
2133     xprintf (stream->xine, XINE_VERBOSITY_LOG, _("load_plugins: using demuxer '%s'\n"), last_demux_name);
2134     inc_node_ref(last_demux);
2135     plugin->node = last_demux;
2136   }
2137   }
2138   pthread_mutex_unlock (&catalog->lock);
2139 
2140   return plugin;
2141 }
2142 
2143 
_x_free_demux_plugin(xine_stream_t * stream,demux_plugin_t ** pdemux)2144 void _x_free_demux_plugin (xine_stream_t *stream, demux_plugin_t **pdemux) {
2145   demux_plugin_t   *demux = *pdemux;
2146   plugin_catalog_t *catalog = stream->xine->plugin_catalog;
2147   plugin_node_t    *node = demux->node;
2148 
2149   *pdemux = NULL;
2150 
2151   demux->dispose(demux);
2152 
2153   if (node) {
2154     pthread_mutex_lock(&catalog->lock);
2155     dec_node_ref(node);
2156     pthread_mutex_unlock(&catalog->lock);
2157   }
2158 }
2159 
2160 
xine_get_autoplay_input_plugin_ids(xine_t * this)2161 const char *const *xine_get_autoplay_input_plugin_ids(xine_t *this) {
2162   const char **last, **end, *test;
2163   int list_id, list_size;
2164   plugin_catalog_t *catalog = this->plugin_catalog;
2165 
2166   pthread_mutex_lock (&catalog->lock);
2167   end = &catalog->ids[0] + sizeof (catalog->ids) / sizeof (catalog->ids[0]) - 1;
2168   last = &catalog->ids[0];
2169   *last = NULL;
2170   test = NULL;
2171 
2172   list_size = xine_sarray_size (catalog->plugin_lists[PLUGIN_INPUT - 1]);
2173   for (list_id = 0; list_id < list_size; list_id++) {
2174 
2175     plugin_node_t *node = xine_sarray_get (catalog->plugin_lists[PLUGIN_INPUT - 1], list_id);
2176     input_class_t *ic = node->plugin_class;
2177     if (!ic) {
2178       _load_plugin_class (this, node, NULL);
2179       ic = node->plugin_class;
2180     }
2181     if (ic && ic->get_autoplay_list) {
2182       if (!strcasecmp (node->info->id, "TEST")) {
2183         /* dont let TEST push user media devices out of xine-ui 1 click list. */
2184         test = node->info->id;
2185       } else {
2186         const char **here = &catalog->ids[0], **p;
2187         while (*here && strcasecmp (*here, node->info->id) < 0)
2188           here++;
2189         last++;
2190         for (p = last; p > here; p--)
2191           p[0] = p[-1];
2192         *here = node->info->id;
2193       }
2194       if (last >= end)
2195         break;
2196     }
2197 
2198   }
2199 
2200   if (last < end) {
2201     *last++ = test;
2202     *last = NULL;
2203   }
2204 
2205   pthread_mutex_unlock (&catalog->lock);
2206 
2207   return catalog->ids;
2208 }
2209 
xine_get_browsable_input_plugin_ids(xine_t * this)2210 const char *const *xine_get_browsable_input_plugin_ids(xine_t *this) {
2211   const char **last, **end, *test;
2212   int list_id, list_size;
2213   plugin_catalog_t *catalog = this->plugin_catalog;
2214 
2215   pthread_mutex_lock (&catalog->lock);
2216   end = &catalog->ids[0] + sizeof (catalog->ids) / sizeof (catalog->ids[0]) - 1;
2217   last = &catalog->ids[0];
2218   *last = NULL;
2219   test = NULL;
2220 
2221   list_size = xine_sarray_size (catalog->plugin_lists[PLUGIN_INPUT - 1]);
2222   for (list_id = 0; list_id < list_size; list_id++) {
2223 
2224     plugin_node_t *node = xine_sarray_get (catalog->plugin_lists[PLUGIN_INPUT - 1], list_id);
2225     input_class_t *ic = node->plugin_class;
2226     if (!ic) {
2227       _load_plugin_class (this, node, NULL);
2228       ic = node->plugin_class;
2229     }
2230     if (ic && ic->get_dir) {
2231       if (!strcasecmp (node->info->id, "TEST")) {
2232         /* dont let TEST push user media devices out of xine-ui 1 click list. */
2233         test = node->info->id;
2234       } else {
2235         const char **here = &catalog->ids[0], **p;
2236         while (*here && strcasecmp (*here, node->info->id) < 0)
2237           here++;
2238         last++;
2239         for (p = last; p > here; p--)
2240           p[0] = p[-1];
2241         *here = node->info->id;
2242       }
2243       if (last >= end)
2244         break;
2245     }
2246 
2247   }
2248 
2249   if (last < end) {
2250     *last++ = test;
2251     *last = NULL;
2252   }
2253 
2254   pthread_mutex_unlock (&catalog->lock);
2255 
2256   return catalog->ids;
2257 }
2258 
2259 /*
2260  *  video out plugins section
2261  */
2262 
_load_video_driver(xine_t * this,plugin_node_t * node,const void * data)2263 static vo_driver_t *_load_video_driver (xine_t *this, plugin_node_t *node,
2264                                         const void *data) {
2265 
2266   vo_driver_t *driver;
2267 
2268   if (!node->plugin_class && !_load_plugin_class (this, node, data))
2269     return NULL;
2270 
2271   driver = ((video_driver_class_t *)node->plugin_class)->open_plugin(node->plugin_class, data);
2272 
2273   if (driver) {
2274     inc_node_ref(node);
2275     driver->node = node;
2276   }
2277 
2278   return driver;
2279 }
2280 
_x_load_video_output_plugin(xine_t * this,const char * id,int visual_type,const void * visual)2281 vo_driver_t *_x_load_video_output_plugin(xine_t *this,
2282                                          const char *id,
2283                                          int visual_type,
2284                                          const void *visual) {
2285 
2286   plugin_node_t      *node;
2287   vo_driver_t        *driver = NULL;
2288   const vo_info_t    *vo_info;
2289   plugin_catalog_t   *catalog = this->plugin_catalog;
2290   int                 list_id, list_size;
2291 
2292   if (id && !strcasecmp(id, "auto"))
2293     id = NULL;
2294 
2295   pthread_mutex_lock (&catalog->lock);
2296 
2297   list_size = xine_sarray_size (catalog->plugin_lists[PLUGIN_VIDEO_OUT - 1]);
2298   for (list_id = 0; list_id < list_size; list_id++) {
2299 
2300     node = xine_sarray_get (catalog->plugin_lists[PLUGIN_VIDEO_OUT - 1], list_id);
2301 
2302     vo_info = (const vo_info_t *)node->info->special_info;
2303     if (vo_info->visual_type == visual_type) {
2304       if (id) {
2305 	if (!strcasecmp (node->info->id, id)) {
2306 	  driver = _load_video_driver (this, node, visual);
2307 	  break;
2308 	}
2309 
2310       } else {
2311 
2312 	driver = _load_video_driver (this, node, visual);
2313 
2314 	if (driver) {
2315 
2316 	  break;
2317 	}
2318       }
2319     }
2320   }
2321 
2322   pthread_mutex_unlock (&catalog->lock);
2323 
2324   return driver;
2325 }
2326 
xine_open_video_driver(xine_t * this,const char * id,int visual_type,const void * visual)2327 xine_video_port_t *xine_open_video_driver (xine_t *this,
2328 					   const char *id,
2329                                            int visual_type,
2330                                            const void *visual) {
2331 
2332   vo_driver_t        *driver;
2333   xine_video_port_t  *port;
2334 
2335   driver = _x_load_video_output_plugin(this, id, visual_type, visual);
2336 
2337   if (!driver) {
2338     lprintf ("failed to load video output plugin <%s>\n", id);
2339     return NULL;
2340   }
2341 
2342   port = _x_vo_new_port(this, driver, 0);
2343 
2344   return port;
2345 }
2346 
xine_new_framegrab_video_port(xine_t * this)2347 xine_video_port_t *xine_new_framegrab_video_port (xine_t *this) {
2348 
2349   plugin_node_t      *node;
2350   vo_driver_t        *driver;
2351   xine_video_port_t  *port;
2352   plugin_catalog_t   *catalog = this->plugin_catalog;
2353   const char         *id;
2354   int                 list_id, list_size;
2355 
2356   driver = NULL;
2357   id     = "none";
2358 
2359   pthread_mutex_lock (&catalog->lock);
2360 
2361   list_size = xine_sarray_size (catalog->plugin_lists[PLUGIN_VIDEO_OUT - 1]);
2362   for (list_id = 0; list_id < list_size; list_id++) {
2363 
2364     node = xine_sarray_get (catalog->plugin_lists[PLUGIN_VIDEO_OUT - 1], list_id);
2365 
2366     if (!strcasecmp (node->info->id, id)) {
2367       driver = _load_video_driver (this, node, NULL);
2368       break;
2369     }
2370   }
2371 
2372   pthread_mutex_unlock (&catalog->lock);
2373 
2374   if (!driver) {
2375     lprintf ("failed to load video output plugin <%s>\n", id);
2376     return NULL;
2377   }
2378 
2379   port = _x_vo_new_port(this, driver, 1);
2380 
2381   return port;
2382 }
2383 
2384 /*
2385  *  audio output plugins section
2386  */
2387 
xine_list_audio_output_plugins(xine_t * xine)2388 const char *const *xine_list_audio_output_plugins (xine_t *xine) {
2389   return _build_list_typed_plugins (xine, PLUGIN_AUDIO_OUT);
2390 }
2391 
xine_list_video_output_plugins(xine_t * xine)2392 const char *const *xine_list_video_output_plugins (xine_t *xine) {
2393   return _build_list_typed_plugins (xine, PLUGIN_VIDEO_OUT);
2394 }
2395 
xine_list_video_output_plugins_typed(xine_t * xine,uint64_t typemask)2396 const char *const *xine_list_video_output_plugins_typed(xine_t *xine, uint64_t typemask)
2397 {
2398   plugin_catalog_t *catalog = xine->plugin_catalog;
2399   plugin_node_t    *node;
2400   int               list_id, list_size, i;
2401 
2402   pthread_mutex_lock (&catalog->lock);
2403 
2404   list_size = xine_sarray_size (catalog->plugin_lists[PLUGIN_VIDEO_OUT - 1]);
2405 
2406   for (list_id = i = 0; list_id < list_size; list_id++)
2407   {
2408     node = xine_sarray_get (catalog->plugin_lists[PLUGIN_VIDEO_OUT - 1], list_id);
2409     if (typemask & (1ULL << ((const vo_info_t *)node->info->special_info)->visual_type))
2410     {
2411       const char *id = node->info->id;
2412       int j = i;
2413       while (--j >= 0)
2414         if (!strcmp (catalog->ids[j], id))
2415           goto ignore; /* already listed */
2416       catalog->ids[i++] = id;
2417     }
2418     ignore: ;
2419   }
2420   catalog->ids[i] = NULL;
2421 
2422   pthread_mutex_unlock (&catalog->lock);
2423   return catalog->ids;
2424 }
2425 
_load_audio_driver(xine_t * this,plugin_node_t * node,const void * data)2426 static ao_driver_t *_load_audio_driver (xine_t *this, plugin_node_t *node,
2427                                         const void *data) {
2428 
2429   ao_driver_t *driver;
2430 
2431   if (!node->plugin_class && !_load_plugin_class (this, node, data))
2432     return NULL;
2433 
2434   driver = ((audio_driver_class_t *)node->plugin_class)->open_plugin(node->plugin_class, data);
2435 
2436   if (driver) {
2437     inc_node_ref(node);
2438     driver->node = node;
2439   }
2440 
2441   return driver;
2442 }
2443 
_x_load_audio_output_plugin(xine_t * this,const char * id)2444 ao_driver_t *_x_load_audio_output_plugin (xine_t *this, const char *id)
2445 {
2446   plugin_node_t      *node;
2447   ao_driver_t        *driver = NULL;
2448   plugin_catalog_t   *catalog = this->plugin_catalog;
2449   int                 list_id, list_size;
2450 
2451   pthread_mutex_lock (&catalog->lock);
2452 
2453   list_size = xine_sarray_size (this->plugin_catalog->plugin_lists[PLUGIN_AUDIO_OUT - 1]);
2454   for (list_id = 0; list_id < list_size; list_id++) {
2455 
2456     node = xine_sarray_get (this->plugin_catalog->plugin_lists[PLUGIN_AUDIO_OUT - 1], list_id);
2457 
2458     if (!strcasecmp(node->info->id, id)) {
2459       driver = _load_audio_driver (this, node, NULL);
2460       break;
2461     }
2462   }
2463 
2464   pthread_mutex_unlock (&catalog->lock);
2465 
2466   if (!driver) {
2467     xprintf (this, XINE_VERBOSITY_LOG,
2468         _("load_plugins: failed to load audio output plugin <%s>\n"), id);
2469   }
2470   return driver;
2471 }
2472 
xine_open_audio_driver(xine_t * this,const char * id,const void * data)2473 xine_audio_port_t *xine_open_audio_driver (xine_t *this, const char *id,
2474                                            const void *data) {
2475 
2476   plugin_node_t      *node;
2477   ao_driver_t        *driver = NULL;
2478   xine_audio_port_t  *port;
2479   const ao_info_t    *ao_info;
2480   plugin_catalog_t   *catalog = this->plugin_catalog;
2481   int                 list_id, list_size;
2482 
2483   if (id && !strcasecmp(id, "auto") )
2484     id = NULL;
2485 
2486   pthread_mutex_lock (&catalog->lock);
2487 
2488   list_size = xine_sarray_size (this->plugin_catalog->plugin_lists[PLUGIN_AUDIO_OUT - 1]);
2489   for (list_id = 0; list_id < list_size; list_id++) {
2490 
2491     node = xine_sarray_get (this->plugin_catalog->plugin_lists[PLUGIN_AUDIO_OUT - 1], list_id);
2492 
2493     ao_info = (const ao_info_t *)node->info->special_info;
2494 
2495     if (id) {
2496       if (!strcasecmp(node->info->id, id)) {
2497 	driver = _load_audio_driver (this, node, data);
2498 	break;
2499       }
2500     } else if( ao_info->priority >= 0 ) {
2501       driver = _load_audio_driver (this, node, data);
2502       if (driver) {
2503 	break;
2504       }
2505     }
2506   }
2507 
2508   pthread_mutex_unlock (&catalog->lock);
2509 
2510   if (!driver) {
2511     if (id)
2512       xprintf (this, XINE_VERBOSITY_LOG,
2513 	       _("load_plugins: failed to load audio output plugin <%s>\n"), id);
2514     else
2515       xprintf (this, XINE_VERBOSITY_LOG,
2516 	       _("load_plugins: audio output auto-probing didn't find any usable audio driver.\n"));
2517     return NULL;
2518   }
2519 
2520   port = _x_ao_new_port(this, driver, 0);
2521 
2522   return port;
2523 }
2524 
xine_new_framegrab_audio_port(xine_t * this)2525 xine_audio_port_t *xine_new_framegrab_audio_port (xine_t *this) {
2526 
2527   xine_audio_port_t  *port;
2528 
2529   port = _x_ao_new_port (this, NULL, 1);
2530 
2531   return port;
2532 }
2533 
_x_free_audio_driver(xine_t * xine,ao_driver_t ** pdriver)2534 void _x_free_audio_driver (xine_t *xine, ao_driver_t **pdriver) {
2535 
2536   ao_driver_t      *driver = *pdriver;
2537   plugin_catalog_t *catalog = xine->plugin_catalog;
2538   plugin_node_t    *node = driver->node;
2539 
2540   *pdriver = NULL;
2541 
2542   driver->exit(driver);
2543 
2544   if (node) {
2545     pthread_mutex_lock(&catalog->lock);
2546     dec_node_ref(node);
2547     pthread_mutex_unlock(&catalog->lock);
2548   }
2549 }
2550 
_x_free_video_driver(xine_t * xine,vo_driver_t ** pdriver)2551 void _x_free_video_driver (xine_t *xine, vo_driver_t **pdriver) {
2552 
2553   vo_driver_t      *driver = *pdriver;
2554   plugin_catalog_t *catalog = xine->plugin_catalog;
2555   plugin_node_t    *node = driver->node;
2556 
2557   *pdriver = NULL;
2558 
2559   driver->dispose (driver);
2560 
2561   if (node) {
2562     pthread_mutex_lock(&catalog->lock);
2563     dec_node_ref(node);
2564     pthread_mutex_unlock(&catalog->lock);
2565   }
2566 }
2567 
xine_close_audio_driver(xine_t * this,xine_audio_port_t * ao_port)2568 void xine_close_audio_driver (xine_t *this, xine_audio_port_t  *ao_port) {
2569 
2570   (void)this;
2571   if( ao_port )
2572     ao_port->exit(ao_port);
2573 
2574 }
2575 
xine_close_video_driver(xine_t * this,xine_video_port_t * vo_port)2576 void xine_close_video_driver (xine_t *this, xine_video_port_t  *vo_port) {
2577 
2578   (void)this;
2579   if( vo_port )
2580     vo_port->exit(vo_port);
2581 
2582 }
2583 
2584 
2585 /*
2586  * get autoplay mrl list from input plugin
2587  */
2588 
_get_input_class(xine_t * this,const char * plugin_id)2589 static input_class_t *_get_input_class (xine_t *this, const char *plugin_id) {
2590 
2591   plugin_catalog_t     *catalog;
2592   plugin_node_t        *node;
2593   int                   list_id, list_size;
2594 
2595   catalog = this->plugin_catalog;
2596 
2597   list_size = xine_sarray_size (catalog->plugin_lists[PLUGIN_INPUT - 1]);
2598   for (list_id = 0; list_id < list_size; list_id++) {
2599 
2600     node = xine_sarray_get (catalog->plugin_lists[PLUGIN_INPUT - 1], list_id);
2601 
2602     if (!strcasecmp (node->info->id, plugin_id)) {
2603       if (node->plugin_class || _load_plugin_class (this, node, NULL)) {
2604         return node->plugin_class;
2605       }
2606     }
2607   }
2608   return NULL;
2609 }
2610 
xine_get_autoplay_mrls(xine_t * this,const char * plugin_id,int * num_mrls)2611 const char * const *xine_get_autoplay_mrls (xine_t *this, const char *plugin_id,
2612 					    int *num_mrls) {
2613 
2614   plugin_catalog_t     *catalog;
2615   input_class_t        *ic;
2616   const char * const   *mrls = NULL;
2617 
2618   catalog = this->plugin_catalog;
2619 
2620   pthread_mutex_lock (&catalog->lock);
2621 
2622   ic = _get_input_class(this, plugin_id);
2623   if (ic && ic->get_autoplay_list)
2624     mrls = ic->get_autoplay_list (ic, num_mrls);
2625 
2626   pthread_mutex_unlock (&catalog->lock);
2627 
2628   return mrls;
2629 }
2630 
2631 /*
2632  * input plugin mrl browser support
2633  */
2634 
xine_get_browse_mrls(xine_t * this,const char * plugin_id,const char * start_mrl,int * num_mrls)2635 xine_mrl_t **xine_get_browse_mrls (xine_t *this, const char *plugin_id,
2636                                    const char *start_mrl, int *num_mrls) {
2637   plugin_catalog_t   *catalog;
2638   input_class_t      *ic;
2639   xine_mrl_t        **mrls = NULL;
2640 
2641   catalog = this->plugin_catalog;
2642 
2643   pthread_mutex_lock (&catalog->lock);
2644 
2645   ic = _get_input_class (this, plugin_id);
2646   if (ic && ic->get_dir)
2647     mrls = ic->get_dir (ic, start_mrl, num_mrls);
2648 
2649   pthread_mutex_unlock (&catalog->lock);
2650 
2651   return mrls;
2652 }
2653 
_x_get_video_decoder(xine_stream_t * stream,uint8_t stream_type)2654 video_decoder_t *_x_get_video_decoder (xine_stream_t *stream, uint8_t stream_type) {
2655 
2656   plugin_node_t    *node;
2657   int               i, j;
2658   plugin_catalog_t *catalog = stream->xine->plugin_catalog;
2659   video_decoder_t  *vd = NULL;
2660 
2661   lprintf ("looking for video decoder for streamtype %02x\n", stream_type);
2662   _x_assert(stream_type < DECODER_MAX);
2663 
2664   pthread_mutex_lock (&catalog->lock);
2665 
2666   for (i = 0; i < PLUGINS_PER_TYPE; i++) {
2667 
2668     node = catalog->video_decoder_map[stream_type][i];
2669 
2670     if (!node) {
2671       break;
2672     }
2673 
2674     if (!node->plugin_class && !_load_plugin_class (stream->xine, node, NULL)) {
2675       /* remove non working plugin from catalog */
2676       xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2677 	      "load_plugins: plugin %s failed to init its class.\n", node->info->id);
2678       for (j = i + 1; j < PLUGINS_PER_TYPE; j++)
2679         catalog->video_decoder_map[stream_type][j - 1] =
2680           catalog->video_decoder_map[stream_type][j];
2681       catalog->video_decoder_map[stream_type][PLUGINS_PER_TYPE-1] = NULL;
2682       i--;
2683       continue;
2684     }
2685 
2686     vd = ((video_decoder_class_t *)node->plugin_class)->open_plugin(node->plugin_class, stream);
2687 
2688     if (vd == (video_decoder_t*)1) {
2689       /* HACK: plugin failed to instantiate because required resources are unavailable at that time,
2690          but may be available later, so don't remove this plugin from catalog. */
2691       xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2692           "load_plugins: plugin %s failed to instantiate, resources temporarily unavailable.\n", node->info->id);
2693     }
2694     else if (vd) {
2695       inc_node_ref(node);
2696       vd->node = node;
2697       xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2698           "load_plugins: plugin %s will be used for video streamtype %02x.\n",
2699           node->info->id, stream_type);
2700 
2701       break;
2702     } else {
2703       /* remove non working plugin from catalog */
2704       xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2705 	      "load_plugins: plugin %s failed to instantiate itself.\n", node->info->id);
2706       for (j = i + 1; j < PLUGINS_PER_TYPE; j++)
2707         catalog->video_decoder_map[stream_type][j - 1] =
2708           catalog->video_decoder_map[stream_type][j];
2709       catalog->video_decoder_map[stream_type][PLUGINS_PER_TYPE-1] = NULL;
2710       i--;
2711     }
2712   }
2713 
2714   pthread_mutex_unlock (&catalog->lock);
2715   return vd;
2716 }
2717 
_x_free_video_decoder(xine_stream_t * stream,video_decoder_t * vd)2718 void _x_free_video_decoder (xine_stream_t *stream, video_decoder_t *vd) {
2719   plugin_catalog_t *catalog = stream->xine->plugin_catalog;
2720   plugin_node_t    *node = vd->node;
2721 
2722   vd->dispose (vd);
2723 
2724   if (node) {
2725     pthread_mutex_lock (&catalog->lock);
2726     dec_node_ref(node);
2727     pthread_mutex_unlock (&catalog->lock);
2728   }
2729 }
2730 
2731 
_x_get_audio_decoder(xine_stream_t * stream,uint8_t stream_type)2732 audio_decoder_t *_x_get_audio_decoder (xine_stream_t *stream, uint8_t stream_type) {
2733 
2734   plugin_node_t    *node;
2735   int               i, j;
2736   plugin_catalog_t *catalog = stream->xine->plugin_catalog;
2737   audio_decoder_t  *ad = NULL;
2738 
2739   lprintf ("looking for audio decoder for streamtype %02x\n", stream_type);
2740   _x_assert(stream_type < DECODER_MAX);
2741 
2742   pthread_mutex_lock (&catalog->lock);
2743 
2744   for (i = 0; i < PLUGINS_PER_TYPE; i++) {
2745 
2746     node = catalog->audio_decoder_map[stream_type][i];
2747 
2748     if (!node) {
2749       break;
2750     }
2751 
2752     if (!node->plugin_class && !_load_plugin_class (stream->xine, node, NULL)) {
2753       /* remove non working plugin from catalog */
2754       xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2755 	      "load_plugins: plugin %s failed to init its class.\n", node->info->id);
2756       for (j = i + 1; j < PLUGINS_PER_TYPE; j++)
2757         catalog->audio_decoder_map[stream_type][j - 1] =
2758           catalog->audio_decoder_map[stream_type][j];
2759       catalog->audio_decoder_map[stream_type][PLUGINS_PER_TYPE-1] = NULL;
2760       i--;
2761       continue;
2762     }
2763 
2764     ad = ((audio_decoder_class_t *)node->plugin_class)->open_plugin(node->plugin_class, stream);
2765 
2766     if (ad == (audio_decoder_t*)1) {
2767       /* HACK: plugin failed to instantiate because required resources are unavailable at that time,
2768          but may be available later, so don't remove this plugin from catalog. */
2769       xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2770           "load_plugins: plugin %s failed to instantiate, resources temporarily unavailable.\n", node->info->id);
2771     }
2772     else if (ad) {
2773       inc_node_ref(node);
2774       ad->node = node;
2775       xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2776           "load_plugins: plugin %s will be used for audio streamtype %02x.\n",
2777           node->info->id, stream_type);
2778       break;
2779     } else {
2780       /* remove non working plugin from catalog */
2781       xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2782 	      "load_plugins: plugin %s failed to instantiate itself.\n", node->info->id);
2783       for (j = i + 1; j < PLUGINS_PER_TYPE; j++)
2784         catalog->audio_decoder_map[stream_type][j - 1] =
2785           catalog->audio_decoder_map[stream_type][j];
2786       catalog->audio_decoder_map[stream_type][PLUGINS_PER_TYPE-1] = NULL;
2787       i--;
2788     }
2789   }
2790 
2791   pthread_mutex_unlock (&catalog->lock);
2792   return ad;
2793 }
2794 
_x_free_audio_decoder(xine_stream_t * stream,audio_decoder_t * ad)2795 void _x_free_audio_decoder (xine_stream_t *stream, audio_decoder_t *ad) {
2796   plugin_catalog_t *catalog = stream->xine->plugin_catalog;
2797   plugin_node_t    *node = ad->node;
2798 
2799   ad->dispose (ad);
2800 
2801   if (node) {
2802     pthread_mutex_lock (&catalog->lock);
2803     dec_node_ref(node);
2804     pthread_mutex_unlock (&catalog->lock);
2805   }
2806 }
2807 
_x_decoder_available(xine_t * xine,uint32_t buftype)2808 int _x_decoder_available (xine_t *xine, uint32_t buftype)
2809 {
2810   plugin_catalog_t *catalog = xine->plugin_catalog;
2811   int stream_type = (buftype>>16) & 0xFF;
2812 
2813   _x_assert(stream_type < DECODER_MAX);
2814 
2815   if ( (buftype & 0xFF000000) == BUF_VIDEO_BASE ) {
2816     if( catalog->video_decoder_map[stream_type][0] )
2817       return 1;
2818   } else
2819   if ( (buftype & 0xFF000000) == BUF_AUDIO_BASE ) {
2820     if( catalog->audio_decoder_map[stream_type][0] )
2821       return 1;
2822   } else
2823   if ( (buftype & 0xFF000000) == BUF_SPU_BASE ) {
2824     if( catalog->spu_decoder_map[stream_type][0] )
2825       return 1;
2826   }
2827 
2828   return 0;
2829 }
2830 
2831 #ifdef LOG
_display_file_plugin_list(xine_list_t * list,plugin_file_t * file)2832 static void _display_file_plugin_list (xine_list_t *list, plugin_file_t *file) {
2833   xine_list_iterator_t ite = NULL;
2834   plugin_node_t *node;
2835   while ((node = xine_list_next_value (list, &ite))) {
2836     if ((node->file == file) && (node->ref)) {
2837       printf("    plugin: %s, class: %p , %d instance(s)\n",
2838 	     node->info->id, node->plugin_class, node->ref);
2839     }
2840   }
2841 }
2842 #endif
2843 
_unload_unref_plugin(xine_t * xine,plugin_node_t * node)2844 static void _unload_unref_plugin(xine_t *xine, plugin_node_t *node) {
2845   if (node->ref == 0) {
2846     plugin_file_t *file = node->file;
2847 
2848     /* no plugin of this class is instancied */
2849     _dispose_plugin_class(node);
2850 
2851     /* check file references */
2852     if (file && !file->ref && file->lib_handle && !file->no_unload) {
2853       /* unload this file */
2854       lprintf("unloading plugin %s\n", file->filename);
2855       if (dlclose(file->lib_handle)) {
2856         const char *error = dlerror();
2857 
2858         xine_log (xine, XINE_LOG_PLUGIN,
2859                   _("load_plugins: cannot unload plugin lib %s:\n%s\n"), file->filename, error);
2860       }
2861       file->lib_handle = NULL;
2862     }
2863   }
2864 }
2865 
_unload_unref_plugins(xine_t * xine,xine_sarray_t * list)2866 static void _unload_unref_plugins(xine_t *xine, xine_sarray_t *list) {
2867 
2868   plugin_node_t *node;
2869   int            list_id, list_size;
2870 
2871   list_size = xine_sarray_size (list);
2872   for (list_id = 0; list_id < list_size; list_id++) {
2873 
2874     node = xine_sarray_get (list, list_id);
2875 
2876     _unload_unref_plugin(xine, node);
2877   }
2878 }
2879 
xine_plugins_garbage_collector(xine_t * self)2880 void xine_plugins_garbage_collector(xine_t *self) {
2881   plugin_catalog_t *catalog = self->plugin_catalog;
2882   int i;
2883 
2884   pthread_mutex_lock (&catalog->lock);
2885   for(i = 0; i < PLUGIN_TYPE_MAX; i++) {
2886     _unload_unref_plugins(self, self->plugin_catalog->plugin_lists[i]);
2887   }
2888 
2889 #if 0
2890   {
2891     plugin_file_t *file;
2892 
2893     printf("\nPlugin summary after garbage collection : \n");
2894     file = xine_list_first_content(self->plugin_catalog->file);
2895     while (file) {
2896       if (file->ref) {
2897 	printf("\n  file %s referenced %d time(s)\n", file->filename, file->ref);
2898 
2899 	for(i = 0; i < PLUGIN_TYPE_MAX; i++) {
2900 	  _display_file_plugin_list (self->plugin_catalog->plugin_lists[i], file)
2901 	}
2902       }
2903       file = xine_list_next_content(self->plugin_catalog->file);
2904     }
2905     printf("End of plugin summary\n\n");
2906   }
2907 #endif
2908 
2909   pthread_mutex_unlock (&catalog->lock);
2910 }
2911 
_x_get_spu_decoder(xine_stream_t * stream,uint8_t stream_type)2912 spu_decoder_t *_x_get_spu_decoder (xine_stream_t *stream, uint8_t stream_type) {
2913 
2914   plugin_node_t    *node;
2915   int               i, j;
2916   plugin_catalog_t *catalog = stream->xine->plugin_catalog;
2917   spu_decoder_t    *sd = NULL;
2918 
2919   lprintf ("looking for spu decoder for streamtype %02x\n", stream_type);
2920   _x_assert(stream_type < DECODER_MAX);
2921 
2922   pthread_mutex_lock (&catalog->lock);
2923 
2924   for (i = 0; i < PLUGINS_PER_TYPE; i++) {
2925 
2926     node = catalog->spu_decoder_map[stream_type][i];
2927 
2928     if (!node) {
2929       break;
2930     }
2931 
2932     if (!node->plugin_class && !_load_plugin_class (stream->xine, node, NULL)) {
2933       /* remove non working plugin from catalog */
2934       xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2935 	      "load_plugins: plugin %s failed to init its class.\n", node->info->id);
2936       for (j = i + 1; j < PLUGINS_PER_TYPE; j++)
2937         catalog->spu_decoder_map[stream_type][j - 1] =
2938           catalog->spu_decoder_map[stream_type][j];
2939       catalog->spu_decoder_map[stream_type][PLUGINS_PER_TYPE-1] = NULL;
2940       i--;
2941       continue;
2942     }
2943 
2944     sd = ((spu_decoder_class_t *)node->plugin_class)->open_plugin(node->plugin_class, stream);
2945 
2946     if (sd) {
2947       inc_node_ref(node);
2948       sd->node = node;
2949       xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2950           "load_plugins: plugin %s will be used for spu streamtype %02x.\n",
2951           node->info->id, stream_type);
2952       break;
2953     } else {
2954       /* remove non working plugin from catalog */
2955       xprintf(stream->xine, XINE_VERBOSITY_DEBUG,
2956 	      "load_plugins: plugin %s failed to instantiate itself.\n", node->info->id);
2957       for (j = i + 1; j < PLUGINS_PER_TYPE; j++)
2958         catalog->spu_decoder_map[stream_type][j - 1] =
2959           catalog->spu_decoder_map[stream_type][j];
2960       catalog->spu_decoder_map[stream_type][PLUGINS_PER_TYPE-1] = NULL;
2961       i--;
2962     }
2963   }
2964 
2965   pthread_mutex_unlock (&catalog->lock);
2966   return sd;
2967 }
2968 
_x_free_spu_decoder(xine_stream_t * stream,spu_decoder_t * sd)2969 void _x_free_spu_decoder (xine_stream_t *stream, spu_decoder_t *sd) {
2970   plugin_catalog_t *catalog = stream->xine->plugin_catalog;
2971   plugin_node_t    *node = sd->node;
2972 
2973   sd->dispose (sd);
2974 
2975   if (node) {
2976     pthread_mutex_lock (&catalog->lock);
2977     dec_node_ref(node);
2978     pthread_mutex_unlock (&catalog->lock);
2979   }
2980 }
2981 
xine_list_demuxer_plugins(xine_t * xine)2982 const char *const *xine_list_demuxer_plugins(xine_t *xine) {
2983   return _build_list_typed_plugins (xine, PLUGIN_DEMUX);
2984 }
2985 
xine_list_input_plugins(xine_t * xine)2986 const char *const *xine_list_input_plugins(xine_t *xine) {
2987   return _build_list_typed_plugins (xine, PLUGIN_INPUT);
2988 }
2989 
xine_list_spu_plugins(xine_t * xine)2990 const char *const *xine_list_spu_plugins(xine_t *xine) {
2991   return _build_list_typed_plugins (xine, PLUGIN_SPU_DECODER);
2992 }
2993 
xine_list_audio_decoder_plugins(xine_t * xine)2994 const char *const *xine_list_audio_decoder_plugins(xine_t *xine) {
2995   return _build_list_typed_plugins (xine, PLUGIN_AUDIO_DECODER);
2996 }
2997 
xine_list_video_decoder_plugins(xine_t * xine)2998 const char *const *xine_list_video_decoder_plugins(xine_t *xine) {
2999   return _build_list_typed_plugins (xine, PLUGIN_VIDEO_DECODER);
3000 }
3001 
xine_list_post_plugins(xine_t * xine)3002 const char *const *xine_list_post_plugins(xine_t *xine) {
3003   return _build_list_typed_plugins (xine, PLUGIN_POST);
3004 }
3005 
xine_list_post_plugins_typed(xine_t * xine,uint32_t type)3006 const char *const *xine_list_post_plugins_typed(xine_t *xine, uint32_t type) {
3007   plugin_catalog_t *catalog = xine->plugin_catalog;
3008   plugin_node_t    *node;
3009   int               i;
3010   int               list_id, list_size;
3011 
3012   pthread_mutex_lock (&catalog->lock);
3013 
3014   i = 0;
3015   list_size = xine_sarray_size (catalog->plugin_lists[PLUGIN_POST - 1]);
3016 
3017   for (list_id = 0; list_id < list_size; list_id++) {
3018     node = xine_sarray_get (catalog->plugin_lists[PLUGIN_POST - 1], list_id);
3019     if (((const post_info_t *)node->info->special_info)->type == type)
3020       catalog->ids[i++] = node->info->id;
3021   }
3022   catalog->ids[i] = NULL;
3023 
3024   pthread_mutex_unlock (&catalog->lock);
3025   return catalog->ids;
3026 }
3027 
3028 #define GET_PLUGIN_DESC(NAME,TYPE,CATITEM) \
3029   const char *xine_get_##NAME##_plugin_description (xine_t *this, const char *plugin_id) { \
3030     plugin_catalog_t *catalog = this->plugin_catalog;					   \
3031     plugin_node_t    *node;                                                                \
3032     int               list_id, list_size;                                                  \
3033     pthread_mutex_lock (&catalog->lock);                                                   \
3034     list_size = xine_sarray_size (catalog->plugin_lists[CATITEM - 1]);                     \
3035     for (list_id = 0; list_id < list_size; list_id++) {                                    \
3036       node = xine_sarray_get (catalog->plugin_lists[CATITEM - 1], list_id);                \
3037       if (!strcasecmp (node->info->id, plugin_id)) {					   \
3038 	TYPE##_class_t *ic = (TYPE##_class_t *) node->plugin_class;			   \
3039         const char *ret = NULL;                                                            \
3040 	if (!ic) {									   \
3041 	  if (_load_plugin_class (this, node, NULL))					   \
3042 	    ic = node->plugin_class;							   \
3043 	}										   \
3044         if (ic)                                                                            \
3045           ret = dgettext(ic->text_domain ? ic->text_domain : XINE_TEXTDOMAIN, ic->description); \
3046         pthread_mutex_unlock (&catalog->lock);                                             \
3047         return ret;                                                                        \
3048       }                                                                                    \
3049     }                                                                                      \
3050     pthread_mutex_unlock (&catalog->lock);                                                 \
3051     return NULL;									   \
3052   }
3053 
GET_PLUGIN_DESC(input,input,PLUGIN_INPUT)3054 GET_PLUGIN_DESC (input,		input,		PLUGIN_INPUT)
3055 GET_PLUGIN_DESC (demux,		demux,		PLUGIN_DEMUX)
3056 GET_PLUGIN_DESC (spu,		spu_decoder,	PLUGIN_SPU_DECODER)
3057 GET_PLUGIN_DESC (audio,		audio_decoder,	PLUGIN_AUDIO_DECODER)
3058 GET_PLUGIN_DESC (video,		video_decoder,	PLUGIN_VIDEO_DECODER)
3059 GET_PLUGIN_DESC (audio_driver,	audio_driver,	PLUGIN_AUDIO_OUT)
3060 GET_PLUGIN_DESC (video_driver,	video_driver,	PLUGIN_VIDEO_OUT)
3061 GET_PLUGIN_DESC (post,		post,		PLUGIN_POST)
3062 
3063 xine_post_t *xine_post_init (xine_t *xine_gen, const char *name, int inputs,
3064 			    xine_audio_port_t **audio_target,
3065 			    xine_video_port_t **video_target) {
3066   xine_private_t *xine = (xine_private_t *)xine_gen;
3067   plugin_catalog_t *catalog = xine->x.plugin_catalog;
3068   plugin_node_t    *node;
3069   post_plugin_t    *post = NULL;
3070   int               list_id, list_size;
3071 
3072   if( !name )
3073     return NULL;
3074 
3075   pthread_mutex_lock(&catalog->lock);
3076 
3077   list_size = xine_sarray_size (catalog->plugin_lists[PLUGIN_POST - 1]);
3078 
3079   for (list_id = 0; list_id < list_size; list_id++) {
3080     node = xine_sarray_get (catalog->plugin_lists[PLUGIN_POST - 1], list_id);
3081 
3082     if (strcmp(node->info->id, name) == 0) {
3083 
3084       if (!node->plugin_class && !_load_plugin_class (&xine->x, node, NULL)) {
3085         xprintf (&xine->x, XINE_VERBOSITY_DEBUG,
3086 		"load_plugins: requested post plugin %s failed to load\n", name);
3087 	break;
3088       }
3089 
3090       post = ((post_class_t *)node->plugin_class)->open_plugin(node->plugin_class,
3091         inputs, audio_target, video_target);
3092 
3093       if (post) {
3094 	post->running_ticket = xine->port_ticket;
3095         post->xine = &xine->x;
3096 	post->node = node;
3097 	inc_node_ref(node);
3098 
3099 	/* init the lists of announced connections */
3100         post->input_ids = malloc (sizeof (char *) * (xine_list_size (post->input) + 1));
3101         if (post->input_ids) {
3102           int i = 0;
3103           xine_list_iterator_t ite = NULL;
3104           xine_post_in_t *input;
3105           while ((input = xine_list_next_value (post->input, &ite)))
3106             post->input_ids[i++] = input->name;
3107           post->input_ids[i] = NULL;
3108         }
3109         post->output_ids = malloc (sizeof (char *) * (xine_list_size (post->output) + 1));
3110         if (post->output_ids) {
3111           int i = 0;
3112           xine_list_iterator_t ite = NULL;
3113           xine_post_out_t *output;
3114           while ((output = xine_list_next_value (post->output, &ite)))
3115             post->output_ids[i++] = output->name;
3116           post->output_ids[i] = NULL;
3117         }
3118 	/* copy the post plugin type to the public part */
3119 	post->xine_post.type = ((const post_info_t *)node->info->special_info)->type;
3120 
3121 	break;
3122       } else {
3123         xprintf (&xine->x, XINE_VERBOSITY_DEBUG,
3124 		"load_plugins: post plugin %s failed to instantiate itself\n", name);
3125 	break;
3126       }
3127     }
3128   }
3129 
3130   pthread_mutex_unlock(&catalog->lock);
3131 
3132   if(post)
3133     return &post->xine_post;
3134   else {
3135     xprintf (&xine->x, XINE_VERBOSITY_DEBUG, "load_plugins: no post plugin named %s found\n", name);
3136     return NULL;
3137   }
3138 }
3139 
xine_post_dispose(xine_t * xine,xine_post_t * post_gen)3140 void xine_post_dispose(xine_t *xine, xine_post_t *post_gen) {
3141   post_plugin_t *post = (post_plugin_t *)post_gen;
3142   (void)xine;
3143   post->dispose(post);
3144   /* we cannot decrement the reference counter, since post plugins can delay
3145    * their disposal if they are still in use => post.c handles the counting for us */
3146 }
3147 
_get_demux_strings(xine_t * self,int kind)3148 static char *_get_demux_strings (xine_t *self, int kind) {
3149   plugin_catalog_t *catalog = self->plugin_catalog;
3150   struct {
3151     const char *s;
3152     size_t len;
3153   } *slist = NULL, *slitem, *slend;
3154   char *res = NULL;
3155 
3156   pthread_mutex_lock (&catalog->lock);
3157   do {
3158     {
3159       int num, list_id;
3160       size_t size;
3161 
3162       num = xine_sarray_size (catalog->plugin_lists[PLUGIN_DEMUX - 1]);
3163       if (num <= 0)
3164         break;
3165       slist = malloc (num * sizeof (*slist));
3166       if (!slist)
3167         break;
3168 
3169       slitem = slist;
3170       size = 0;
3171       for (list_id = 0; list_id < num; list_id++) {
3172         plugin_node_t *const node = xine_sarray_get (catalog->plugin_lists[PLUGIN_DEMUX - 1], list_id);
3173         if (!node->plugin_class)
3174           _load_plugin_class (self, node, NULL);
3175         if (node->plugin_class) {
3176           demux_class_t *const cls = (demux_class_t *)node->plugin_class;
3177           const char *s = kind ? cls->extensions : cls->mimetypes;
3178           if (s) {
3179             slitem->s = s;
3180             size += (slitem->len = strlen (s));
3181             slitem++;
3182           }
3183         }
3184       }
3185       slend = slitem;
3186       if (slend == slist)
3187         break;
3188       res = malloc (size + (slend - slist) * (kind ? 1 : 0) + 1);
3189       if (!res)
3190         break;
3191     }
3192 
3193     {
3194       char *q = res;
3195       slitem = slist;
3196       if (kind) {
3197         do {
3198           xine_small_memcpy (q, slitem->s, slitem->len);
3199           q += slitem->len;
3200           *q++ = ' ';
3201           slitem++;
3202         } while (slitem < slend);
3203         q[-1] = 0;
3204       } else {
3205         do {
3206           xine_small_memcpy (q, slitem->s, slitem->len);
3207           q += slitem->len;
3208           slitem++;
3209         } while (slitem < slend);
3210         q[0] = 0;
3211       }
3212     }
3213   } while (0);
3214   pthread_mutex_unlock (&catalog->lock);
3215   free (slist);
3216   return res;
3217 }
3218 
3219 /* get a list of file extensions for file types supported by xine
3220  * the list is separated by spaces
3221  *
3222  * the pointer returned can be free()ed when no longer used */
xine_get_file_extensions(xine_t * self)3223 char *xine_get_file_extensions (xine_t *self) {
3224   return _get_demux_strings (self, 1);
3225 }
3226 
3227 /* get a list of mime types supported by xine
3228  *
3229  * the pointer returned can be free()ed when no longer used */
xine_get_mime_types(xine_t * self)3230 char *xine_get_mime_types (xine_t *self) {
3231   return _get_demux_strings (self, 0);
3232 }
3233 
3234 
3235 /* get the demuxer identifier that handles a given mime type
3236  *
3237  * the pointer returned can be free()ed when no longer used
3238  * returns NULL if no demuxer is available to handle this. */
xine_get_demux_for_mime_type(xine_t * self,const char * mime_type)3239 char *xine_get_demux_for_mime_type (xine_t *self, const char *mime_type) {
3240 
3241   plugin_catalog_t *catalog = self->plugin_catalog;
3242   plugin_node_t    *node;
3243   char             *id = NULL;
3244   int               list_id, list_size;
3245 
3246   pthread_mutex_lock (&catalog->lock);
3247 
3248   list_size = xine_sarray_size (catalog->plugin_lists[PLUGIN_DEMUX - 1]);
3249 
3250   for (list_id = 0; (list_id < list_size) && !id; list_id++) {
3251 
3252     node = xine_sarray_get (catalog->plugin_lists[PLUGIN_DEMUX - 1], list_id);
3253     if (probe_mime_type (self, node, mime_type))
3254       id = strdup(node->info->id);
3255   }
3256 
3257   pthread_mutex_unlock (&catalog->lock);
3258 
3259   return id;
3260 }
3261 
dispose_plugin_list(xine_sarray_t * list,int is_cache)3262 static int dispose_plugin_list (xine_sarray_t *list, int is_cache) {
3263 
3264   decoder_info_t *decoder_info;
3265   int             list_id, list_size;
3266   int             num = 0;
3267 
3268   if (!list)
3269     return 0;
3270 
3271   list_size = xine_sarray_size (list);
3272   for (list_id = 0; list_id < list_size; list_id++) {
3273 
3274     fat_node_t *node, *nextnode;
3275     for (node = xine_sarray_get (list, list_id); node; node = nextnode) {
3276 
3277       nextnode = is_cache && (node->node.file == &node->file) ? node->nextplugin : NULL;
3278 
3279       if (node->node.ref == 0)
3280         _dispose_plugin_class (&node->node);
3281       else {
3282         lprintf ("node \"%s\" still referenced %d time(s)\n", node->node.info->id, node->node.ref);
3283 	continue;
3284       }
3285 
3286       /* free special info */
3287       switch (node->info->type & PLUGIN_TYPE_MASK) {
3288       case PLUGIN_SPU_DECODER:
3289       case PLUGIN_AUDIO_DECODER:
3290       case PLUGIN_VIDEO_DECODER:
3291 	decoder_info = (decoder_info_t *)node->node.info->special_info;
3292         if (!(IS_FAT_NODE (node) && (decoder_info->supported_types == &node->supported_types[0])))
3293           _x_freep (&decoder_info->supported_types);
3294         /* fall thru */
3295       default:
3296         if (!(IS_FAT_NODE (node) && node->node.info->special_info  == &node->ainfo))
3297           _x_freep (&node->node.info->special_info);
3298 	break;
3299       }
3300 
3301       /* free info structure and string copies */
3302       if (!IS_FAT_NODE (node)) {
3303         _x_freep (&node->node.info->id);
3304         _x_freep (&node->node.info);
3305       }
3306 #ifdef FAST_SCAN_PLUGINS
3307       if (node->node.config_entry_list) {
3308         xine_list_delete (node->node.config_entry_list);
3309         node->node.config_entry_list = NULL;
3310       }
3311 #else
3312       _free_string_list (&node->node.config_entry_list);
3313 #endif
3314       /* file entries in cache list are "dummies" (do not refer to opened files) */
3315       /* those are not in file list, so free here */
3316       if (is_cache && node->node.file) {
3317         _x_assert (node->node.file->lib_handle == NULL);
3318         _x_assert (node->node.file->ref == 0);
3319         if (node->node.file != &node->file) {
3320           _x_freep (&node->node.file->filename);
3321           _x_freep (&node->node.file);
3322         }
3323       }
3324       free (node);
3325       num++;
3326     }
3327   }
3328   xine_sarray_delete (list);
3329   return num;
3330 }
3331 
3332 
dispose_plugin_file_list(xine_list_t * list)3333 static void dispose_plugin_file_list (xine_list_t *list) {
3334   plugin_file_t        *file;
3335   xine_list_iterator_t  ite = NULL;
3336 
3337   while ((file = xine_list_next_value (list, &ite))) {
3338     if ((char *)file + sizeof (*file) != file->filename) {
3339       _x_freep (&file->filename);
3340     }
3341     free (file);
3342   }
3343   xine_list_delete (list);
3344 }
3345 
3346 
3347 /*
3348  * dispose all currently loaded plugins (shutdown)
3349  */
3350 
_x_dispose_plugins(xine_t * this)3351 void _x_dispose_plugins (xine_t *this) {
3352 
3353   if(this->plugin_catalog) {
3354     int i;
3355 
3356     if (this->config) {
3357       i = this->config->unregister_callbacks (this->config, NULL, _decoder_priority_cb, NULL, 0);
3358       if (i)
3359         xprintf (this, XINE_VERBOSITY_DEBUG,
3360           "load_plugins: unregistered %d decoder priority callbacks.\n", i);
3361     }
3362 
3363     for (i = 0; i < PLUGIN_TYPE_MAX; i++) {
3364       dispose_plugin_list (this->plugin_catalog->plugin_lists[i], 0);
3365     }
3366     dispose_plugin_list (this->plugin_catalog->modules_list, 0);
3367 
3368     i = dispose_plugin_list (this->plugin_catalog->cache_list, 1);
3369     if (i)
3370       xprintf (this, XINE_VERBOSITY_DEBUG,
3371         "load_plugins: dropped %d outdated cache entries.\n", i);
3372     dispose_plugin_file_list (this->plugin_catalog->file_list);
3373 
3374     for (i = 0; this->plugin_catalog->prio_desc[i]; i++)
3375       _x_freep(&this->plugin_catalog->prio_desc[i]);
3376 
3377     pthread_mutex_destroy(&this->plugin_catalog->lock);
3378 
3379     _x_freep (&this->plugin_catalog);
3380   }
3381 }
3382 
3383