/src/vlc/src/modules/entry.c
Line | Count | Source (jump to first uncovered line) |
1 | | /***************************************************************************** |
2 | | * entry.c : Callbacks for module entry point |
3 | | ***************************************************************************** |
4 | | * Copyright (C) 2007 VLC authors and VideoLAN |
5 | | * Copyright © 2007-2008 Rémi Denis-Courmont |
6 | | * |
7 | | * This program is free software; you can redistribute it and/or modify it |
8 | | * under the terms of the GNU Lesser General Public License as published by |
9 | | * the Free Software Foundation; either version 2.1 of the License, or |
10 | | * (at your option) any later version. |
11 | | * |
12 | | * This program is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public License |
18 | | * along with this program; if not, write to the Free Software Foundation, |
19 | | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
20 | | *****************************************************************************/ |
21 | | |
22 | | #ifdef HAVE_CONFIG_H |
23 | | # include "config.h" |
24 | | #endif |
25 | | |
26 | | #include <stdatomic.h> |
27 | | #include <vlc_common.h> |
28 | | #include <vlc_arrays.h> |
29 | | #include <vlc_plugin.h> |
30 | | #include <assert.h> |
31 | | #include <stdarg.h> |
32 | | #include <limits.h> |
33 | | #include <float.h> |
34 | | #ifdef HAVE_SEARCH_H |
35 | | # include <search.h> |
36 | | #endif |
37 | | |
38 | | #include "modules/modules.h" |
39 | | #include "config/configuration.h" |
40 | | #include "../libvlc.h" |
41 | | |
42 | | module_t *vlc_module_create(vlc_plugin_t *plugin) |
43 | 4.68k | { |
44 | 4.68k | module_t *module = malloc (sizeof (*module)); |
45 | 4.68k | if (module == NULL) |
46 | 0 | return NULL; |
47 | | |
48 | | /* NOTE XXX: For backward compatibility with preferences UIs, the first |
49 | | * module must stay first. That defines under which module, the |
50 | | * configuration items of the plugin belong. The order of the following |
51 | | * entries is irrelevant. */ |
52 | 4.68k | module_t *parent = plugin->module; |
53 | 4.68k | if (parent == NULL) |
54 | 3.27k | { |
55 | 3.27k | module->next = NULL; |
56 | 3.27k | plugin->module = module; |
57 | 3.27k | } |
58 | 1.40k | else |
59 | 1.40k | { |
60 | 1.40k | module->next = parent->next; |
61 | 1.40k | parent->next = module; |
62 | 1.40k | } |
63 | | |
64 | 4.68k | plugin->modules_count++; |
65 | 4.68k | module->plugin = plugin; |
66 | | |
67 | 4.68k | module->psz_shortname = NULL; |
68 | 4.68k | module->psz_longname = NULL; |
69 | 4.68k | module->psz_help = NULL; |
70 | 4.68k | module->psz_help_html = NULL; |
71 | 4.68k | module->pp_shortcuts = NULL; |
72 | 4.68k | module->i_shortcuts = 0; |
73 | 4.68k | module->psz_capability = NULL; |
74 | 4.68k | module->i_score = (parent != NULL) ? parent->i_score : 1; |
75 | 4.68k | module->activate_name = NULL; |
76 | 4.68k | module->deactivate_name = NULL; |
77 | 4.68k | module->pf_activate = NULL; |
78 | 4.68k | module->deactivate = NULL; |
79 | 4.68k | return module; |
80 | 4.68k | } |
81 | | |
82 | | /** |
83 | | * Destroys a module. |
84 | | */ |
85 | | void vlc_module_destroy (module_t *module) |
86 | 0 | { |
87 | 0 | while (module != NULL) |
88 | 0 | { |
89 | 0 | module_t *next = module->next; |
90 | |
|
91 | 0 | free(module->pp_shortcuts); |
92 | 0 | free(module); |
93 | 0 | module = next; |
94 | 0 | } |
95 | 0 | } |
96 | | |
97 | | vlc_plugin_t *vlc_plugin_create(void) |
98 | 3.27k | { |
99 | 3.27k | vlc_plugin_t *plugin = malloc(sizeof (*plugin)); |
100 | 3.27k | if (unlikely(plugin == NULL)) |
101 | 0 | return NULL; |
102 | | |
103 | 3.27k | plugin->modules_count = 0; |
104 | 3.27k | plugin->textdomain = NULL; |
105 | 3.27k | plugin->conf.params = NULL; |
106 | 3.27k | plugin->conf.size = 0; |
107 | 3.27k | plugin->conf.count = 0; |
108 | 3.27k | plugin->conf.booleans = 0; |
109 | | #ifdef HAVE_DYNAMIC_PLUGINS |
110 | | plugin->unloadable = true; |
111 | | atomic_init(&plugin->handle, 0); |
112 | | plugin->abspath = NULL; |
113 | | plugin->path = NULL; |
114 | | #endif |
115 | 3.27k | plugin->module = NULL; |
116 | | |
117 | 3.27k | return plugin; |
118 | 3.27k | } |
119 | | |
120 | | /** |
121 | | * Destroys a plug-in. |
122 | | * @warning If the plug-in was dynamically loaded in memory, the library handle |
123 | | * and associated memory mappings and linker resources will be leaked. |
124 | | */ |
125 | | void vlc_plugin_destroy(vlc_plugin_t *plugin) |
126 | 0 | { |
127 | 0 | assert(plugin != NULL); |
128 | | #ifdef HAVE_DYNAMIC_PLUGINS |
129 | | assert(!plugin->unloadable || atomic_load(&plugin->handle) == 0); |
130 | | #endif |
131 | | |
132 | 0 | if (plugin->module != NULL) |
133 | 0 | vlc_module_destroy(plugin->module); |
134 | |
|
135 | 0 | config_Free(plugin->conf.params, plugin->conf.size); |
136 | | #ifdef HAVE_DYNAMIC_PLUGINS |
137 | | free(plugin->abspath); |
138 | | free(plugin->path); |
139 | | #endif |
140 | 0 | free(plugin); |
141 | 0 | } |
142 | | |
143 | | static struct vlc_param *vlc_config_create(vlc_plugin_t *plugin, int type) |
144 | 33.3k | { |
145 | 33.3k | unsigned confsize = plugin->conf.size; |
146 | 33.3k | struct vlc_param *tab = plugin->conf.params; |
147 | | |
148 | 33.3k | if ((confsize & 0xf) == 0) |
149 | 4.83k | { |
150 | 4.83k | tab = realloc_or_free (tab, (confsize + 17) * sizeof (*tab)); |
151 | 4.83k | if (tab == NULL) |
152 | 0 | return NULL; |
153 | | |
154 | 4.83k | plugin->conf.params = tab; |
155 | 4.83k | } |
156 | | |
157 | 33.3k | memset (tab + confsize, 0, sizeof (tab[confsize])); |
158 | | |
159 | 33.3k | struct vlc_param *param = tab + confsize; |
160 | 33.3k | struct module_config_t *item = ¶m->item; |
161 | | |
162 | 33.3k | param->owner = plugin; |
163 | | |
164 | 33.3k | if (IsConfigIntegerType (type)) |
165 | 8.52k | { |
166 | 8.52k | item->max.i = INT64_MAX; |
167 | 8.52k | item->min.i = INT64_MIN; |
168 | 8.52k | } |
169 | 24.8k | else if( IsConfigFloatType (type)) |
170 | 832 | { |
171 | 832 | item->max.f = FLT_MAX; |
172 | 832 | item->min.f = -FLT_MAX; |
173 | 832 | } |
174 | 24.0k | else |
175 | 24.0k | atomic_init(¶m->value.str, NULL); |
176 | 33.3k | item->i_type = type; |
177 | | |
178 | 33.3k | if (CONFIG_ITEM(type)) |
179 | 26.5k | { |
180 | 26.5k | plugin->conf.count++; |
181 | 26.5k | if (type == CONFIG_ITEM_BOOL) |
182 | 4.68k | plugin->conf.booleans++; |
183 | 26.5k | } |
184 | 33.3k | plugin->conf.size++; |
185 | | |
186 | 33.3k | return param; |
187 | 33.3k | } |
188 | | |
189 | | /** |
190 | | * Plug-in descriptor callback. |
191 | | * |
192 | | * This callback populates modules, configuration items and properties of a |
193 | | * plug-in from the plug-in descriptor. |
194 | | */ |
195 | | static int vlc_plugin_desc_cb(void *ctx, void *tgt, int propid, ...) |
196 | 160k | { |
197 | 160k | vlc_plugin_t *plugin = ctx; |
198 | 160k | module_t *module = tgt; |
199 | 160k | va_list ap; |
200 | 160k | int ret = 0; |
201 | | |
202 | 160k | va_start (ap, propid); |
203 | 160k | switch (propid) |
204 | 160k | { |
205 | 4.68k | case VLC_MODULE_CREATE: |
206 | 4.68k | { |
207 | 4.68k | module_t *super = plugin->module; |
208 | 4.68k | module_t *submodule = vlc_module_create(plugin); |
209 | 4.68k | if (unlikely(submodule == NULL)) |
210 | 0 | { |
211 | 0 | ret = -1; |
212 | 0 | break; |
213 | 0 | } |
214 | | |
215 | 4.68k | *(va_arg (ap, module_t **)) = submodule; |
216 | 4.68k | if (super == NULL) |
217 | 3.27k | break; |
218 | | |
219 | | /* Inheritance. Ugly!! */ |
220 | 1.40k | submodule->pp_shortcuts = xmalloc (sizeof ( *submodule->pp_shortcuts )); |
221 | 1.40k | submodule->pp_shortcuts[0] = super->pp_shortcuts[0]; |
222 | 1.40k | submodule->i_shortcuts = 1; /* object name */ |
223 | | |
224 | 1.40k | submodule->psz_shortname = super->psz_shortname; |
225 | 1.40k | submodule->psz_longname = super->psz_longname; |
226 | 1.40k | submodule->psz_capability = super->psz_capability; |
227 | 1.40k | break; |
228 | 4.68k | } |
229 | | |
230 | 33.3k | case VLC_CONFIG_CREATE: |
231 | 33.3k | { |
232 | 33.3k | int type = va_arg (ap, int); |
233 | 33.3k | struct vlc_param *param = vlc_config_create(plugin, type); |
234 | | |
235 | 33.3k | *va_arg(ap, struct vlc_param **)= param; |
236 | 33.3k | if (unlikely(param == NULL)) |
237 | 0 | ret = -1; |
238 | 33.3k | break; |
239 | 4.68k | } |
240 | | |
241 | 3.17k | case VLC_MODULE_SHORTCUT: |
242 | 3.17k | { |
243 | 3.17k | unsigned i_shortcuts = va_arg (ap, unsigned); |
244 | 3.17k | unsigned index = module->i_shortcuts; |
245 | | /* The cache loader accept only a small number of shortcuts */ |
246 | 3.17k | assert(i_shortcuts + index <= MODULE_SHORTCUT_MAX); |
247 | | |
248 | 3.17k | const char *const *tab = va_arg (ap, const char *const *); |
249 | 3.17k | const char **pp = realloc (module->pp_shortcuts, |
250 | 3.17k | sizeof (pp[0]) * (index + i_shortcuts)); |
251 | 3.17k | if (unlikely(pp == NULL)) |
252 | 0 | { |
253 | 0 | ret = -1; |
254 | 0 | break; |
255 | 0 | } |
256 | 3.17k | module->pp_shortcuts = pp; |
257 | 3.17k | module->i_shortcuts = index + i_shortcuts; |
258 | 3.17k | pp += index; |
259 | 7.38k | for (unsigned i = 0; i < i_shortcuts; i++) |
260 | 4.21k | pp[i] = tab[i]; |
261 | 3.17k | break; |
262 | 3.17k | } |
263 | | |
264 | 4.62k | case VLC_MODULE_CAPABILITY: |
265 | 4.62k | module->psz_capability = va_arg (ap, const char *); |
266 | 4.62k | break; |
267 | | |
268 | 4.62k | case VLC_MODULE_SCORE: |
269 | 4.62k | module->i_score = va_arg (ap, int); |
270 | 4.62k | break; |
271 | | |
272 | 4.62k | case VLC_MODULE_CB_OPEN: |
273 | 4.62k | module->activate_name = va_arg(ap, const char *); |
274 | 4.62k | module->pf_activate = va_arg (ap, void *); |
275 | 4.62k | break; |
276 | | |
277 | 3.38k | case VLC_MODULE_CB_CLOSE: |
278 | 3.38k | module->deactivate_name = va_arg(ap, const char *); |
279 | 3.38k | module->deactivate = va_arg(ap, vlc_deactivate_cb); |
280 | 3.38k | break; |
281 | | |
282 | 0 | case VLC_MODULE_NO_UNLOAD: |
283 | | #ifdef HAVE_DYNAMIC_PLUGINS |
284 | | plugin->unloadable = false; |
285 | | #endif |
286 | 0 | break; |
287 | | |
288 | 3.27k | case VLC_MODULE_NAME: |
289 | 3.27k | { |
290 | 3.27k | const char *value = va_arg (ap, const char *); |
291 | | |
292 | 3.27k | assert (module->i_shortcuts == 0); |
293 | 3.27k | module->pp_shortcuts = malloc( sizeof( *module->pp_shortcuts ) ); |
294 | 3.27k | module->pp_shortcuts[0] = value; |
295 | 3.27k | module->i_shortcuts = 1; |
296 | | |
297 | 3.27k | assert (module->psz_longname == NULL); |
298 | 3.27k | module->psz_longname = value; |
299 | 3.27k | break; |
300 | 3.27k | } |
301 | | |
302 | 1.82k | case VLC_MODULE_SHORTNAME: |
303 | 1.82k | module->psz_shortname = va_arg (ap, const char *); |
304 | 1.82k | break; |
305 | | |
306 | 4.36k | case VLC_MODULE_DESCRIPTION: |
307 | | // TODO: do not set this in VLC_MODULE_NAME |
308 | 4.36k | module->psz_longname = va_arg (ap, const char *); |
309 | 4.36k | break; |
310 | | |
311 | 0 | case VLC_MODULE_HELP: |
312 | 0 | module->psz_help = va_arg (ap, const char *); |
313 | 0 | break; |
314 | | |
315 | 0 | case VLC_MODULE_HELP_HTML: |
316 | 0 | module->psz_help_html = va_arg (ap, const char *); |
317 | 0 | break; |
318 | | |
319 | 0 | case VLC_MODULE_TEXTDOMAIN: |
320 | 0 | plugin->textdomain = va_arg(ap, const char *); |
321 | 0 | break; |
322 | | |
323 | 26.5k | case VLC_CONFIG_NAME: |
324 | 26.5k | { |
325 | 26.5k | struct vlc_param *param = tgt; |
326 | 26.5k | const char *name = va_arg (ap, const char *); |
327 | | |
328 | 26.5k | assert (name != NULL); |
329 | 26.5k | param->item.psz_name = name; |
330 | 26.5k | break; |
331 | 26.5k | } |
332 | | |
333 | 28.1k | case VLC_CONFIG_VALUE: |
334 | 28.1k | { |
335 | 28.1k | struct vlc_param *param = tgt; |
336 | 28.1k | module_config_t *item = ¶m->item; |
337 | | |
338 | 28.1k | if (IsConfigIntegerType(item->i_type) |
339 | 28.1k | || !CONFIG_ITEM(item->i_type)) |
340 | 10.7k | { |
341 | 10.7k | item->orig.i = va_arg(ap, int64_t); |
342 | 10.7k | item->value.i = item->orig.i; |
343 | 10.7k | atomic_store_explicit(¶m->value.i, item->orig.i, |
344 | 10.7k | memory_order_relaxed); |
345 | 10.7k | } |
346 | 17.4k | else |
347 | 17.4k | if (IsConfigFloatType (item->i_type)) |
348 | 780 | { |
349 | 780 | item->orig.f = va_arg(ap, double); |
350 | 780 | item->value.f = item->orig.f; |
351 | 780 | atomic_store_explicit(¶m->value.f, item->orig.f, |
352 | 780 | memory_order_relaxed); |
353 | 780 | } |
354 | 16.6k | else |
355 | 16.6k | if (IsConfigStringType (item->i_type)) |
356 | 16.6k | { |
357 | 16.6k | const char *value = va_arg (ap, const char *); |
358 | 16.6k | item->orig.psz = (char *)value; |
359 | 16.6k | vlc_param_SetString(param, value); |
360 | 16.6k | } |
361 | 28.1k | break; |
362 | 26.5k | } |
363 | | |
364 | 936 | case VLC_CONFIG_RANGE: |
365 | 936 | { |
366 | 936 | struct vlc_param *param = tgt; |
367 | 936 | module_config_t *item = ¶m->item; |
368 | | |
369 | 936 | if (IsConfigFloatType (item->i_type)) |
370 | 104 | { |
371 | 104 | item->min.f = va_arg (ap, double); |
372 | 104 | item->max.f = va_arg (ap, double); |
373 | 104 | } |
374 | 832 | else |
375 | 832 | { |
376 | 832 | item->min.i = va_arg (ap, int64_t); |
377 | 832 | item->max.i = va_arg (ap, int64_t); |
378 | 832 | } |
379 | 936 | break; |
380 | 26.5k | } |
381 | | |
382 | 780 | case VLC_CONFIG_VOLATILE: |
383 | 780 | { |
384 | 780 | struct vlc_param *param = tgt; |
385 | | |
386 | 780 | param->unsaved = true; |
387 | 780 | break; |
388 | 26.5k | } |
389 | | |
390 | 832 | case VLC_CONFIG_PRIVATE: |
391 | 832 | { |
392 | 832 | struct vlc_param *param = tgt; |
393 | | |
394 | 832 | param->internal = true; |
395 | 832 | break; |
396 | 26.5k | } |
397 | | |
398 | 1.19k | case VLC_CONFIG_REMOVED: |
399 | 1.19k | { |
400 | 1.19k | struct vlc_param *param = tgt; |
401 | | |
402 | 1.19k | param->obsolete = true; |
403 | 1.19k | break; |
404 | 26.5k | } |
405 | | |
406 | 728 | case VLC_CONFIG_CAPABILITY: |
407 | 728 | { |
408 | 728 | struct vlc_param *param = tgt; |
409 | | |
410 | 728 | param->item.psz_type = va_arg(ap, const char *); |
411 | 728 | break; |
412 | 26.5k | } |
413 | | |
414 | 780 | case VLC_CONFIG_SHORTCUT: |
415 | 780 | { |
416 | 780 | struct vlc_param *param = tgt; |
417 | | |
418 | 780 | char c = va_arg(ap, int); |
419 | 780 | assert(c != '\0' && c != '?' && c != ':'); |
420 | 780 | param->shortname = c; |
421 | 780 | break; |
422 | 780 | } |
423 | | |
424 | 3.38k | case VLC_CONFIG_SAFE: |
425 | 3.38k | { |
426 | 3.38k | struct vlc_param *param = tgt; |
427 | | |
428 | 3.38k | param->safe = true; |
429 | 3.38k | break; |
430 | 780 | } |
431 | | |
432 | 27.3k | case VLC_CONFIG_DESC: |
433 | 27.3k | { |
434 | 27.3k | struct vlc_param *param = tgt; |
435 | | |
436 | 27.3k | param->item.psz_text = va_arg(ap, const char *); |
437 | 27.3k | param->item.psz_longtext = va_arg(ap, const char *); |
438 | 27.3k | break; |
439 | 780 | } |
440 | | |
441 | 1.40k | case VLC_CONFIG_LIST: |
442 | 1.40k | { |
443 | 1.40k | struct vlc_param *param = tgt; |
444 | 1.40k | module_config_t *item = ¶m->item; |
445 | 1.40k | size_t len = va_arg (ap, size_t); |
446 | | |
447 | 1.40k | assert (item->list_count == 0); /* cannot replace choices */ |
448 | 1.40k | if (len == 0) |
449 | 0 | break; /* nothing to do */ |
450 | | /* Copy values */ |
451 | 1.40k | if (IsConfigIntegerType (item->i_type)) |
452 | 988 | item->list.i = va_arg(ap, const int *); |
453 | 416 | else |
454 | 416 | if (IsConfigStringType (item->i_type)) |
455 | 416 | { |
456 | 416 | const char *const *src = va_arg (ap, const char *const *); |
457 | 416 | const char **dst = xmalloc (sizeof (const char *) * len); |
458 | | |
459 | 416 | memcpy(dst, src, sizeof (const char *) * len); |
460 | 416 | item->list.psz = dst; |
461 | 416 | } |
462 | 0 | else |
463 | 0 | break; |
464 | | |
465 | | /* Copy textual descriptions */ |
466 | | /* XXX: item->list_text[len + 1] is probably useless. */ |
467 | 1.40k | const char *const *text = va_arg (ap, const char *const *); |
468 | 1.40k | const char **dtext = xmalloc (sizeof (const char *) * (len + 1)); |
469 | | |
470 | 1.40k | memcpy(dtext, text, sizeof (const char *) * len); |
471 | 1.40k | item->list_text = dtext; |
472 | 1.40k | item->list_count = len; |
473 | 1.40k | break; |
474 | 1.40k | } |
475 | | |
476 | 0 | default: |
477 | 0 | fprintf (stderr, "LibVLC: unknown module property %d\n", propid); |
478 | 0 | fprintf (stderr, "LibVLC: too old to use this module?\n"); |
479 | 0 | ret = -1; |
480 | 0 | break; |
481 | 160k | } |
482 | | |
483 | 160k | va_end (ap); |
484 | 160k | return ret; |
485 | 160k | } |
486 | | |
487 | | /** |
488 | | * Runs a plug-in descriptor. |
489 | | * |
490 | | * This loads the plug-in meta-data in memory. |
491 | | */ |
492 | | vlc_plugin_t *vlc_plugin_describe(vlc_plugin_cb entry) |
493 | 3.27k | { |
494 | 3.27k | vlc_plugin_t *plugin = vlc_plugin_create(); |
495 | 3.27k | if (unlikely(plugin == NULL)) |
496 | 0 | return NULL; |
497 | | |
498 | 3.27k | if (entry(vlc_plugin_desc_cb, plugin) != 0) |
499 | 0 | { |
500 | 0 | vlc_plugin_destroy(plugin); /* partially initialized plug-in... */ |
501 | 0 | plugin = NULL; |
502 | 0 | } |
503 | 3.27k | return plugin; |
504 | 3.27k | } |
505 | | |
506 | | struct vlc_plugin_symbol |
507 | | { |
508 | | const char *name; |
509 | | void *addr; |
510 | | }; |
511 | | |
512 | | static int vlc_plugin_symbol_compare(const void *a, const void *b) |
513 | 0 | { |
514 | 0 | const struct vlc_plugin_symbol *sa = a , *sb = b; |
515 | |
|
516 | 0 | return strcmp(sa->name, sb->name); |
517 | 0 | } |
518 | | |
519 | | /** |
520 | | * Plug-in symbols callback. |
521 | | * |
522 | | * This callback generates a mapping of plugin symbol names to symbol |
523 | | * addresses. |
524 | | */ |
525 | | static int vlc_plugin_gpa_cb(void *ctx, void *tgt, int propid, ...) |
526 | 0 | { |
527 | 0 | void **rootp = ctx; |
528 | 0 | const char *name; |
529 | 0 | void *addr; |
530 | |
|
531 | 0 | (void) tgt; |
532 | |
|
533 | 0 | switch (propid) |
534 | 0 | { |
535 | 0 | case VLC_MODULE_CB_OPEN: |
536 | 0 | { |
537 | 0 | va_list ap; |
538 | |
|
539 | 0 | va_start(ap, propid); |
540 | 0 | name = va_arg(ap, const char *); |
541 | 0 | addr = va_arg(ap, void *); |
542 | 0 | va_end (ap); |
543 | 0 | break; |
544 | 0 | } |
545 | 0 | case VLC_MODULE_CB_CLOSE: |
546 | 0 | { |
547 | 0 | va_list ap; |
548 | |
|
549 | 0 | va_start(ap, propid); |
550 | 0 | name = va_arg(ap, const char *); |
551 | 0 | addr = va_arg(ap, vlc_deactivate_cb); |
552 | 0 | va_end(ap); |
553 | 0 | break; |
554 | 0 | } |
555 | 0 | default: |
556 | 0 | return 0; |
557 | 0 | } |
558 | | |
559 | 0 | struct vlc_plugin_symbol *sym = malloc(sizeof (*sym)); |
560 | |
|
561 | 0 | sym->name = name; |
562 | 0 | sym->addr = addr; |
563 | |
|
564 | 0 | void **symp = tsearch(sym, rootp, vlc_plugin_symbol_compare); |
565 | 0 | if (unlikely(symp == NULL)) |
566 | 0 | { /* Memory error */ |
567 | 0 | free(sym); |
568 | 0 | return -1; |
569 | 0 | } |
570 | | |
571 | 0 | if (*symp != sym) |
572 | 0 | { /* Duplicate symbol */ |
573 | 0 | #ifndef NDEBUG |
574 | 0 | const struct vlc_plugin_symbol *oldsym = *symp; |
575 | 0 | assert(oldsym->addr == sym->addr); |
576 | 0 | #endif |
577 | 0 | free(sym); |
578 | 0 | } |
579 | 0 | return 0; |
580 | 0 | } |
581 | | |
582 | | /** |
583 | | * Gets the symbols of a plugin. |
584 | | * |
585 | | * This function generates a list of symbol names and addresses for a given |
586 | | * plugin descriptor. The result can be used with vlc_plugin_get_symbol() |
587 | | * to resolve a symbol name to an address. |
588 | | * |
589 | | * The result must be freed with vlc_plugin_free_symbols(). The result is only |
590 | | * meaningful until the plugin is unloaded. |
591 | | */ |
592 | | static void *vlc_plugin_get_symbols(vlc_plugin_cb entry) |
593 | 0 | { |
594 | 0 | void *root = NULL; |
595 | |
|
596 | 0 | if (entry(vlc_plugin_gpa_cb, &root)) |
597 | 0 | { |
598 | 0 | tdestroy(root, free); |
599 | 0 | return NULL; |
600 | 0 | } |
601 | | |
602 | 0 | return root; |
603 | 0 | } |
604 | | |
605 | | static void vlc_plugin_free_symbols(void *root) |
606 | 0 | { |
607 | 0 | tdestroy(root, free); |
608 | 0 | } |
609 | | |
610 | | static int vlc_plugin_get_symbol(void *root, const char *name, |
611 | | void **restrict addrp) |
612 | 0 | { |
613 | 0 | if (name == NULL) |
614 | 0 | { |
615 | 0 | *addrp = NULL; |
616 | 0 | return 0; |
617 | 0 | } |
618 | | |
619 | 0 | const void **symp = tfind(&name, &root, vlc_plugin_symbol_compare); |
620 | |
|
621 | 0 | if (symp == NULL) |
622 | 0 | return -1; |
623 | | |
624 | 0 | const struct vlc_plugin_symbol *sym = *symp; |
625 | |
|
626 | 0 | *addrp = sym->addr; |
627 | 0 | return 0; |
628 | 0 | } |
629 | | |
630 | | int vlc_plugin_resolve(vlc_plugin_t *plugin, vlc_plugin_cb entry) |
631 | 0 | { |
632 | 0 | void *syms = vlc_plugin_get_symbols(entry); |
633 | 0 | int ret = 0; |
634 | | |
635 | | /* Resolve modules activate/deactivate callbacks */ |
636 | 0 | for (module_t *module = plugin->module; |
637 | 0 | module != NULL; |
638 | 0 | module = module->next) |
639 | 0 | { |
640 | 0 | void *deactivate; |
641 | |
|
642 | 0 | if (vlc_plugin_get_symbol(syms, module->activate_name, |
643 | 0 | &module->pf_activate) |
644 | 0 | || vlc_plugin_get_symbol(syms, module->deactivate_name, &deactivate)) |
645 | 0 | { |
646 | 0 | ret = -1; |
647 | 0 | break; |
648 | 0 | } |
649 | | |
650 | 0 | module->deactivate = deactivate; |
651 | 0 | } |
652 | |
|
653 | 0 | vlc_plugin_free_symbols(syms); |
654 | 0 | return ret; |
655 | 0 | } |