summaryrefslogtreecommitdiffhomepage
path: root/api/plugin-support.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'api/plugin-support.hpp')
-rw-r--r--api/plugin-support.hpp283
1 files changed, 151 insertions, 132 deletions
diff --git a/api/plugin-support.hpp b/api/plugin-support.hpp
index 8fc01b98..4300da18 100644
--- a/api/plugin-support.hpp
+++ b/api/plugin-support.hpp
@@ -8,135 +8,124 @@
#pragma once
#include "plugin-api.hpp"
+#include "compat/library-path.hpp"
#include <memory>
#include <algorithm>
#include <cstring>
+#include <vector>
#include <QDebug>
#include <QString>
#include <QLibrary>
-#include <QList>
#include <QDir>
-#include <QList>
#include <QIcon>
-#if defined(__APPLE__)
-# define OPENTRACK_SOLIB_EXT "dylib"
-#elif defined(_WIN32)
-# define OPENTRACK_SOLIB_EXT "dll"
-#else
-# define OPENTRACK_SOLIB_EXT "so"
-#endif
+extern "C" {
+ using module_ctor_t = void* (*)(void);
+ using module_metadata_t = Metadata_* (*)(void);
+}
-#define OPENTRACK_SOLIB_PREFIX "lib"
+enum dylib_load_mode : unsigned
+{
+ dylib_load_norm = 0,
+ dylib_load_quiet = 1 << 0,
+ dylib_load_none = 1 << 1,
+};
-extern "C" typedef void* (*OPENTRACK_CTOR_FUNPTR)(void);
-extern "C" typedef Metadata* (*OPENTRACK_METADATA_FUNPTR)(void);
+enum class dylib_type : unsigned
+{
+ Filter = 0xdeadbabe,
+ Tracker = 0xcafebeef,
+ Protocol = 0xdeadf00d,
+ Video = 0xbadf00d,
+ Invalid = (unsigned)-1,
+};
struct dylib final
{
- enum Type : unsigned
- {
- Filter = 0xdeadbabeu,
- Tracker = 0xcafebeefu,
- Protocol = 0xdeadf00du,
- Extension = 0xdeadf001u,
- Invalid = 0xcafebabeu,
- };
-
- dylib(const QString& filename_, Type t) :
- type(Invalid),
+ dylib(const QString& filename_, dylib_type t, dylib_load_mode load_mode = dylib_load_norm) :
full_filename(filename_),
- module_name(trim_filename(filename_)),
- Dialog(nullptr),
- Constructor(nullptr),
- Meta(nullptr)
+ module_name(trim_filename(filename_))
{
// otherwise dlopen opens the calling executable
- if (filename_.size() == 0 || module_name.size() == 0)
+ if (filename_.isEmpty() || module_name.isEmpty())
return;
handle.setFileName(filename_);
- handle.setLoadHints(QLibrary::DeepBindHint | QLibrary::PreventUnloadHint);
-
- if (check(!handle.load()))
- return;
-
- if (check((Dialog = (OPENTRACK_CTOR_FUNPTR) handle.resolve("GetDialog"), !Dialog)))
- return;
+ handle.setLoadHints(QLibrary::DeepBindHint | QLibrary::ResolveAllSymbolsHint);
- if (check((Constructor = (OPENTRACK_CTOR_FUNPTR) handle.resolve("GetConstructor"), !Constructor)))
- return;
-
- if (check((Meta = (OPENTRACK_METADATA_FUNPTR) handle.resolve("GetMetadata"), !Meta)))
- return;
+#ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wcomma"
+#endif
- auto m = std::unique_ptr<Metadata>(Meta());
+ if (!handle.load())
+ goto fail;
- icon = m->icon();
- name = m->name();
+ if (!(load_mode & dylib_load_none))
+ {
+ std::unique_ptr<Metadata_> m;
- type = t;
- }
- ~dylib()
- {
- // QLibrary refcounts the .dll's so don't forcefully unload
- }
+ if (Dialog = (module_ctor_t) handle.resolve("GetDialog"), !Dialog)
+ goto fail;
- static QList<std::shared_ptr<dylib>> enum_libraries(const QString& library_path)
- {
- QDir module_directory(library_path);
- QList<std::shared_ptr<dylib>> ret;
+ if (Constructor = (module_ctor_t) handle.resolve("GetConstructor"), !Constructor)
+ goto fail;
- using str = QLatin1String;
+ if (Meta = (module_metadata_t) handle.resolve("GetMetadata"), !Meta)
+ goto fail;
- static const struct filter_ {
- Type type;
- QLatin1String glob;
- } filters[] = {
- { Filter, str(OPENTRACK_SOLIB_PREFIX "opentrack-filter-*." OPENTRACK_SOLIB_EXT), },
- { Tracker, str(OPENTRACK_SOLIB_PREFIX "opentrack-tracker-*." OPENTRACK_SOLIB_EXT), },
- { Protocol, str(OPENTRACK_SOLIB_PREFIX "opentrack-proto-*." OPENTRACK_SOLIB_EXT), },
- { Extension, str(OPENTRACK_SOLIB_PREFIX "opentrack-ext-*." OPENTRACK_SOLIB_EXT), },
- };
+ m = std::unique_ptr<Metadata_>(Meta());
- for (const filter_& filter : filters)
- {
- for (const QString& filename : module_directory.entryList({ filter.glob }, QDir::Files, QDir::Name))
+ if (!m)
{
- std::shared_ptr<dylib> lib = std::make_shared<dylib>(QStringLiteral("%1/%2").arg(library_path).arg(filename), filter.type);
-
- if (lib->type == Invalid)
- continue;
-
- if (std::any_of(ret.cbegin(),
- ret.cend(),
- [&lib](const std::shared_ptr<dylib>& a) {
- return a->type == lib->type && a->name == lib->name;
- }))
+ if (!(load_mode & dylib_load_quiet))
{
- qDebug() << "duplicate lib" << filename << "ident" << lib->name;
- continue;
+ qDebug() << "library" << module_name << "failed: no metadata";
+ load_mode = dylib_load_quiet;
}
-
- ret.push_back(lib);
+ goto fail;
}
+
+ icon = m->icon();
+ name = m->name();
}
+ else
+ name = module_name;
- return ret;
+ type = t;
+
+ return;
+#ifdef __clang__
+# pragma clang diagnostic pop
+#endif
+
+fail:
+ if (!(load_mode & dylib_load_quiet))
+ qDebug() << "library" << module_name << "failed:" << handle.errorString();
+
+ Constructor = nullptr;
+ Dialog = nullptr;
+ Meta = nullptr;
+
+ type = dylib_type::Invalid;
}
- Type type;
+ // QLibrary refcounts the .dll's so don't forcefully unload
+ ~dylib() = default;
+
+ dylib_type type = dylib_type::Invalid;
QString full_filename;
QString module_name;
QIcon icon;
QString name;
- OPENTRACK_CTOR_FUNPTR Dialog;
- OPENTRACK_CTOR_FUNPTR Constructor;
- OPENTRACK_METADATA_FUNPTR Meta;
+ module_ctor_t Dialog = nullptr;
+ module_ctor_t Constructor = nullptr;
+ module_metadata_t Meta = nullptr;
+
private:
QLibrary handle;
@@ -150,21 +139,21 @@ private:
{
in = in.mid(idx + 1);
- if (in.startsWith(OPENTRACK_SOLIB_PREFIX) &&
- in.endsWith("." OPENTRACK_SOLIB_EXT))
+ if (in.startsWith(OPENTRACK_LIBRARY_PREFIX) &&
+ in.endsWith("." OPENTRACK_LIBRARY_EXTENSION))
{
- constexpr unsigned pfx_len = sizeof(OPENTRACK_SOLIB_PREFIX) - 1;
- constexpr unsigned rst_len = sizeof("." OPENTRACK_SOLIB_EXT) - 1;
+ constexpr unsigned pfx_len = sizeof(OPENTRACK_LIBRARY_PREFIX) - 1;
+ constexpr unsigned rst_len = sizeof("." OPENTRACK_LIBRARY_EXTENSION) - 1;
in = in.mid(pfx_len);
in = in.left(in.size() - rst_len);
- static constexpr const char* const names[] =
+ const char* const names[] =
{
- "opentrack-tracker-",
- "opentrack-proto-",
- "opentrack-filter-",
- "opentrack-ext-",
+ OPENTRACK_LIBRARY_PREFIX "opentrack-tracker-",
+ OPENTRACK_LIBRARY_PREFIX "opentrack-proto-",
+ OPENTRACK_LIBRARY_PREFIX "opentrack-filter-",
+ OPENTRACK_LIBRARY_PREFIX "opentrack-video-",
};
for (auto name : names)
@@ -174,74 +163,104 @@ private:
}
}
}
- return QString();
- }
-
- bool check(bool fail)
- {
- if (fail)
- {
- qDebug() << "library" << module_name << "failed:" << handle.errorString();
-
- if (handle.isLoaded())
- (void) handle.unload();
-
- Constructor = nullptr;
- Dialog = nullptr;
- Meta = nullptr;
-
- type = Invalid;
- }
-
- return fail;
+ return {""};
}
};
struct Modules final
{
using dylib_ptr = std::shared_ptr<dylib>;
- using dylib_list = QList<dylib_ptr>;
-
- Modules(const QString& library_path) :
- module_list(dylib::enum_libraries(library_path)),
- filter_modules(filter(dylib::Filter)),
- tracker_modules(filter(dylib::Tracker)),
- protocol_modules(filter(dylib::Protocol)),
- extension_modules(filter(dylib::Extension))
+ using dylib_list = std::vector<dylib_ptr>;
+ using type = dylib_type;
+
+ Modules(const QString& library_path, dylib_load_mode load_mode = dylib_load_norm) :
+ module_list(enum_libraries(library_path, load_mode)),
+ filter_modules(filter(type::Filter)),
+ tracker_modules(filter(type::Tracker)),
+ protocol_modules(filter(type::Protocol)),
+ video_modules(filter(type::Video))
{}
dylib_list& filters() { return filter_modules; }
dylib_list& trackers() { return tracker_modules; }
dylib_list& protocols() { return protocol_modules; }
- dylib_list& extensions() { return extension_modules; }
+
private:
dylib_list module_list;
dylib_list filter_modules;
dylib_list tracker_modules;
dylib_list protocol_modules;
- dylib_list extension_modules;
+ dylib_list video_modules;
static dylib_list& sorted(dylib_list& xs)
{
- std::sort(xs.begin(), xs.end(), [&](const dylib_ptr& a, const dylib_ptr& b) { return a->name.toLower() < b->name.toLower(); });
+ std::sort(xs.begin(), xs.end(),
+ [&](const dylib_ptr& a, const dylib_ptr& b) {
+ return a->name.toLower() < b->name.toLower();
+ });
return xs;
}
- dylib_list filter(dylib::Type t)
+ dylib_list filter(dylib_type t)
{
- QList<std::shared_ptr<dylib>> ret;
- for (auto x : module_list)
+ dylib_list ret; ret.reserve(module_list.size());
+ for (const auto& x : module_list)
if (x->type == t)
ret.push_back(x);
return sorted(ret);
}
+
+ static dylib_list enum_libraries(const QString& library_path,
+ dylib_load_mode load_mode = dylib_load_norm)
+ {
+ QDir dir(library_path);
+ dylib_list ret;
+
+ const struct filter_ {
+ type t = type::Invalid;
+ QString glob;
+ dylib_load_mode load_mode = dylib_load_norm;
+ } filters[] = {
+ { type::Filter, OPENTRACK_LIBRARY_PREFIX "opentrack-filter-*." OPENTRACK_LIBRARY_EXTENSION, },
+ { type::Tracker, OPENTRACK_LIBRARY_PREFIX "opentrack-tracker-*." OPENTRACK_LIBRARY_EXTENSION, },
+ { type::Protocol, OPENTRACK_LIBRARY_PREFIX "opentrack-proto-*." OPENTRACK_LIBRARY_EXTENSION, },
+ { type::Video, OPENTRACK_LIBRARY_PREFIX "opentrack-video-*." OPENTRACK_LIBRARY_EXTENSION, dylib_load_none, },
+ };
+
+ for (const filter_& filter : filters)
+ {
+ for (const QString& filename : dir.entryList({ filter.glob }, QDir::Files, QDir::Name))
+ {
+ dylib_load_mode load_mode_{filter.load_mode | load_mode};
+ auto lib = std::make_shared<dylib>(QString("%1/%2").arg(library_path, filename), filter.t, load_mode_);
+
+ if (lib->type == type::Invalid)
+ continue;
+
+ if (std::any_of(ret.cbegin(),
+ ret.cend(),
+ [&lib](const std::shared_ptr<dylib>& a) {
+ return a->type == lib->type && a->name == lib->name;
+ }))
+ {
+ if (!(load_mode & dylib_load_quiet))
+ qDebug() << "duplicate lib" << filename << "ident" << lib->name;
+ continue;
+ }
+
+ ret.push_back(std::move(lib));
+ }
+ }
+
+ return ret;
+ }
};
template<typename t>
-static inline std::shared_ptr<t> make_dylib_instance(const std::shared_ptr<dylib>& lib)
+std::shared_ptr<t> make_dylib_instance(const std::shared_ptr<dylib>& lib)
{
- std::shared_ptr<t> ret;
if (lib != nullptr && lib->Constructor)
- ret = std::shared_ptr<t>(reinterpret_cast<t*>(reinterpret_cast<OPENTRACK_CTOR_FUNPTR>(lib->Constructor)()));
- return ret;
+ return std::shared_ptr<t>{(t*)lib->Constructor()};
+ else
+ return nullptr;
}