Coverage Report

Created: 2026-05-30 08:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/src/modules/modules.c
Line
Count
Source
1
/*****************************************************************************
2
 * modules.c : Builtin and plugin modules management functions
3
 *****************************************************************************
4
 * Copyright (C) 2001-2011 VLC authors and VideoLAN
5
 *
6
 * Authors: Sam Hocevar <sam@zoy.org>
7
 *          Ethan C. Baldridge <BaldridgeE@cadmus.com>
8
 *          Hans-Peter Jansen <hpj@urpla.net>
9
 *          Gildas Bazin <gbazin@videolan.org>
10
 *          Rémi Denis-Courmont
11
 *
12
 * This program is free software; you can redistribute it and/or modify it
13
 * under the terms of the GNU Lesser General Public License as published by
14
 * the Free Software Foundation; either version 2.1 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
 * GNU Lesser General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Lesser General Public License
23
 * along with this program; if not, write to the Free Software Foundation,
24
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25
 *****************************************************************************/
26
27
#ifdef HAVE_CONFIG_H
28
# include "config.h"
29
#endif
30
31
#include <stdlib.h>
32
#include <string.h>
33
#ifdef ENABLE_NLS
34
# include <libintl.h>
35
#endif
36
#include <assert.h>
37
38
#include <vlc_common.h>
39
#include <vlc_modules.h>
40
#include "../libvlc.h"
41
#include "config/configuration.h"
42
#include "vlc_arrays.h"
43
#include "modules/modules.h"
44
45
bool module_provides (const module_t *m, const char *cap)
46
0
{
47
0
    return !strcmp (module_get_capability (m), cap);
48
0
}
49
50
const char *module_get_object( const module_t *m )
51
15.6M
{
52
15.6M
    if (unlikely(m->i_shortcuts == 0))
53
0
        return "unnamed";
54
15.6M
    return m->pp_shortcuts[0];
55
15.6M
}
56
57
const char *module_get_name( const module_t *m, bool long_name )
58
0
{
59
0
    if( long_name && ( m->psz_longname != NULL) )
60
0
        return m->psz_longname;
61
62
0
    if (m->psz_shortname != NULL)
63
0
        return m->psz_shortname;
64
0
    return module_get_object (m);
65
0
}
66
67
const char *module_get_help( const module_t *m )
68
0
{
69
0
    return m->psz_help;
70
0
}
71
72
const char *module_get_help_html( const module_t *m )
73
0
{
74
0
    return m->psz_help_html;
75
0
}
76
77
const char *module_get_capability (const module_t *m)
78
5.21M
{
79
5.21M
    return (m->psz_capability != NULL) ? m->psz_capability : "none";
80
5.21M
}
81
82
int module_get_score( const module_t *m )
83
61.3M
{
84
61.3M
    return m->i_score;
85
61.3M
}
86
87
const char *module_gettext (const module_t *m, const char *str)
88
0
{
89
0
    if (unlikely(str == NULL || *str == '\0'))
90
0
        return "";
91
#ifdef ENABLE_NLS
92
    const char *domain = m->plugin->textdomain;
93
    return dgettext ((domain != NULL) ? domain : PACKAGE_NAME, str);
94
#else
95
0
    (void)m;
96
0
    return str;
97
0
#endif
98
0
}
99
100
static bool module_match_name(const module_t *m, const char *name, size_t len)
101
4.13M
{
102
16.2M
     for (size_t i = 0; i < m->i_shortcuts; i++)
103
12.1M
          if (strncasecmp(m->pp_shortcuts[i], name, len) == 0
104
127k
           && m->pp_shortcuts[i][len] == '\0')
105
126k
              return true;
106
107
4.01M
     return false;
108
4.13M
}
109
110
ssize_t vlc_module_match(const char *capability, const char *names,
111
                         bool strict, module_t ***restrict modules,
112
                         size_t *restrict strict_matches)
113
5.31M
{
114
5.31M
    module_t *const *tab;
115
5.31M
    size_t total = module_list_cap(&tab, capability);
116
5.31M
    module_t **unsorted = malloc(total * sizeof (*unsorted));
117
5.31M
    module_t **sorted = malloc(total * sizeof (*sorted));
118
5.31M
    size_t matches = 0;
119
120
5.31M
    if (total > 0) {
121
5.31M
        if (unlikely(unsorted == NULL || sorted == NULL)) {
122
0
            free(unsorted);
123
0
            free(sorted);
124
0
            *modules = NULL;
125
0
            return -1;
126
0
        }
127
5.31M
        memcpy(unsorted, tab, total * sizeof (*unsorted));
128
5.31M
    }
129
130
5.31M
    *modules = sorted;
131
132
    /* Go through the list of module shortcut names. */
133
5.31M
    if (names != NULL) {
134
5.41M
        while (names[0] != '\0') {
135
5.31M
            const char *shortcut = names;
136
5.31M
            size_t slen = strcspn(names, ",");
137
138
5.31M
            names += slen;
139
5.31M
            names += strspn(names, ",");
140
141
            /* "none" matches nothing and ends the search */
142
5.31M
            if (slen == 4 && strncasecmp("none", shortcut, 4) == 0) {
143
75
                total = 0;
144
75
                break;
145
75
            }
146
147
            /* "any" matches everything with strictly positive score */
148
5.31M
            if (slen == 3 && strncasecmp("any", shortcut, 3) == 0) {
149
5.21M
                strict = false;
150
5.21M
                break;
151
5.21M
            }
152
153
4.23M
            for (size_t i = 0; i < total; i++) {
154
4.13M
                module_t *cand = unsorted[i];
155
156
4.13M
                if (cand != NULL && module_match_name(cand, shortcut, slen)) {
157
126k
                    assert(matches < total);
158
126k
                    sorted[matches++] = cand;
159
126k
                    unsorted[i] = NULL;
160
126k
                }
161
4.13M
            }
162
99.0k
        }
163
5.31M
    }
164
165
5.31M
    if (strict_matches != NULL)
166
5.31M
        *strict_matches = matches;
167
168
5.31M
    if (!strict) {
169
        /* List remaining modules with strictly positive score. */
170
66.5M
        for (size_t i = 0; i < total; i++) {
171
61.3M
            module_t *cand = unsorted[i];
172
173
61.3M
            if (cand != NULL) {
174
                /* Modules are sorted by decreasing score, so there is no point
175
                 * carrying on after the first zero score is found.
176
                 */
177
61.3M
                if (module_get_score(cand) <= 0)
178
2.97k
                    break;
179
180
61.3M
                assert(matches < total);
181
61.3M
                sorted[matches++] = cand;
182
61.3M
            }
183
61.3M
        }
184
5.21M
    }
185
186
5.31M
    free(unsorted);
187
5.31M
    return matches;
188
5.31M
}
189
190
void *vlc_module_map(vlc_logger_t *log, module_t *module)
191
41.3M
{
192
41.3M
    return vlc_plugin_Map(log, module->plugin) ? NULL : module->pf_activate;
193
41.3M
}
194
195
module_t *(vlc_module_load)(struct vlc_logger *log, const char *capability,
196
                            const char *name, bool strict,
197
                            vlc_activate_t probe, ...)
198
5.31M
{
199
5.31M
    if (name == NULL || name[0] == '\0')
200
5.20M
        name = "any";
201
202
    /* Find matching modules */
203
5.31M
    module_t **mods;
204
5.31M
    size_t strict_total;
205
5.31M
    ssize_t total = vlc_module_match(capability, name, strict,
206
5.31M
                                     &mods, &strict_total);
207
208
5.31M
    if (unlikely(total < 0))
209
0
        return NULL;
210
211
5.31M
    vlc_debug(log, "looking for %s module matching \"%s\": %zd candidates",
212
5.31M
              capability, name, total);
213
214
5.31M
    module_t *module = NULL;
215
5.31M
    va_list args;
216
217
5.31M
    va_start(args, probe);
218
219
41.4M
    for (size_t i = 0; i < (size_t)total; i++) {
220
41.3M
        module_t *cand = mods[i];
221
41.3M
        int ret = VLC_EGENERIC;
222
41.3M
        void *cb = vlc_module_map(log, cand);
223
224
41.3M
        if (cb == NULL)
225
0
            continue;
226
227
41.3M
        va_list ap;
228
229
41.3M
        va_copy(ap, args);
230
41.3M
        ret = probe(cb, i < strict_total, ap);
231
41.3M
        va_end(ap);
232
233
41.3M
        switch (ret) {
234
5.20M
            case VLC_SUCCESS:
235
5.20M
                vlc_debug(log, "using %s module \"%s\"", capability,
236
5.20M
                          module_get_object(cand));
237
5.20M
                module = cand;
238
                /* fall through */
239
5.20M
            case VLC_ETIMEOUT:
240
5.20M
                goto done;
241
41.3M
        }
242
41.3M
    }
243
244
5.31M
done:
245
5.31M
    va_end (args);
246
247
5.31M
    if (module == NULL)
248
5.31M
        vlc_debug(log, "no %s modules matched with name %s", capability, name);
249
250
5.31M
    free(mods);
251
5.31M
    return module;
252
5.31M
}
253
254
static int generic_start(void *func, bool forced, va_list ap)
255
41.2M
{
256
41.2M
    vlc_object_t *obj = va_arg(ap, vlc_object_t *);
257
41.2M
    int (*activate)(vlc_object_t *) = func;
258
41.2M
    int ret;
259
260
41.2M
    obj->force = forced;
261
41.2M
    ret = activate(obj);
262
41.2M
    if (ret != VLC_SUCCESS)
263
36.0M
        vlc_objres_clear(obj);
264
41.2M
    return ret;
265
41.2M
}
266
267
#undef module_need
268
module_t *module_need(vlc_object_t *obj, const char *cap, const char *name,
269
                      bool strict)
270
5.21M
{
271
5.21M
    const bool b_force_backup = obj->force; /* FIXME: remove this */
272
5.21M
    module_t *module = vlc_module_load(obj->logger, cap, name, strict,
273
5.21M
                                       generic_start, obj);
274
5.21M
    if (module != NULL) {
275
5.12M
        var_Create(obj, "module-name", VLC_VAR_STRING);
276
5.12M
        var_SetString(obj, "module-name", module_get_object(module));
277
5.12M
    }
278
279
5.21M
    obj->force = b_force_backup;
280
5.21M
    return module;
281
5.21M
}
282
283
#undef module_unneed
284
void module_unneed(vlc_object_t *obj, module_t *module)
285
5.20M
{
286
5.20M
    msg_Dbg(obj, "removing \"%s\" module \"%s\"", module_get_capability(module),
287
5.20M
            module_get_object(module));
288
5.20M
    var_Destroy(obj, "module-name");
289
290
5.20M
    if (module->deactivate != NULL)
291
3.54M
        module->deactivate(obj);
292
293
5.20M
    vlc_objres_clear(obj);
294
5.20M
}
295
296
module_t *module_find (const char *name)
297
0
{
298
0
    size_t count;
299
0
    module_t **list = module_list_get (&count);
300
301
0
    assert (name != NULL);
302
303
0
    for (size_t i = 0; i < count; i++)
304
0
    {
305
0
        module_t *module = list[i];
306
307
0
        if (unlikely(module->i_shortcuts == 0))
308
0
            continue;
309
0
        if (!strcmp (module->pp_shortcuts[0], name))
310
0
        {
311
0
            module_list_free (list);
312
0
            return module;
313
0
        }
314
0
    }
315
0
    module_list_free (list);
316
0
    return NULL;
317
0
}
318
319
module_config_t *module_config_get( const module_t *module, unsigned *restrict psize )
320
0
{
321
0
    const vlc_plugin_t *plugin = module->plugin;
322
323
0
    assert( psize != NULL );
324
0
    *psize = 0;
325
326
0
    if (plugin->module != module)
327
0
    {   /* For backward compatibility, pretend non-first modules have no
328
         * configuration items. */
329
0
        return NULL;
330
0
    }
331
332
0
    size_t size = plugin->conf.size;
333
0
    module_config_t *config = vlc_alloc( size, sizeof( *config ) );
334
335
0
    if( !config )
336
0
        return NULL;
337
338
0
    unsigned i, j;
339
0
    for( i = 0, j = 0; i < size; i++ )
340
0
    {
341
0
        const struct vlc_param *param = plugin->conf.params + i;
342
0
        const module_config_t *item = &param->item;
343
344
0
        if (param->internal /* internal option */
345
0
         || param->obsolete /* removed option */)
346
0
            continue;
347
348
0
        memcpy( config + j, item, sizeof( *config ) );
349
0
        j++;
350
0
    }
351
0
    *psize = j;
352
353
0
    return config;
354
0
}
355
356
void module_config_free( module_config_t *config )
357
0
{
358
0
    free( config );
359
0
}