/* This file is part of the KDE project Copyright (C) 2007 Bernhard Loos This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kpluginloader.h" #include "kaboutdata.h" #include #include #include #include "kpluginfactory.h" #include #include "klibrary.h" #include #include #include #include extern int kLibraryDebugArea(); class KPluginLoaderPrivate { Q_DECLARE_PUBLIC(KPluginLoader) protected: KPluginLoaderPrivate(const QString &libname) : name(libname), pluginVersion(~0U), verificationData(0), lib(0) {} ~KPluginLoaderPrivate() { delete lib; } KPluginLoader *q_ptr; const QString name; quint32 pluginVersion; KDEPluginVerificationData *verificationData; QString errorString; KLibrary *lib; }; inline QString makeLibName( const QString &libname ) { #if defined(Q_OS_WIN) || defined(Q_OS_CYGWIN) if (!libname.endsWith(QLatin1String(".dll"))) return libname + QLatin1String(".dll"); return libname; #else int pos = libname.lastIndexOf(QLatin1Char('/')); if (pos < 0) pos = 0; if (libname.indexOf(QLatin1Char('.'), pos) < 0) { const char* const extList[] = { ".so", ".dylib", ".bundle", ".sl" }; for (uint i = 0; i < sizeof(extList) / sizeof(*extList); ++i) { const QString lib = libname + QString::fromLatin1(extList[i]); if (QLibrary::isLibrary(lib)) return lib; } } return libname; #endif } QString findLibraryInternal(const QString &name, const KComponentData &cData) { // Convert name to a valid platform libname QString libname = makeLibName(name); QFileInfo fileinfo(name); bool hasPrefix = fileinfo.fileName().startsWith(QLatin1String("lib")); bool kdeinit = fileinfo.fileName().startsWith(QLatin1String("libkdeinit4_")); if (hasPrefix && !kdeinit) kDebug(kLibraryDebugArea()) << "plugins should not have a 'lib' prefix:" << libname; #ifdef Q_CC_MSVC // first remove the 'lib' prefix in front of windows plugins libname = fixLibPrefix(libname); #endif // If it is a absolute path just return it if (!QDir::isRelativePath(libname)) return libname; // Start looking QString libfile; // Check for kde modules/plugins? libfile = cData.dirs()->findResource("module", libname); if (!libfile.isEmpty()) return libfile; // Now look where they don't belong but sometimes are #ifndef Q_CC_MSVC if (!hasPrefix) libname = fileinfo.path() + QLatin1String("/lib") + fileinfo.fileName(); #endif libfile = cData.dirs()->findResource("lib", libname); if (!libfile.isEmpty()) { if (!kdeinit) { kDebug(kLibraryDebugArea()) << "library" << libname << "not found under 'module' but under 'lib'"; } return libfile; } // Nothing found return QString(); } bool KPluginLoader::isLoaded() const { return QPluginLoader::isLoaded() || d_ptr->lib; } KPluginLoader::KPluginLoader(const QString &plugin, const KComponentData &componentdata, QObject *parent) : QPluginLoader(findLibraryInternal(plugin, componentdata), parent), d_ptr(new KPluginLoaderPrivate(plugin)) { d_ptr->q_ptr = this; Q_D(KPluginLoader); // No lib, no fun. if (fileName().isEmpty()) { d->errorString = i18n( "Could not find plugin '%1' for application '%2'", plugin, componentdata.aboutData()->appName()); return; } } KPluginLoader::KPluginLoader(const KService &service, const KComponentData &componentdata, QObject *parent) : QPluginLoader(findLibraryInternal(service.library(), componentdata), parent), d_ptr(new KPluginLoaderPrivate(service.library())) { d_ptr->q_ptr = this; Q_D(KPluginLoader); // It's probably to late to check this because service.library() is used // above. if (!service.isValid()) { d->errorString = i18n("The provided service is not valid"); return; } // service.library() is used to find the lib. So first check if it is empty. if (service.library().isEmpty()) { d->errorString = i18n("The service '%1' provides no library or the Library key is missing", service.entryPath()); return; } // No lib, no fun. service.library() was set but we were still unable to // find the lib. if (fileName().isEmpty()) { d->errorString = i18n( "Could not find plugin '%1' for application '%2'", service.name(), componentdata.aboutData()->appName()); return; } } KPluginLoader::~KPluginLoader() { delete d_ptr; } KPluginFactory *KPluginLoader::factory() { Q_D(KPluginLoader); if (!load()) return 0; QObject *obj = instance(); if (!obj) return 0; KPluginFactory *factory = qobject_cast(obj); if (factory == 0) { kDebug(kLibraryDebugArea()) << "Expected a KPluginFactory, got a" << obj->metaObject()->className(); delete obj; d->errorString = i18n("The library %1 does not offer a KDE 4 compatible factory." , d->name); } return factory; } bool KPluginLoader::load() { Q_D(KPluginLoader); if (isLoaded()) return true; if (!QPluginLoader::load()) { d->lib = new KLibrary(d->name); if (d->lib->load()) return true; return false; } Q_ASSERT(!fileName().isEmpty()); QLibrary lib(fileName()); Q_ASSERT(lib.isLoaded()); // already loaded by QPluginLoader::load() d->verificationData = (KDEPluginVerificationData *) lib.resolve("kde_plugin_verification_data"); if (d->verificationData) { if (d->verificationData->dataVersion < KDEPluginVerificationData::PluginVerificationDataVersion || ((d->verificationData->KDEVersion & 0xFFFF00) > (KDE_VERSION & 0xFFFF00)) // newer minor version || (KDE_VERSION_MAJOR << 16 != (d->verificationData->KDEVersion & 0xFF0000))) // different major version { d->errorString = i18n("The plugin '%1' uses an incompatible KDE library (%2).", d->name, QString::fromLatin1(d->verificationData->KDEVersionString)); unload(); return false; } } else { kDebug(kLibraryDebugArea()) << "The plugin" << d->name << "doesn't contain a kde_plugin_verification_data structure"; } quint32 *version = (quint32 *) lib.resolve("kde_plugin_version"); if (version) d->pluginVersion = *version; else d->pluginVersion = ~0U; return true; } QString KPluginLoader::errorString() const { Q_D(const KPluginLoader); if (!d->errorString.isEmpty()) return d->errorString; return QPluginLoader::errorString(); } quint32 KPluginLoader::pluginVersion() const { Q_D(const KPluginLoader); const_cast(this)->load(); return d->pluginVersion; } QString KPluginLoader::pluginName() const { Q_D(const KPluginLoader); const_cast(this)->load(); return d->name; } #include "moc_kpluginloader.cpp"