/****************************************************************************** Copyright (C) 2013 by Hugh Bailey This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ******************************************************************************/ #include "util/platform.h" #include "util/dstr.h" #include "obs-defs.h" #include "obs-data.h" #include "obs-module.h" void *load_module_subfunc(void *module, const char *module_name, const char *name, const char *func, bool required) { struct dstr func_name; void *func_addr = NULL; dstr_init_copy(&func_name, name); dstr_cat(&func_name, "_"); dstr_cat(&func_name, func); func_addr = os_dlsym(module, func_name.array); if (required && !func_addr) blog(LOG_ERROR, "Could not load function '%s' from module '%s'", func_name.array, module_name); dstr_free(&func_name); return func_addr; } static void module_load_exports(struct obs_module *mod, struct darray *output_array, const char *type, const size_t data_size, void *callback_ptr) { bool (*enum_func)(size_t idx, const char **name); bool (*callback)(void*, const char*, const char*, void*); struct dstr enum_name; const char *name; size_t i = 0; callback = callback_ptr; dstr_init_copy(&enum_name, "enum_"); dstr_cat(&enum_name, type); enum_func = os_dlsym(mod->module, enum_name.array); if (!enum_func) goto complete; while (enum_func(i++, &name)) { void *info = bmalloc(data_size); if (!callback(mod->module, mod->name, name, info)) blog(LOG_ERROR, "Couldn't load '%s' because it " "was missing required functions", name); else darray_push_back(data_size, output_array, info); bfree(info); } complete: dstr_free(&enum_name); } extern char *find_plugin(const char *plugin); /* checks API version of module and calls module_load if it exists. * if the API version used by the module is incompatible, fails. */ static int call_module_load(void *module, const char *path) { uint32_t (*module_version)(uint32_t obs_ver) = NULL; bool (*module_load)(void) = NULL; uint32_t version, major, minor; module_load = os_dlsym(module, "module_load"); module_version = os_dlsym(module, "module_version"); if (!module_version) { blog(LOG_WARNING, "Module '%s' failed to load: " "module_version not found.", path); return MODULE_FUNCTIONNOTFOUND; } version = module_version(LIBOBS_API_VER); major = (version >> 16); minor = (version & 0xFF); if (major != LIBOBS_API_MAJOR_VER) { blog(LOG_WARNING, "Module '%s' failed to load: " "incompatible major version " "(current API: %u.%u, module version: %u.%u)", path, LIBOBS_API_MAJOR_VER, LIBOBS_API_MINOR_VER, major, minor); return MODULE_INCOMPATIBLE_VER; } if (minor > LIBOBS_API_MINOR_VER) { blog(LOG_WARNING, "Module '%s' failed to load: " "incompatible minor version " "(current API: %u.%u, module version: %u.%u)", path, LIBOBS_API_MAJOR_VER, LIBOBS_API_MINOR_VER, major, minor); return MODULE_INCOMPATIBLE_VER; } if (module_load && !module_load()) { blog(LOG_WARNING, "Module '%s' failed to load: " "module_load failed", path); return MODULE_ERROR; } return MODULE_SUCCESS; } int obs_load_module(const char *path) { struct obs_module mod; char *plugin_path = find_plugin(path); int errorcode; mod.module = os_dlopen(plugin_path); bfree(plugin_path); if (!mod.module) return MODULE_FILENOTFOUND; errorcode = call_module_load(mod.module, path); if (errorcode != MODULE_SUCCESS) { os_dlclose(mod.module); return errorcode; } mod.name = bstrdup(path); module_load_exports(&mod, &obs->input_types.da, "inputs", sizeof(struct source_info), get_source_info); module_load_exports(&mod, &obs->filter_types.da, "filters", sizeof(struct source_info), get_source_info); module_load_exports(&mod, &obs->transition_types.da, "transitions", sizeof(struct source_info), get_source_info); module_load_exports(&mod, &obs->output_types.da, "outputs", sizeof(struct output_info), get_output_info); da_push_back(obs->modules, &mod); return MODULE_SUCCESS; } void free_module(struct obs_module *mod) { if (!mod) return; if (mod->module) { void (*module_unload)(void); module_unload = os_dlsym(mod->module, "module_unload"); if (module_unload) module_unload(); os_dlclose(mod->module); } bfree(mod->name); }