// SPDX-License-Identifier: GPL-2.0-or-later /* * Loader for external plug-ins. * * Authors: * Moritz Eberl * * Copyright (C) 2016 Authors * * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ #include "loader.h" #include #include "system.h" #include #include "dependency.h" #include "inkscape-version.h" namespace Inkscape { namespace Extension { typedef Implementation::Implementation *(*_getImplementation)(); typedef const gchar *(*_getInkscapeVersion)(); bool Loader::load_dependency(Dependency *dep) { GModule *module = nullptr; module = g_module_open(dep->get_name(), (GModuleFlags)0); if (module == nullptr) { return false; } return true; } /** * @brief Load the actual implementation of a plugin supplied by the plugin. * @param doc The xml representation of the INX extension configuration. * @return The implementation of the extension loaded from the plugin. */ Implementation::Implementation *Loader::load_implementation(Inkscape::XML::Document *doc) { try { Inkscape::XML::Node *repr = doc->root(); Inkscape::XML::Node *child_repr = repr->firstChild(); // Iterate over the xml content while (child_repr != nullptr) { char const *chname = child_repr->name(); if (!strncmp(chname, INKSCAPE_EXTENSION_NS_NC, strlen(INKSCAPE_EXTENSION_NS_NC))) { chname += strlen(INKSCAPE_EXTENSION_NS); } // Deal with dependencies if we have them if (!strcmp(chname, "dependency")) { Dependency dep = Dependency(child_repr, nullptr); // TODO: Why is "this" not an extension? // try to load it bool success = load_dependency(&dep); if( !success ){ // Could not load dependency, we abort const char *res = g_module_error(); g_warning("Unable to load dependency %s of plugin %s.\nDetails: %s\n", dep.get_name(), "", res); return nullptr; } } // Found a plugin to load if (!strcmp(chname, "plugin")) { // The name of the plugin is actually the library file we want to load if (const gchar *name = child_repr->attribute("name")) { GModule *module = nullptr; _getImplementation GetImplementation = nullptr; _getInkscapeVersion GetInkscapeVersion = nullptr; // build the path where to look for the plugin gchar *path = g_build_filename(_baseDirectory.c_str(), name, (char *) nullptr); module = g_module_open(path, G_MODULE_BIND_LOCAL); g_free(path); if (module == nullptr) { // we were not able to load the plugin, write warning and abort const char *res = g_module_error(); g_warning("Unable to load extension %s.\nDetails: %s\n", name, res); return nullptr; } // Get a handle to the version function of the module if (g_module_symbol(module, "GetInkscapeVersion", (gpointer *) &GetInkscapeVersion) == FALSE) { // This didn't work, write warning and abort const char *res = g_module_error(); g_warning("Unable to load extension %s.\nDetails: %s\n", name, res); return nullptr; } // Get a handle to the function that delivers the implementation if (g_module_symbol(module, "GetImplementation", (gpointer *) &GetImplementation) == FALSE) { // This didn't work, write warning and abort const char *res = g_module_error(); g_warning("Unable to load extension %s.\nDetails: %s\n", name, res); return nullptr; } // Get version and test against this version const gchar* version = GetInkscapeVersion(); if( strcmp(version, version_string) != 0) { // The versions are different, display warning. g_warning("Plugin was built against Inkscape version %s, this is %s. The plugin might not be compatible.", version, version_string); } Implementation::Implementation *i = GetImplementation(); return i; } } child_repr = child_repr->next(); } } catch (std::exception &e) { g_warning("Unable to load extension."); } return nullptr; } } // namespace Extension } // namespace Inkscape /* Local Variables: mode:c++ c-file-style:"stroustrup" c-file-offsets:((innamespace .0)(inline-open . 0)(case-label . +)) indent-tabs-mode:nil fill-column:99 End: */ // vim:filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99: