KDECore
kpluginloader.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE project 00002 Copyright (C) 2007 Bernhard Loos <nhuh.put@web.de> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License version 2 as published by the Free Software Foundation. 00007 00008 This library is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00011 Library General Public License for more details. 00012 00013 You should have received a copy of the GNU Library General Public License 00014 along with this library; see the file COPYING.LIB. If not, write to 00015 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00016 Boston, MA 02110-1301, USA. 00017 */ 00018 00019 #include "kpluginloader.h" 00020 00021 #include "kaboutdata.h" 00022 #include <kcomponentdata.h> 00023 #include <kstandarddirs.h> 00024 #include <klocale.h> 00025 #include "kpluginfactory.h" 00026 #include <kservice.h> 00027 #include "klibrary.h" 00028 #include <kdebug.h> 00029 00030 #include <QtCore/QLibrary> 00031 #include <QtCore/QDir> 00032 #include <QtCore/QFileInfo> 00033 00034 extern int kLibraryDebugArea(); 00035 00036 class KPluginLoaderPrivate 00037 { 00038 Q_DECLARE_PUBLIC(KPluginLoader) 00039 protected: 00040 KPluginLoaderPrivate(const QString &libname) 00041 : name(libname), pluginVersion(~0U), verificationData(0), lib(0) 00042 {} 00043 ~KPluginLoaderPrivate() 00044 { 00045 delete lib; 00046 } 00047 00048 KPluginLoader *q_ptr; 00049 const QString name; 00050 quint32 pluginVersion; 00051 KDEPluginVerificationData *verificationData; 00052 QString errorString; 00053 00054 KLibrary *lib; 00055 }; 00056 00057 inline QString makeLibName( const QString &libname ) 00058 { 00059 #if defined(Q_OS_WIN) || defined(Q_OS_CYGWIN) 00060 if (!libname.endsWith(QLatin1String(".dll"))) 00061 return libname + QLatin1String(".dll"); 00062 return libname; 00063 #else 00064 int pos = libname.lastIndexOf(QLatin1Char('/')); 00065 if (pos < 0) 00066 pos = 0; 00067 if (libname.indexOf(QLatin1Char('.'), pos) < 0) { 00068 const char* const extList[] = { ".so", ".dylib", ".bundle", ".sl" }; 00069 for (uint i = 0; i < sizeof(extList) / sizeof(*extList); ++i) { 00070 const QString lib = libname + QString::fromLatin1(extList[i]); 00071 if (QLibrary::isLibrary(lib)) 00072 return lib; 00073 } 00074 } 00075 return libname; 00076 #endif 00077 } 00078 00079 #ifdef Q_OS_WIN 00080 extern QString fixLibPrefix(const QString& libname); 00081 #endif 00082 00083 QString findLibraryInternal(const QString &name, const KComponentData &cData) 00084 { 00085 // Convert name to a valid platform libname 00086 QString libname = makeLibName(name); 00087 QFileInfo fileinfo(name); 00088 bool hasPrefix = fileinfo.fileName().startsWith(QLatin1String("lib")); 00089 bool kdeinit = fileinfo.fileName().startsWith(QLatin1String("libkdeinit4_")); 00090 00091 if (hasPrefix && !kdeinit) 00092 kDebug(kLibraryDebugArea()) << "plugins should not have a 'lib' prefix:" << libname; 00093 #ifdef Q_CC_MSVC 00094 // first remove the 'lib' prefix in front of windows plugins 00095 libname = fixLibPrefix(libname); 00096 #endif 00097 00098 // If it is a absolute path just return it 00099 if (!QDir::isRelativePath(libname)) 00100 return libname; 00101 00102 // Start looking 00103 QString libfile; 00104 00105 // Check for kde modules/plugins? 00106 libfile = cData.dirs()->findResource("module", libname); 00107 if (!libfile.isEmpty()) 00108 return libfile; 00109 00110 // Now look where they don't belong but sometimes are 00111 #ifndef Q_CC_MSVC 00112 if (!hasPrefix) 00113 libname = fileinfo.path() + QLatin1String("/lib") + fileinfo.fileName(); 00114 #endif 00115 00116 libfile = cData.dirs()->findResource("lib", libname); 00117 if (!libfile.isEmpty()) { 00118 if (!kdeinit) { 00119 kDebug(kLibraryDebugArea()) << "library" << libname << "not found under 'module' but under 'lib'"; 00120 } 00121 return libfile; 00122 } 00123 00124 // Nothing found 00125 return QString(); 00126 } 00127 00128 bool KPluginLoader::isLoaded() const 00129 { 00130 return QPluginLoader::isLoaded() || d_ptr->lib; 00131 } 00132 00133 KPluginLoader::KPluginLoader(const QString &plugin, const KComponentData &componentdata, QObject *parent) 00134 : QPluginLoader(findLibraryInternal(plugin, componentdata), parent), d_ptr(new KPluginLoaderPrivate(plugin)) 00135 { 00136 d_ptr->q_ptr = this; 00137 Q_D(KPluginLoader); 00138 00139 // No lib, no fun. 00140 if (fileName().isEmpty()) { 00141 d->errorString = i18n( 00142 "Could not find plugin '%1' for application '%2'", 00143 plugin, 00144 componentdata.aboutData()->appName()); 00145 return; 00146 } 00147 } 00148 00149 00150 KPluginLoader::KPluginLoader(const KService &service, const KComponentData &componentdata, QObject *parent) 00151 : QPluginLoader(findLibraryInternal(service.library(), componentdata), parent), d_ptr(new KPluginLoaderPrivate(service.library())) 00152 { 00153 d_ptr->q_ptr = this; 00154 Q_D(KPluginLoader); 00155 00156 // It's probably to late to check this because service.library() is used 00157 // above. 00158 if (!service.isValid()) { 00159 d->errorString = i18n("The provided service is not valid", service.entryPath()); 00160 return; 00161 } 00162 00163 // service.library() is used to find the lib. So first check if it is empty. 00164 if (service.library().isEmpty()) { 00165 d->errorString = i18n("The service '%1' provides no library or the Library key is missing in ", service.entryPath()); 00166 return; 00167 } 00168 00169 // No lib, no fun. service.library() was set but we were still unable to 00170 // find the lib. 00171 if (fileName().isEmpty()) { 00172 d->errorString = i18n( 00173 "Could not find plugin '%1' for application '%2'", 00174 service.name(), 00175 componentdata.aboutData()->appName()); 00176 return; 00177 } 00178 } 00179 00180 KPluginLoader::~KPluginLoader() 00181 { 00182 delete d_ptr; 00183 } 00184 00185 KPluginFactory *KPluginLoader::factory() 00186 { 00187 Q_D(KPluginLoader); 00188 00189 if (!load()) 00190 return 0; 00191 00192 #ifndef KDE_NO_DEPRECATED 00193 if (d->lib) { 00194 // Calling a deprecated method, but this is the only way to 00195 // support both new and old-style factories for now. 00196 // KDE5: remove the whole if(). 00197 return d->lib->factory(d->name.toUtf8()); 00198 } 00199 #endif 00200 00201 QObject *obj = instance(); 00202 00203 if (!obj) 00204 return 0; 00205 00206 KPluginFactory *factory = qobject_cast<KPluginFactory *>(obj); 00207 00208 if (factory == 0) { 00209 kDebug(kLibraryDebugArea()) << "Expected a KPluginFactory, got a" << obj->metaObject()->className(); 00210 delete obj; 00211 d->errorString = i18n("The library %1 does not offer a KDE 4 compatible factory." , d->name); 00212 } 00213 00214 return factory; 00215 } 00216 00217 bool KPluginLoader::load() 00218 { 00219 Q_D(KPluginLoader); 00220 00221 if (isLoaded()) 00222 return true; 00223 00224 if (!QPluginLoader::load()) { 00225 d->lib = new KLibrary(d->name); 00226 if (d->lib->load()) 00227 return true; 00228 00229 return false; 00230 } 00231 00232 Q_ASSERT(!fileName().isEmpty()); 00233 QLibrary lib(fileName()); 00234 Q_ASSERT(lib.isLoaded()); // already loaded by QPluginLoader::load() 00235 00236 d->verificationData = (KDEPluginVerificationData *) lib.resolve("kde_plugin_verification_data"); 00237 if (d->verificationData) { 00238 if (d->verificationData->dataVersion < KDEPluginVerificationData::PluginVerificationDataVersion 00239 || (d->verificationData->KDEVersion > KDE_VERSION) 00240 || (KDE_VERSION_MAJOR << 16 != (d->verificationData->KDEVersion & 0xFF0000))) 00241 { 00242 d->errorString = i18n("The plugin '%1' uses an incompatible KDE library (%2).", d->name, QString::fromLatin1(d->verificationData->KDEVersionString)); 00243 unload(); 00244 return false; 00245 } 00246 } else { 00247 kDebug(kLibraryDebugArea()) << "The plugin" << d->name << "doesn't contain a kde_plugin_verification_data structure"; 00248 } 00249 00250 quint32 *version = (quint32 *) lib.resolve("kde_plugin_version"); 00251 if (version) 00252 d->pluginVersion = *version; 00253 else 00254 d->pluginVersion = ~0U; 00255 00256 return true; 00257 } 00258 00259 QString KPluginLoader::errorString() const 00260 { 00261 Q_D(const KPluginLoader); 00262 const_cast<KPluginLoader*>(this)->load(); 00263 00264 if (!d->errorString.isEmpty()) 00265 return d->errorString; 00266 00267 return QPluginLoader::errorString(); 00268 } 00269 00270 quint32 KPluginLoader::pluginVersion() const 00271 { 00272 Q_D(const KPluginLoader); 00273 const_cast<KPluginLoader*>(this)->load(); 00274 return d->pluginVersion; 00275 } 00276 00277 QString KPluginLoader::pluginName() const 00278 { 00279 Q_D(const KPluginLoader); 00280 const_cast<KPluginLoader*>(this)->load(); 00281 return d->name; 00282 } 00283 00284 #include "kpluginloader.moc"
KDE 4.6 API Reference