#include <cstdio>
#include <cinttypes>
#include "plugin-support.h"
#include <QCoreApplication>
#include <QFile>
#include <QDir>
#include <iostream>
#ifndef _WIN32
# include <dlfcn.h>
#endif
SelectedLibraries::~SelectedLibraries()
{
}
template<typename t>
static mem<t> make_instance(mem<dylib> lib)
{
mem<t> ret;
if (lib != nullptr && lib->Constructor)
{
qDebug() << "dylib" << (lib ? lib->filename : "<null>") << "ptr" << (intptr_t) lib->Constructor;
std::cout.flush();
ret = mem<t>(reinterpret_cast<t*>(reinterpret_cast<CTOR_FUNPTR>(lib->Constructor)()));
}
return ret;
}
SelectedLibraries::SelectedLibraries(QFrame* frame, dylibptr t, dylibptr p, dylibptr f) :
pTracker(nullptr),
pFilter(nullptr),
pProtocol(nullptr),
correct(false)
{
pTracker = make_instance<ITracker>(t);
pProtocol = make_instance<IProtocol>(p);
pFilter = make_instance<IFilter>(f);
if (!pTracker || !pProtocol)
{
qDebug() << "dylib load failure";
return;
}
if(!pProtocol->correct())
{
qDebug() << "protocol load failure";
return;
}
pTracker->start_tracker(frame);
correct = true;
}
#if defined(__APPLE__)
# define SONAME "dylib"
#elif defined(_WIN32)
# define SONAME "dll"
#else
# define SONAME "so"
#endif
#include <iostream>
#ifdef _MSC_VER
# error "No support for MSVC anymore"
#else
# define LIB_PREFIX "lib"
#endif
static bool get_metadata(mem<dylib> lib, QString& name, QIcon& icon)
{
Metadata* meta;
if (!lib->Meta || ((meta = lib->Meta()), !meta))
return false;
name = meta->name();
icon = meta->icon();
delete meta;
return true;
}
QList<mem<dylib>> dylib::enum_libraries()
{
#define BASE "opentrack-"
#define SUFF "-*."
const char* filters_n[] = { BASE "filter" SUFF,
BASE "tracker" SUFF,
BASE "proto" SUFF };
const Type filters_t[] = { Filter, Tracker, Protocol };
QDir settingsDir( QCoreApplication::applicationDirPath() );
QList<mem<dylib>> ret;
for (int i = 0; i < 3; i++)
{
QString filter = filters_n[i];
auto t = filters_t[i];
QStringList filenames = settingsDir.entryList(QStringList { LIB_PREFIX + filter + SONAME },
QDir::Files,
QDir::Name);
for (int i = 0; i < filenames.size(); i++) {
QIcon icon;
QString longName;
QString str = filenames.at(i);
auto lib = std::make_shared<dylib>(str, t);
qDebug() << "Loading" << str;
std::cout.flush();
if (!get_metadata(lib, longName, icon))
continue;
ret.push_back(lib);
}
}
return ret;
}
dylib::dylib(const QString& filename, Type t) :
type(t),
filename(filename),
Dialog(nullptr),
Constructor(nullptr),
Meta(nullptr),
handle(nullptr)
{
// otherwise dlopen opens the calling executable
if (filename.size() == 0)
return;
#if defined(_WIN32)
QString fullPath = QCoreApplication::applicationDirPath() + "/" + this->filename;
handle = new QLibrary(fullPath);
struct _foo {
static bool die(QLibrary*& l, bool failp)
{
if (failp)
{
qDebug() << "failed" << l->errorString();
delete l;
l = nullptr;
}
return failp;
}
};
if (_foo::die(handle, !handle->load()))
return;
Dialog = (CTOR_FUNPTR) handle->resolve("GetDialog");
if (_foo::die(handle, !Dialog))
return;
Constructor = (CTOR_FUNPTR) handle->resolve("GetConstructor");
if (_foo::die(handle, !Constructor))
return;
Meta = (METADATA_FUNPTR) handle->resolve("GetMetadata");
if (_foo::die(handle, !Meta))
return;
#else
QByteArray latin1 = QFile::encodeName(filename);
handle = dlopen(latin1.constData(), RTLD_NOW |
# if defined(__APPLE__)
RTLD_LOCAL|RTLD_FIRST|RTLD_NOW
# else
RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE
# endif
);
struct _foo {
static bool err(void*& handle)
{
const char* err = dlerror();
if (err)
{
fprintf(stderr, "Error, ignoring: %s\n", err);
fflush(stderr);
dlclose(handle);
handle = nullptr;
return true;
}
return false;
}
};
if (handle)
{
if (_foo::err(handle))
return;
Dialog = (CTOR_FUNPTR) dlsym(handle, "GetDialog");
if (_foo::err(handle))
return;
Constructor = (CTOR_FUNPTR) dlsym(handle, "GetConstructor");
if (_foo::err(handle))
return;
Meta = (METADATA_FUNPTR) dlsym(handle, "GetMetadata");
if (_foo::err(handle))
return;
} else {
(void) _foo::err(handle);
}
#endif
auto m = mem<Metadata>(Meta());
icon = m->icon();
name = m->name();
}
dylib::~dylib()
{
#if defined(_WIN32)
if (handle)
delete handle;
#else
if (handle)
(void) dlclose(handle);
#endif
}