diff options
author | axis <qt-info@nokia.com> | 2009-04-24 11:34:15 (GMT) |
---|---|---|
committer | axis <qt-info@nokia.com> | 2009-04-24 11:34:15 (GMT) |
commit | 8f427b2b914d5b575a4a7c0ed65d2fb8f45acc76 (patch) | |
tree | a17e1a767a89542ab59907462206d7dcf2e504b2 /src/corelib/plugin | |
download | Qt-8f427b2b914d5b575a4a7c0ed65d2fb8f45acc76.zip Qt-8f427b2b914d5b575a4a7c0ed65d2fb8f45acc76.tar.gz Qt-8f427b2b914d5b575a4a7c0ed65d2fb8f45acc76.tar.bz2 |
Long live Qt for S60!
Diffstat (limited to 'src/corelib/plugin')
-rw-r--r-- | src/corelib/plugin/plugin.pri | 24 | ||||
-rw-r--r-- | src/corelib/plugin/qfactoryinterface.h | 67 | ||||
-rw-r--r-- | src/corelib/plugin/qfactoryloader.cpp | 256 | ||||
-rw-r--r-- | src/corelib/plugin/qfactoryloader_p.h | 89 | ||||
-rw-r--r-- | src/corelib/plugin/qlibrary.cpp | 1182 | ||||
-rw-r--r-- | src/corelib/plugin/qlibrary.h | 120 | ||||
-rw-r--r-- | src/corelib/plugin/qlibrary_p.h | 122 | ||||
-rw-r--r-- | src/corelib/plugin/qlibrary_unix.cpp | 289 | ||||
-rw-r--r-- | src/corelib/plugin/qlibrary_win.cpp | 147 | ||||
-rw-r--r-- | src/corelib/plugin/qplugin.h | 141 | ||||
-rw-r--r-- | src/corelib/plugin/qpluginloader.cpp | 402 | ||||
-rw-r--r-- | src/corelib/plugin/qpluginloader.h | 100 | ||||
-rw-r--r-- | src/corelib/plugin/quuid.cpp | 624 | ||||
-rw-r--r-- | src/corelib/plugin/quuid.h | 190 |
14 files changed, 3753 insertions, 0 deletions
diff --git a/src/corelib/plugin/plugin.pri b/src/corelib/plugin/plugin.pri new file mode 100644 index 0000000..aaecec9 --- /dev/null +++ b/src/corelib/plugin/plugin.pri @@ -0,0 +1,24 @@ +# Qt core library plugin module + +HEADERS += \ + plugin/qfactoryinterface.h \ + plugin/qpluginloader.h \ + plugin/qlibrary.h \ + plugin/qlibrary_p.h \ + plugin/qplugin.h \ + plugin/quuid.h \ + plugin/qfactoryloader_p.h + +SOURCES += \ + plugin/qpluginloader.cpp \ + plugin/qfactoryloader.cpp \ + plugin/quuid.cpp \ + plugin/qlibrary.cpp + +win32 { + SOURCES += plugin/qlibrary_win.cpp +} + +unix { + SOURCES += plugin/qlibrary_unix.cpp +} diff --git a/src/corelib/plugin/qfactoryinterface.h b/src/corelib/plugin/qfactoryinterface.h new file mode 100644 index 0000000..ee00d8f --- /dev/null +++ b/src/corelib/plugin/qfactoryinterface.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFACTORYINTERFACE_H +#define QFACTORYINTERFACE_H + +#include <QtCore/qobject.h> +#include <QtCore/qstringlist.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +struct Q_CORE_EXPORT QFactoryInterface +{ + virtual ~QFactoryInterface() {} + virtual QStringList keys() const = 0; +}; + + +Q_DECLARE_INTERFACE(QFactoryInterface, "com.trolltech.Qt.QFactoryInterface") + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QFACTORYINTERFACE_H diff --git a/src/corelib/plugin/qfactoryloader.cpp b/src/corelib/plugin/qfactoryloader.cpp new file mode 100644 index 0000000..5163027 --- /dev/null +++ b/src/corelib/plugin/qfactoryloader.cpp @@ -0,0 +1,256 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfactoryloader_p.h" + +#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +#include "qfactoryinterface.h" +#include "qmap.h" +#include <qdir.h> +#include <qsettings.h> +#include <qdebug.h> +#include "qmutex.h" +#include "qplugin.h" +#include "qpluginloader.h" +#include "private/qobject_p.h" +#include "private/qcoreapplication_p.h" + +QT_BEGIN_NAMESPACE + +Q_GLOBAL_STATIC(QList<QFactoryLoader *>, qt_factory_loaders); + +Q_GLOBAL_STATIC_WITH_ARGS(QMutex, qt_factoryloader_mutex, (QMutex::Recursive)) + +class QFactoryLoaderPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QFactoryLoader) +public: + QFactoryLoaderPrivate(){} + mutable QMutex mutex; + QByteArray iid; + QList<QLibraryPrivate*> libraryList; + QMap<QString,QLibraryPrivate*> keyMap; + QStringList keyList; + QString suffix; + Qt::CaseSensitivity cs; + QStringList loadedPaths; + + void unloadPath(const QString &path); +}; + +QFactoryLoader::QFactoryLoader(const char *iid, + const QString &suffix, + Qt::CaseSensitivity cs) + : QObject(*new QFactoryLoaderPrivate) +{ + moveToThread(QCoreApplicationPrivate::mainThread()); + Q_D(QFactoryLoader); + d->iid = iid; + d->cs = cs; + d->suffix = suffix; + + + QMutexLocker locker(qt_factoryloader_mutex()); + qt_factory_loaders()->append(this); + update(); +} + + + +void QFactoryLoader::update() +{ +#ifdef QT_SHARED + Q_D(QFactoryLoader); + QStringList paths = QCoreApplication::libraryPaths(); + QSettings settings(QSettings::UserScope, QLatin1String("Trolltech")); + for (int i = 0; i < paths.count(); ++i) { + const QString &pluginDir = paths.at(i); + // Already loaded, skip it... + if (d->loadedPaths.contains(pluginDir)) + continue; + d->loadedPaths << pluginDir; + + QString path = pluginDir + d->suffix; + if (!QDir(path).exists(QLatin1String("."))) + continue; + + QStringList plugins = QDir(path).entryList(QDir::Files); + QLibraryPrivate *library = 0; + for (int j = 0; j < plugins.count(); ++j) { + QString fileName = QDir::cleanPath(path + QLatin1Char('/') + plugins.at(j)); + if (qt_debug_component()) { + qDebug() << "QFactoryLoader::QFactoryLoader() looking at" << fileName; + } + library = QLibraryPrivate::findOrCreate(QFileInfo(fileName).canonicalFilePath()); + if (!library->isPlugin(&settings)) { + if (qt_debug_component()) { + qDebug() << library->errorString; + qDebug() << " not a plugin"; + } + library->release(); + continue; + } + QString regkey = QString::fromLatin1("Qt Factory Cache %1.%2/%3:/%4") + .arg((QT_VERSION & 0xff0000) >> 16) + .arg((QT_VERSION & 0xff00) >> 8) + .arg(QLatin1String(d->iid)) + .arg(fileName); + QStringList reg, keys; + reg = settings.value(regkey).toStringList(); + if (reg.count() && library->lastModified == reg[0]) { + keys = reg; + keys.removeFirst(); + } else { + if (!library->loadPlugin()) { + if (qt_debug_component()) { + qDebug() << library->errorString; + qDebug() << " could not load"; + } + library->release(); + continue; + } + QObject *instance = library->instance(); + if (!instance) + // ignore plugins that have a valid signature but cannot be loaded. + continue; + QFactoryInterface *factory = qobject_cast<QFactoryInterface*>(instance); + if (instance && factory && instance->qt_metacast(d->iid)) + keys = factory->keys(); + if (keys.isEmpty()) + library->unload(); + reg.clear(); + reg << library->lastModified; + reg += keys; + settings.setValue(regkey, reg); + } + if (qt_debug_component()) { + qDebug() << "keys" << keys; + } + + if (keys.isEmpty()) { + library->release(); + continue; + } + d->libraryList += library; + for (int k = 0; k < keys.count(); ++k) { + // first come first serve, unless the first + // library was built with a future Qt version, + // whereas the new one has a Qt version that fits + // better + QString key = keys.at(k); + if (!d->cs) + key = key.toLower(); + QLibraryPrivate *previous = d->keyMap.value(key); + if (!previous || (previous->qt_version > QT_VERSION && library->qt_version <= QT_VERSION)) { + d->keyMap[key] = library; + d->keyList += keys.at(k); + } + } + } + } +#else + Q_D(QFactoryLoader); + if (qt_debug_component()) { + qDebug() << "QFactoryLoader::QFactoryLoader() ignoring" << d->iid + << "since plugins are disabled in static builds"; + } +#endif +} + +QFactoryLoader::~QFactoryLoader() +{ + Q_D(QFactoryLoader); + for (int i = 0; i < d->libraryList.count(); ++i) + d->libraryList.at(i)->release(); + + QMutexLocker locker(qt_factoryloader_mutex()); + qt_factory_loaders()->removeAll(this); +} + +QStringList QFactoryLoader::keys() const +{ + Q_D(const QFactoryLoader); + QMutexLocker locker(&d->mutex); + QStringList keys = d->keyList; + QObjectList instances = QPluginLoader::staticInstances(); + for (int i = 0; i < instances.count(); ++i) + if (QFactoryInterface *factory = qobject_cast<QFactoryInterface*>(instances.at(i))) + if (instances.at(i)->qt_metacast(d->iid)) + keys += factory->keys(); + return keys; +} + +QObject *QFactoryLoader::instance(const QString &key) const +{ + Q_D(const QFactoryLoader); + QMutexLocker locker(&d->mutex); + QObjectList instances = QPluginLoader::staticInstances(); + for (int i = 0; i < instances.count(); ++i) + if (QFactoryInterface *factory = qobject_cast<QFactoryInterface*>(instances.at(i))) + if (instances.at(i)->qt_metacast(d->iid) && factory->keys().contains(key, Qt::CaseInsensitive)) + return instances.at(i); + + QString lowered = d->cs ? key : key.toLower(); + if (QLibraryPrivate* library = d->keyMap.value(lowered)) { + if (library->instance || library->loadPlugin()) { + if (QObject *obj = library->instance()) { + if (obj && !obj->parent()) + obj->moveToThread(QCoreApplicationPrivate::mainThread()); + return obj; + } + } + } + return 0; +} + +void QFactoryLoader::refreshAll() +{ + QMutexLocker locker(qt_factoryloader_mutex()); + QList<QFactoryLoader *> *loaders = qt_factory_loaders(); + for (QList<QFactoryLoader *>::const_iterator it = loaders->constBegin(); + it != loaders->constEnd(); ++it) { + (*it)->update(); + } +} + +QT_END_NAMESPACE + +#endif // QT_NO_LIBRARY diff --git a/src/corelib/plugin/qfactoryloader_p.h b/src/corelib/plugin/qfactoryloader_p.h new file mode 100644 index 0000000..8110a60 --- /dev/null +++ b/src/corelib/plugin/qfactoryloader_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFACTORYLOADER_P_H +#define QFACTORYLOADER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "QtCore/qobject.h" +#include "QtCore/qstringlist.h" +#include "private/qlibrary_p.h" + +#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + +QT_BEGIN_NAMESPACE + +class QFactoryLoaderPrivate; + +class Q_CORE_EXPORT QFactoryLoader : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QFactoryLoader) + +public: + QFactoryLoader(const char *iid, + const QString &suffix = QString(), + Qt::CaseSensitivity = Qt::CaseSensitive); + ~QFactoryLoader(); + + QStringList keys() const; + QObject *instance(const QString &key) const; + + void update(); + + static void refreshAll(); +}; + +QT_END_NAMESPACE + +#endif // QT_NO_LIBRARY + +#endif // QFACTORYLOADER_P_H diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp new file mode 100644 index 0000000..420dd1d --- /dev/null +++ b/src/corelib/plugin/qlibrary.cpp @@ -0,0 +1,1182 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" +#include "qlibrary.h" + +#ifndef QT_NO_LIBRARY + +#include "qlibrary_p.h" +#include <qstringlist.h> +#include <qfile.h> +#include <qfileinfo.h> +#include <qmutex.h> +#include <qmap.h> +#include <qsettings.h> +#include <qdatetime.h> +#ifdef Q_OS_MAC +# include <private/qcore_mac_p.h> +#endif +#ifndef NO_ERRNO_H +#include <errno.h> +#endif // NO_ERROR_H +#include <qdebug.h> +#include <qvector.h> +#include <qdir.h> + +QT_BEGIN_NAMESPACE + +//#define QT_DEBUG_COMPONENT + +#ifdef QT_NO_DEBUG +# define QLIBRARY_AS_DEBUG false +#else +# define QLIBRARY_AS_DEBUG true +#endif + +#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) +// We don't use separate debug and release libs on UNIX, so we want +// to allow loading plugins, regardless of how they were built. +# define QT_NO_DEBUG_PLUGIN_CHECK +#endif + +Q_GLOBAL_STATIC(QMutex, qt_library_mutex) + +/*! + \class QLibrary + \reentrant + \brief The QLibrary class loads shared libraries at runtime. + + \mainclass + \ingroup plugins + + An instance of a QLibrary object operates on a single shared + object file (which we call a "library", but is also known as a + "DLL"). A QLibrary provides access to the functionality in the + library in a platform independent way. You can either pass a file + name in the constructor, or set it explicitly with setFileName(). + When loading the library, QLibrary searches in all the + system-specific library locations (e.g. \c LD_LIBRARY_PATH on + Unix), unless the file name has an absolute path. If the file + cannot be found, QLibrary tries the name with different + platform-specific file suffixes, like ".so" on Unix, ".dylib" on + the Mac, or ".dll" on Windows and Symbian. This makes it possible + to specify shared libraries that are only identified by their + basename (i.e. without their suffix), so the same code will work + on different operating systems. + + The most important functions are load() to dynamically load the + library file, isLoaded() to check whether loading was successful, + and resolve() to resolve a symbol in the library. The resolve() + function implicitly tries to load the library if it has not been + loaded yet. Multiple instances of QLibrary can be used to access + the same physical library. Once loaded, libraries remain in memory + until the application terminates. You can attempt to unload a + library using unload(), but if other instances of QLibrary are + using the same library, the call will fail, and unloading will + only happen when every instance has called unload(). + + A typical use of QLibrary is to resolve an exported symbol in a + library, and to call the C function that this symbol represents. + This is called "explicit linking" in contrast to "implicit + linking", which is done by the link step in the build process when + linking an executable against a library. + + Note: In Symbian resolving symbols using their names is supported + only if the library is built as STDDLL. Otherwise ordinals must + be used. Also, in Symbian the path of the library is ignored and + system default library location is always used. + + The following code snippet loads a library, resolves the symbol + "mysymbol", and calls the function if everything succeeded. If + something goes wrong, e.g. the library file does not exist or the + symbol is not defined, the function pointer will be 0 and won't be + called. + + \snippet doc/src/snippets/code/src_corelib_plugin_qlibrary.cpp 0 + + The symbol must be exported as a C function from the library for + resolve() to work. This means that the function must be wrapped in + an \c{extern "C"} block if the library is compiled with a C++ + compiler. On Windows, this also requires the use of a \c dllexport + macro; see resolve() for the details of how this is done. For + convenience, there is a static resolve() function which you can + use if you just want to call a function in a library without + explicitly loading the library first: + + \snippet doc/src/snippets/code/src_corelib_plugin_qlibrary.cpp 1 + + \sa QPluginLoader +*/ + +/*! + \enum QLibrary::LoadHint + + This enum describes the possible hints that can be used to change the way + libraries are handled when they are loaded. These values indicate how + symbols are resolved when libraries are loaded, and are specified using + the setLoadHints() function. + + \value ResolveAllSymbolsHint + Causes all symbols in a library to be resolved when it is loaded, not + simply when resolve() is called. + \value ExportExternalSymbolsHint + Exports unresolved and external symbols in the library so that they can be + resolved in other dynamically-loaded libraries loaded later. + \value LoadArchiveMemberHint + Allows the file name of the library to specify a particular object file + within an archive file. + If this hint is given, the filename of the library consists of + a path, which is a reference to an archive file, followed by + a reference to the archive member. + + \sa loadHints +*/ + + +#ifndef QT_NO_PLUGIN_CHECK +struct qt_token_info +{ + qt_token_info(const char *f, const ulong fc) + : fields(f), field_count(fc), results(fc), lengths(fc) + { + results.fill(0); + lengths.fill(0); + } + + const char *fields; + const ulong field_count; + + QVector<const char *> results; + QVector<ulong> lengths; +}; + +/* + return values: + 1 parse ok + 0 eos + -1 parse error +*/ +static int qt_tokenize(const char *s, ulong s_len, ulong *advance, + qt_token_info &token_info) +{ + ulong pos = 0, field = 0, fieldlen = 0; + char current; + int ret = -1; + *advance = 0; + for (;;) { + current = s[pos]; + + // next char + ++pos; + ++fieldlen; + ++*advance; + + if (! current || pos == s_len + 1) { + // save result + token_info.results[(int)field] = s; + token_info.lengths[(int)field] = fieldlen - 1; + + // end of string + ret = 0; + break; + } + + if (current == token_info.fields[field]) { + // save result + token_info.results[(int)field] = s; + token_info.lengths[(int)field] = fieldlen - 1; + + // end of field + fieldlen = 0; + ++field; + if (field == token_info.field_count - 1) { + // parse ok + ret = 1; + } + if (field == token_info.field_count) { + // done parsing + break; + } + + // reset string and its length + s = s + pos; + s_len -= pos; + pos = 0; + } + } + + return ret; +} + +/* + returns true if the string s was correctly parsed, false otherwise. +*/ +static bool qt_parse_pattern(const char *s, uint *version, bool *debug, QByteArray *key) +{ + bool ret = true; + + qt_token_info pinfo("=\n", 2); + int parse; + ulong at = 0, advance, parselen = qstrlen(s); + do { + parse = qt_tokenize(s + at, parselen, &advance, pinfo); + if (parse == -1) { + ret = false; + break; + } + + at += advance; + parselen -= advance; + + if (qstrncmp("version", pinfo.results[0], pinfo.lengths[0]) == 0) { + // parse version string + qt_token_info pinfo2("..-", 3); + if (qt_tokenize(pinfo.results[1], pinfo.lengths[1], + &advance, pinfo2) != -1) { + QByteArray m(pinfo2.results[0], pinfo2.lengths[0]); + QByteArray n(pinfo2.results[1], pinfo2.lengths[1]); + QByteArray p(pinfo2.results[2], pinfo2.lengths[2]); + *version = (m.toUInt() << 16) | (n.toUInt() << 8) | p.toUInt(); + } else { + ret = false; + break; + } + } else if (qstrncmp("debug", pinfo.results[0], pinfo.lengths[0]) == 0) { + *debug = qstrncmp("true", pinfo.results[1], pinfo.lengths[1]) == 0; + } else if (qstrncmp("buildkey", pinfo.results[0], + pinfo.lengths[0]) == 0){ + // save buildkey + *key = QByteArray(pinfo.results[1], pinfo.lengths[1]); + } + } while (parse == 1 && parselen > 0); + + return ret; +} +#endif // QT_NO_PLUGIN_CHECK + +#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_SYMBIAN) && !defined(QT_NO_PLUGIN_CHECK) + +#if defined(Q_OS_FREEBSD) || defined(Q_OS_LINUX) +# define USE_MMAP +QT_BEGIN_INCLUDE_NAMESPACE +# include <sys/types.h> +# include <sys/mman.h> +QT_END_INCLUDE_NAMESPACE +#endif // Q_OS_FREEBSD || Q_OS_LINUX + +static long qt_find_pattern(const char *s, ulong s_len, + const char *pattern, ulong p_len) +{ + /* + we search from the end of the file because on the supported + systems, the read-only data/text segments are placed at the end + of the file. HOWEVER, when building with debugging enabled, all + the debug symbols are placed AFTER the data/text segments. + + what does this mean? when building in release mode, the search + is fast because the data we are looking for is at the end of the + file... when building in debug mode, the search is slower + because we have to skip over all the debugging symbols first + */ + + if (! s || ! pattern || p_len > s_len) return -1; + ulong i, hs = 0, hp = 0, delta = s_len - p_len; + + for (i = 0; i < p_len; ++i) { + hs += s[delta + i]; + hp += pattern[i]; + } + i = delta; + for (;;) { + if (hs == hp && qstrncmp(s + i, pattern, p_len) == 0) + return i; + if (i == 0) + break; + --i; + hs -= s[i + p_len]; + hs += s[i]; + } + + return -1; +} + +/* + This opens the specified library, mmaps it into memory, and searches + for the QT_PLUGIN_VERIFICATION_DATA. The advantage of this approach is that + we can get the verification data without have to actually load the library. + This lets us detect mismatches more safely. + + Returns false if version/key information is not present, or if the + information could not be read. + Returns true if version/key information is present and successfully read. +*/ +static bool qt_unix_query(const QString &library, uint *version, bool *debug, QByteArray *key, QLibraryPrivate *lib = 0) +{ + QFile file(library); + if (!file.open(QIODevice::ReadOnly)) { + if (lib) + lib->errorString = file.errorString(); + if (qt_debug_component()) { + qWarning("%s: %s", (const char*) QFile::encodeName(library), + qPrintable(qt_error_string(errno))); + } + return false; + } + + QByteArray data; + char *filedata = 0; + ulong fdlen = 0; + +# ifdef USE_MMAP + char *mapaddr = 0; + size_t maplen = file.size(); + mapaddr = (char *) mmap(mapaddr, maplen, PROT_READ, MAP_PRIVATE, file.handle(), 0); + if (mapaddr != MAP_FAILED) { + // mmap succeeded + filedata = mapaddr; + fdlen = maplen; + } else { + // mmap failed + if (qt_debug_component()) { + qWarning("mmap: %s", qPrintable(qt_error_string(errno))); + } + if (lib) + lib->errorString = QLibrary::tr("Could not mmap '%1': %2") + .arg(library) + .arg(qt_error_string()); +# endif // USE_MMAP + // try reading the data into memory instead + data = file.readAll(); + filedata = data.data(); + fdlen = data.size(); +# ifdef USE_MMAP + } +# endif // USE_MMAP + + // verify that the pattern is present in the plugin + const char pattern[] = "pattern=QT_PLUGIN_VERIFICATION_DATA"; + const ulong plen = qstrlen(pattern); + long pos = qt_find_pattern(filedata, fdlen, pattern, plen); + + bool ret = false; + if (pos >= 0) + ret = qt_parse_pattern(filedata + pos, version, debug, key); + + if (!ret && lib) + lib->errorString = QLibrary::tr("Plugin verification data mismatch in '%1'").arg(library); +# ifdef USE_MMAP + if (mapaddr != MAP_FAILED && munmap(mapaddr, maplen) != 0) { + if (qt_debug_component()) + qWarning("munmap: %s", qPrintable(qt_error_string(errno))); + if (lib) + lib->errorString = QLibrary::tr("Could not unmap '%1': %2") + .arg(library) + .arg( qt_error_string() ); + } +# endif // USE_MMAP + + file.close(); + return ret; +} + +#endif // Q_OS_UNIX && !Q_OS_MAC && !defined(Q_OS_SYMBIAN) && !defined(QT_NO_PLUGIN_CHECK) + +typedef QMap<QString, QLibraryPrivate*> LibraryMap; +Q_GLOBAL_STATIC(LibraryMap, libraryMap) + +QLibraryPrivate::QLibraryPrivate(const QString &canonicalFileName, const QString &version) + :pHnd(0), fileName(canonicalFileName), fullVersion(version), instance(0), qt_version(0), + libraryRefCount(1), libraryUnloadCount(0), pluginState(MightBeAPlugin) +{ libraryMap()->insert(canonicalFileName, this); } + +QLibraryPrivate *QLibraryPrivate::findOrCreate(const QString &fileName, const QString &version) +{ + QMutexLocker locker(qt_library_mutex()); + if (QLibraryPrivate *lib = libraryMap()->value(fileName)) { + lib->libraryRefCount.ref(); + return lib; + } + + return new QLibraryPrivate(fileName, version); +} + +QLibraryPrivate::~QLibraryPrivate() +{ + LibraryMap * const map = libraryMap(); + if (map) { + QLibraryPrivate *that = map->take(fileName); + Q_ASSERT(this == that); + Q_UNUSED(that); + } +} + +void *QLibraryPrivate::resolve(const char *symbol) +{ + if (!pHnd) + return 0; + return resolve_sys(symbol); +} + + +bool QLibraryPrivate::load() +{ + libraryUnloadCount.ref(); + if (pHnd) + return true; + if (fileName.isEmpty()) + return false; + return load_sys(); +} + +bool QLibraryPrivate::unload() +{ + if (!pHnd) + return false; + if (!libraryUnloadCount.deref()) { // only unload if ALL QLibrary instance wanted to + if (instance) + delete instance(); + if (unload_sys()) { + instance = 0; + pHnd = 0; + } + } + + return (pHnd == 0); +} + +void QLibraryPrivate::release() +{ + QMutexLocker locker(qt_library_mutex()); + if (!libraryRefCount.deref()) + delete this; +} + +bool QLibraryPrivate::loadPlugin() +{ + if (instance) { + libraryUnloadCount.ref(); + return true; + } + if (load()) { + instance = (QtPluginInstanceFunction)resolve("qt_plugin_instance"); +#if defined(Q_OS_SYMBIAN) + // If resolving with function name failed (i.e. not STDDLL), try resolving using known ordinal + if (!instance) + instance = (QtPluginInstanceFunction)resolve("2"); +#endif + return instance; + } + return false; +} + +/*! + Returns true if \a fileName has a valid suffix for a loadable + library; otherwise returns false. + + \table + \header \i Platform \i Valid suffixes + \row \i Windows \i \c .dll + \row \i Unix/Linux \i \c .so + \row \i AIX \i \c .a + \row \i HP-UX \i \c .sl, \c .so (HP-UXi) + \row \i Mac OS X \i \c .dylib, \c .bundle, \c .so + \endtable + + Trailing versioning numbers on Unix are ignored. + */ +bool QLibrary::isLibrary(const QString &fileName) +{ +#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) + return fileName.endsWith(QLatin1String(".dll")); +#elif defined(Q_OS_SYMBIAN) + // Plugin stubs are also considered libraries in Symbian. + return (fileName.endsWith(QLatin1String(".dll")) || + fileName.endsWith(QLatin1String(".qtplugin"))); +#else + QString completeSuffix = QFileInfo(fileName).completeSuffix(); + if (completeSuffix.isEmpty()) + return false; + QStringList suffixes = completeSuffix.split(QLatin1Char('.')); +# if defined(Q_OS_DARWIN) + + // On Mac, libs look like libmylib.1.0.0.dylib + const QString lastSuffix = suffixes.at(suffixes.count() - 1); + const QString firstSuffix = suffixes.at(0); + + bool valid = (lastSuffix == QLatin1String("dylib") + || firstSuffix == QLatin1String("so") + || firstSuffix == QLatin1String("bundle")); + + return valid; +# else // Generic Unix + QStringList validSuffixList; + +# if defined(Q_OS_HPUX) +/* + See "HP-UX Linker and Libraries User's Guide", section "Link-time Differences between PA-RISC and IPF": + "In PA-RISC (PA-32 and PA-64) shared libraries are suffixed with .sl. In IPF (32-bit and 64-bit), + the shared libraries are suffixed with .so. For compatibility, the IPF linker also supports the .sl suffix." + */ + validSuffixList << QLatin1String("sl"); +# if defined __ia64 + validSuffixList << QLatin1String("so"); +# endif +# elif defined(Q_OS_AIX) + validSuffixList << QLatin1String("a") << QLatin1String("so"); +# elif defined(Q_OS_UNIX) + validSuffixList << QLatin1String("so"); +# endif + + // Examples of valid library names: + // libfoo.so + // libfoo.so.0 + // libfoo.so.0.3 + // libfoo-0.3.so + // libfoo-0.3.so.0.3.0 + + int suffix; + int suffixPos = -1; + for (suffix = 0; suffix < validSuffixList.count() && suffixPos == -1; ++suffix) + suffixPos = suffixes.indexOf(validSuffixList.at(suffix)); + + bool valid = suffixPos != -1; + for (int i = suffixPos + 1; i < suffixes.count() && valid; ++i) + if (i != suffixPos) + suffixes.at(i).toInt(&valid); + return valid; +# endif +#endif + +} + +bool QLibraryPrivate::isPlugin(QSettings *settings) +{ + errorString.clear(); + if (pluginState != MightBeAPlugin) + return pluginState == IsAPlugin; + +#ifndef QT_NO_PLUGIN_CHECK + bool debug = !QLIBRARY_AS_DEBUG; + QByteArray key; + bool success = false; + + QFileInfo fileinfo(fileName); + +#ifndef QT_NO_DATESTRING + lastModified = fileinfo.lastModified().toString(Qt::ISODate); +#endif + QString regkey = QString::fromLatin1("Qt Plugin Cache %1.%2.%3/%4") + .arg((QT_VERSION & 0xff0000) >> 16) + .arg((QT_VERSION & 0xff00) >> 8) + .arg(QLIBRARY_AS_DEBUG ? QLatin1String("debug") : QLatin1String("false")) + .arg(fileName); + QStringList reg; +#ifndef QT_NO_SETTINGS + bool madeSettings = false; + if (!settings) { + settings = new QSettings(QSettings::UserScope, QLatin1String("Trolltech")); + madeSettings = true; + } + reg = settings->value(regkey).toStringList(); +#endif + if (reg.count() == 4 && lastModified == reg.at(3)) { + qt_version = reg.at(0).toUInt(0, 16); + debug = bool(reg.at(1).toInt()); + key = reg.at(2).toLatin1(); + success = qt_version != 0; + } else { +#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_SYMBIAN) + if (!pHnd) { + // use unix shortcut to avoid loading the library + success = qt_unix_query(fileName, &qt_version, &debug, &key, this); + } else +#endif + { + bool temporary_load = false; +#ifdef Q_OS_WIN + HMODULE hTempModule = 0; +#endif + if (!pHnd) { +#ifdef Q_OS_WIN + QT_WA({ + hTempModule = ::LoadLibraryExW((wchar_t*)QDir::toNativeSeparators(fileName).utf16(), 0, DONT_RESOLVE_DLL_REFERENCES); + } , { + temporary_load = load_sys(); + }); +#else +# if defined(Q_OS_SYMBIAN) + //Guard against accidentally trying to load non-plugin libraries by making sure the stub exists + if (fileinfo.exists()) +# endif + temporary_load = load_sys(); +#endif + } +# ifdef Q_CC_BOR + typedef const char * __stdcall (*QtPluginQueryVerificationDataFunction)(); +# else + typedef const char * (*QtPluginQueryVerificationDataFunction)(); +# endif +#ifdef Q_OS_WIN + QtPluginQueryVerificationDataFunction qtPluginQueryVerificationDataFunction = hTempModule + ? (QtPluginQueryVerificationDataFunction) +#ifdef Q_OS_WINCE + ::GetProcAddressW(hTempModule, L"qt_plugin_query_verification_data") +#else + ::GetProcAddress(hTempModule, "qt_plugin_query_verification_data") +#endif + : (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data"); +#else + QtPluginQueryVerificationDataFunction qtPluginQueryVerificationDataFunction = NULL; +# if defined(Q_OS_SYMBIAN) + if (temporary_load) { + qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data"); + // If resolving with function name failed (i.e. not STDDLL), try resolving using known ordinal + if (!qtPluginQueryVerificationDataFunction) + qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("1"); + } +# else + qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data"); +# endif +#endif + + if (!qtPluginQueryVerificationDataFunction + || !qt_parse_pattern(qtPluginQueryVerificationDataFunction(), &qt_version, &debug, &key)) { + qt_version = 0; + key = "unknown"; + if (temporary_load) + unload_sys(); + } else { + success = true; + } +#ifdef Q_OS_WIN + if (hTempModule) { + BOOL ok = ::FreeLibrary(hTempModule); + if (ok) { + hTempModule = 0; + } + + } +#endif + } + + QStringList queried; + queried << QString::number(qt_version,16) + << QString::number((int)debug) + << QLatin1String(key) + << lastModified; +#ifndef QT_NO_SETTINGS + settings->setValue(regkey, queried); +#endif + } +#ifndef QT_NO_SETTINGS + if (madeSettings) + delete settings; +#endif + + if (!success) { + if (errorString.isEmpty()){ + if (fileName.isEmpty()) + errorString = QLibrary::tr("The shared library was not found."); + else + errorString = QLibrary::tr("The file '%1' is not a valid Qt plugin.").arg(fileName); + } + return false; + } + + pluginState = IsNotAPlugin; // be pessimistic + + if ((qt_version > QT_VERSION) || ((QT_VERSION & 0xff0000) > (qt_version & 0xff0000))) { + if (qt_debug_component()) { + qWarning("In %s:\n" + " Plugin uses incompatible Qt library (%d.%d.%d) [%s]", + (const char*) QFile::encodeName(fileName), + (qt_version&0xff0000) >> 16, (qt_version&0xff00) >> 8, qt_version&0xff, + debug ? "debug" : "release"); + } + errorString = QLibrary::tr("The plugin '%1' uses incompatible Qt library. (%2.%3.%4) [%5]") + .arg(fileName) + .arg((qt_version&0xff0000) >> 16) + .arg((qt_version&0xff00) >> 8) + .arg(qt_version&0xff) + .arg(debug ? QLatin1String("debug") : QLatin1String("release")); + } else if (key != QT_BUILD_KEY +#ifdef QT_BUILD_KEY_COMPAT + // be sure to load plugins using an older but compatible build key + && key != QT_BUILD_KEY_COMPAT +#endif + ) { + if (qt_debug_component()) { + qWarning("In %s:\n" + " Plugin uses incompatible Qt library\n" + " expected build key \"%s\", got \"%s\"", + (const char*) QFile::encodeName(fileName), + QT_BUILD_KEY, + key.isEmpty() ? "<null>" : (const char *) key); + } + errorString = QLibrary::tr("The plugin '%1' uses incompatible Qt library." + " Expected build key \"%2\", got \"%3\"") + .arg(fileName) + .arg(QLatin1String(QT_BUILD_KEY)) + .arg(key.isEmpty() ? QLatin1String("<null>") : QLatin1String((const char *) key)); +#ifndef QT_NO_DEBUG_PLUGIN_CHECK + } else if(debug != QLIBRARY_AS_DEBUG) { + //don't issue a qWarning since we will hopefully find a non-debug? --Sam + errorString = QLibrary::tr("The plugin '%1' uses incompatible Qt library." + " (Cannot mix debug and release libraries.)").arg(fileName); +#endif + } else { + pluginState = IsAPlugin; + } + + return pluginState == IsAPlugin; +#else + Q_UNUSED(settings); + return pluginState == MightBeAPlugin; +#endif +} + +/*! + Loads the library and returns true if the library was loaded + successfully; otherwise returns false. Since resolve() always + calls this function before resolving any symbols it is not + necessary to call it explicitly. In some situations you might want + the library loaded in advance, in which case you would use this + function. + + \sa unload() +*/ +bool QLibrary::load() +{ + if (!d) + return false; + if (did_load) + return d->pHnd; + did_load = true; + return d->load(); +} + +/*! + Unloads the library and returns true if the library could be + unloaded; otherwise returns false. + + This happens automatically on application termination, so you + shouldn't normally need to call this function. + + If other instances of QLibrary are using the same library, the + call will fail, and unloading will only happen when every instance + has called unload(). + + Note that on Mac OS X 10.3 (Panther), dynamic libraries cannot be unloaded. + + \sa resolve(), load() +*/ +bool QLibrary::unload() +{ + if (did_load) { + did_load = false; + return d->unload(); + } + return false; +} + +/*! + Returns true if the library is loaded; otherwise returns false. + + \sa load() + */ +bool QLibrary::isLoaded() const +{ + return d && d->pHnd; +} + + +/*! + Constructs a library with the given \a parent. + */ +QLibrary::QLibrary(QObject *parent) + :QObject(parent), d(0), did_load(false) +{ +} + + +/*! + Constructs a library object with the given \a parent that will + load the library specified by \a fileName. + + We recommend omitting the file's suffix in \a fileName, since + QLibrary will automatically look for the file with the appropriate + suffix in accordance with the platform, e.g. ".so" on Unix, + ".dylib" on Mac OS X, and ".dll" on Windows. (See \l{fileName}.) + + Note: In Symbian the path portion of the \a fileName is ignored. + */ +QLibrary::QLibrary(const QString& fileName, QObject *parent) + :QObject(parent), d(0), did_load(false) +{ + setFileName(fileName); +} + + +/*! + Constructs a library object with the given \a parent that will + load the library specified by \a fileName and major version number \a verNum. + Currently, the version number is ignored on Windows and Symbian. + + We recommend omitting the file's suffix in \a fileName, since + QLibrary will automatically look for the file with the appropriate + suffix in accordance with the platform, e.g. ".so" on Unix, + ".dylib" on Mac OS X, and ".dll" on Windows. (See \l{fileName}.) + + Note: In Symbian the path portion of the \a fileName is ignored. +*/ +QLibrary::QLibrary(const QString& fileName, int verNum, QObject *parent) + :QObject(parent), d(0), did_load(false) +{ + setFileNameAndVersion(fileName, verNum); +} + +/*! + Constructs a library object with the given \a parent that will + load the library specified by \a fileName and full version number \a version. + Currently, the version number is ignored on Windows and Symbian. + + We recommend omitting the file's suffix in \a fileName, since + QLibrary will automatically look for the file with the appropriate + suffix in accordance with the platform, e.g. ".so" on Unix, + ".dylib" on Mac OS X, and ".dll" on Windows. (See \l{fileName}.) + + Note: In Symbian the path portion of the \a fileName is ignored. + */ +QLibrary::QLibrary(const QString& fileName, const QString &version, QObject *parent) + :QObject(parent), d(0), did_load(false) +{ + setFileNameAndVersion(fileName, version); +} + +/*! + Destroys the QLibrary object. + + Unless unload() was called explicitly, the library stays in memory + until the application terminates. + + \sa isLoaded(), unload() +*/ +QLibrary::~QLibrary() +{ + if (d) + d->release(); +} + + +/*! + \property QLibrary::fileName + \brief the file name of the library + + We recommend omitting the file's suffix in the file name, since + QLibrary will automatically look for the file with the appropriate + suffix (see isLibrary()). + + When loading the library, QLibrary searches in all system-specific + library locations (e.g. \c LD_LIBRARY_PATH on Unix), unless the + file name has an absolute path. After loading the library + successfully, fileName() returns the fully-qualified file name of + the library, including the full path to the library if one was given + in the constructor or passed to setFileName(). + + For example, after successfully loading the "GL" library on Unix + platforms, fileName() will return "libGL.so". If the file name was + originally passed as "/usr/lib/libGL", fileName() will return + "/usr/lib/libGL.so". + + Note: In Symbian the path portion of the \a fileName is ignored. +*/ + +void QLibrary::setFileName(const QString &fileName) +{ + QLibrary::LoadHints lh; + if (d) { + lh = d->loadHints; + d->release(); + d = 0; + did_load = false; + } + d = QLibraryPrivate::findOrCreate(fileName); + d->loadHints = lh; +} + +QString QLibrary::fileName() const +{ + if (d) + return d->qualifiedFileName.isEmpty() ? d->fileName : d->qualifiedFileName; + return QString(); +} + +/*! + \fn void QLibrary::setFileNameAndVersion(const QString &fileName, int versionNumber) + + Sets the fileName property and major version number to \a fileName + and \a versionNumber respectively. + The \a versionNumber is ignored on Windows and Symbian. + + Note: In Symbian the path portion of the \a fileName is ignored. + + \sa setFileName() +*/ +void QLibrary::setFileNameAndVersion(const QString &fileName, int verNum) +{ + QLibrary::LoadHints lh; + if (d) { + lh = d->loadHints; + d->release(); + d = 0; + did_load = false; + } + d = QLibraryPrivate::findOrCreate(fileName, verNum >= 0 ? QString::number(verNum) : QString()); + d->loadHints = lh; +} + +/*! + \since 4.4 + + Sets the fileName property and full version number to \a fileName + and \a version respectively. + The \a version parameter is ignored on Windows and Symbian. + + Note: In Symbian the path portion of the \a fileName is ignored. + + \sa setFileName() +*/ +void QLibrary::setFileNameAndVersion(const QString &fileName, const QString &version) +{ + QLibrary::LoadHints lh; + if (d) { + lh = d->loadHints; + d->release(); + d = 0; + did_load = false; + } + d = QLibraryPrivate::findOrCreate(fileName, version); + d->loadHints = lh; +} + +/*! + Returns the address of the exported symbol \a symbol. The library is + loaded if necessary. The function returns 0 if the symbol could + not be resolved or if the library could not be loaded. + + Example: + \snippet doc/src/snippets/code/src_corelib_plugin_qlibrary.cpp 2 + + The symbol must be exported as a C function from the library. This + means that the function must be wrapped in an \c{extern "C"} if + the library is compiled with a C++ compiler. On Windows you must + also explicitly export the function from the DLL using the + \c{__declspec(dllexport)} compiler directive, for example: + + \snippet doc/src/snippets/code/src_corelib_plugin_qlibrary.cpp 3 + + with \c MY_EXPORT defined as + + \snippet doc/src/snippets/code/src_corelib_plugin_qlibrary.cpp 4 + + Note: In Symbian resolving with symbol names works only if the loaded + library was built as STDDLL. Otherwise, the ordinals must be used. +*/ +void *QLibrary::resolve(const char *symbol) +{ + if (!load()) + return 0; + return d->resolve(symbol); +} + +/*! + \overload + + Loads the library \a fileName and returns the address of the + exported symbol \a symbol. Note that \a fileName should not + include the platform-specific file suffix; (see \l{fileName}). The + library remains loaded until the application exits. + + The function returns 0 if the symbol could not be resolved or if + the library could not be loaded. + + Note: In Symbian resolving with symbol names works only if the loaded + library was built as STDDLL. Otherwise, the ordinals must be used. + + \sa resolve() +*/ +void *QLibrary::resolve(const QString &fileName, const char *symbol) +{ + QLibrary library(fileName); + return library.resolve(symbol); +} + +/*! + \overload + + Loads the library \a fileName with major version number \a verNum and + returns the address of the exported symbol \a symbol. + Note that \a fileName should not include the platform-specific file suffix; + (see \l{fileName}). The library remains loaded until the application exits. + \a verNum is ignored on Windows. + + The function returns 0 if the symbol could not be resolved or if + the library could not be loaded. + + Note: In Symbian resolving with symbol names works only if the loaded + library was built as STDDLL. Otherwise, the ordinals must be used. + + \sa resolve() +*/ +void *QLibrary::resolve(const QString &fileName, int verNum, const char *symbol) +{ + QLibrary library(fileName, verNum); + return library.resolve(symbol); +} + +/*! + \overload + \since 4.4 + + Loads the library \a fileName with full version number \a version and + returns the address of the exported symbol \a symbol. + Note that \a fileName should not include the platform-specific file suffix; + (see \l{fileName}). The library remains loaded until the application exits. + \a version is ignored on Windows. + + The function returns 0 if the symbol could not be resolved or if + the library could not be loaded. + + Note: In Symbian resolving with symbol names works only if the loaded + library was built as STDDLL. Otherwise, the ordinals must be used. + + \sa resolve() +*/ +void *QLibrary::resolve(const QString &fileName, const QString &version, const char *symbol) +{ + QLibrary library(fileName, version); + return library.resolve(symbol); +} + +/*! + \fn QString QLibrary::library() const + + Use fileName() instead. +*/ + +/*! + \fn void QLibrary::setAutoUnload( bool b ) + + Use load(), isLoaded(), and unload() as necessary instead. +*/ + +/*! + \since 4.2 + + Returns a text string with the description of the last error that occurred. + Currently, errorString will only be set if load(), unload() or resolve() for some reason fails. +*/ +QString QLibrary::errorString() const +{ + return (!d || d->errorString.isEmpty()) ? tr("Unknown error") : d->errorString; +} + +/*! + \property QLibrary::loadHints + \brief Give the load() function some hints on how it should behave. + + You can give some hints on how the symbols are resolved. Usually, + the symbols are not resolved at load time, but resolved lazily, + (that is, when resolve() is called). If you set the loadHint to + ResolveAllSymbolsHint, then all symbols will be resolved at load time + if the platform supports it. + + Setting ExportExternalSymbolsHint will make the external symbols in the + library available for resolution in subsequent loaded libraries. + + If LoadArchiveMemberHint is set, the file name + is composed of two components: A path which is a reference to an + archive file followed by the second component which is the reference to + the archive member. For instance, the fileName \c libGL.a(shr_64.o) will refer + to the library \c shr_64.o in the archive file named \c libGL.a. This + is only supported on the AIX platform. + + The interpretation of the load hints is platform dependent, and if + you use it you are probably making some assumptions on which platform + you are compiling for, so use them only if you understand the consequences + of them. + + By default, none of these flags are set, so libraries will be loaded with + lazy symbol resolution, and will not export external symbols for resolution + in other dynamically-loaded libraries. +*/ +void QLibrary::setLoadHints(LoadHints hints) +{ + if (!d) { + d = QLibraryPrivate::findOrCreate(QString()); // ugly, but we need a d-ptr + d->errorString.clear(); + } + d->loadHints = hints; +} + +QLibrary::LoadHints QLibrary::loadHints() const +{ + return d ? d->loadHints : (QLibrary::LoadHints)0; +} + +/* Internal, for debugging */ +bool qt_debug_component() +{ +#if defined(QT_DEBUG_COMPONENT) + return true; //compatibility? +#else + static int debug_env = -1; + if (debug_env == -1) + debug_env = QT_PREPEND_NAMESPACE(qgetenv)("QT_DEBUG_PLUGINS").toInt(); + + return debug_env != 0; +#endif +} + +QT_END_NAMESPACE + +#endif // QT_NO_LIBRARY diff --git a/src/corelib/plugin/qlibrary.h b/src/corelib/plugin/qlibrary.h new file mode 100644 index 0000000..7e551e5 --- /dev/null +++ b/src/corelib/plugin/qlibrary.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLIBRARY_H +#define QLIBRARY_H + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#if defined(QT_NO_LIBRARY) && defined(Q_OS_WIN) +#undef QT_NO_LIBRARY +#pragma message("QT_NO_LIBRARY is not supported on Windows") +#endif + +#ifndef QT_NO_LIBRARY + +class QLibraryPrivate; + +class Q_CORE_EXPORT QLibrary : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString fileName READ fileName WRITE setFileName) + Q_PROPERTY(LoadHints loadHints READ loadHints WRITE setLoadHints) + Q_FLAGS(LoadHint LoadHints) +public: + enum LoadHint { + ResolveAllSymbolsHint = 0x01, + ExportExternalSymbolsHint = 0x02, + LoadArchiveMemberHint = 0x04 + }; + Q_DECLARE_FLAGS(LoadHints, LoadHint) + + explicit QLibrary(QObject *parent = 0); + explicit QLibrary(const QString& fileName, QObject *parent = 0); + explicit QLibrary(const QString& fileName, int verNum, QObject *parent = 0); + explicit QLibrary(const QString& fileName, const QString &version, QObject *parent = 0); + ~QLibrary(); + + void *resolve(const char *symbol); + static void *resolve(const QString &fileName, const char *symbol); + static void *resolve(const QString &fileName, int verNum, const char *symbol); + static void *resolve(const QString &fileName, const QString &version, const char *symbol); + + bool load(); + bool unload(); + bool isLoaded() const; + + static bool isLibrary(const QString &fileName); + + void setFileName(const QString &fileName); + QString fileName() const; + + void setFileNameAndVersion(const QString &fileName, int verNum); + void setFileNameAndVersion(const QString &fileName, const QString &version); + QString errorString() const; + + void setLoadHints(LoadHints hints); + LoadHints loadHints() const; +#ifdef QT3_SUPPORT + inline QT3_SUPPORT QString library() const { return fileName(); } + inline QT3_SUPPORT void setAutoUnload( bool ) {} +#endif +private: + QLibraryPrivate *d; + bool did_load; + Q_DISABLE_COPY(QLibrary) +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QLibrary::LoadHints) + +#endif //QT_NO_LIBRARY + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif //QLIBRARY_H diff --git a/src/corelib/plugin/qlibrary_p.h b/src/corelib/plugin/qlibrary_p.h new file mode 100644 index 0000000..36bde95 --- /dev/null +++ b/src/corelib/plugin/qlibrary_p.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLIBRARY_P_H +#define QLIBRARY_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QLibrary class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#ifdef Q_WS_WIN +# include "QtCore/qt_windows.h" +#endif +#include "QtCore/qlibrary.h" +#include "QtCore/qpointer.h" +#include "QtCore/qstringlist.h" +#include "QtCore/qplugin.h" + +#ifndef QT_NO_LIBRARY + +QT_BEGIN_NAMESPACE + +bool qt_debug_component(); + +class QSettings; +class QLibraryPrivate +{ +public: + +#ifdef Q_WS_WIN + HINSTANCE +#else + void * +#endif + pHnd; + + QString fileName, qualifiedFileName; + QString fullVersion; + + bool load(); + bool loadPlugin(); // loads and resolves instance + bool unload(); + void release(); + void *resolve(const char *); + + static QLibraryPrivate *findOrCreate(const QString &fileName, const QString &version = QString()); + + QtPluginInstanceFunction instance; + uint qt_version; + QString lastModified; + + QString errorString; + QLibrary::LoadHints loadHints; + + bool isPlugin(QSettings *settings = 0); + + +private: + explicit QLibraryPrivate(const QString &canonicalFileName, const QString &version); + ~QLibraryPrivate(); + + bool load_sys(); + bool unload_sys(); + void *resolve_sys(const char *); + + QAtomicInt libraryRefCount; + QAtomicInt libraryUnloadCount; + + enum {IsAPlugin, IsNotAPlugin, MightBeAPlugin } pluginState; + friend class QLibraryPrivateHasFriends; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_LIBRARY + +#endif // QLIBRARY_P_H diff --git a/src/corelib/plugin/qlibrary_unix.cpp b/src/corelib/plugin/qlibrary_unix.cpp new file mode 100644 index 0000000..c868d4a --- /dev/null +++ b/src/corelib/plugin/qlibrary_unix.cpp @@ -0,0 +1,289 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" + +#include <qfile.h> +#include "qlibrary_p.h" +#include <qfileinfo.h> +#include <qcoreapplication.h> + +#ifndef QT_NO_LIBRARY + +#ifdef Q_OS_MAC +# include <private/qcore_mac_p.h> +#endif + +#if defined(QT_AOUT_UNDERSCORE) +#include <string.h> +#endif + +QT_BEGIN_NAMESPACE + +#if !defined(QT_HPUX_LD) +QT_BEGIN_INCLUDE_NAMESPACE +#include <dlfcn.h> +QT_END_INCLUDE_NAMESPACE +#endif + +static QString qdlerror() +{ +#if !defined(QT_HPUX_LD) + const char *err = dlerror(); +#else + const char *err = strerror(errno); +#endif + return err ? QLatin1String("(")+QString::fromLocal8Bit(err) + QLatin1String(")"): QString(); +} + +bool QLibraryPrivate::load_sys() +{ + QFileInfo fi(fileName); + +#if defined(Q_OS_SYMBIAN) + QString path; // In Symbian, always resolve with just the filename + QString name; + + // Replace possible ".qtplugin" suffix with ".dll" + if (fi.suffix() == QLatin1String("qtplugin")) + name = fi.completeBaseName() + QLatin1String(".dll"); + else + name = fi.fileName(); +#else + QString path = fi.path(); + QString name = fi.fileName(); + if (path == QLatin1String(".") && !fileName.startsWith(path)) + path.clear(); + else + path += QLatin1Char('/'); +#endif + // The first filename we want to attempt to load is the filename as the callee specified. + // Thus, the first attempt we do must be with an empty prefix and empty suffix. + QStringList suffixes(QLatin1String("")), prefixes(QLatin1String("")); + if (pluginState != IsAPlugin) { +#if !defined(Q_OS_SYMBIAN) + prefixes << QLatin1String("lib"); +#endif +#if defined(Q_OS_HPUX) + // according to + // http://docs.hp.com/en/B2355-90968/linkerdifferencesiapa.htm + + // In PA-RISC (PA-32 and PA-64) shared libraries are suffixed + // with .sl. In IPF (32-bit and 64-bit), the shared libraries + // are suffixed with .so. For compatibility, the IPF linker + // also supports the .sl suffix. + + // But since we don't know if we are built on HPUX or HPUXi, + // we support both .sl (and .<version>) and .so suffixes but + // .so is preferred. +# if defined(__ia64) + if (!fullVersion.isEmpty()) { + suffixes << QString::fromLatin1(".so.%1").arg(fullVersion); + } else { + suffixes << QLatin1String(".so"); + } +# endif + if (!fullVersion.isEmpty()) { + suffixes << QString::fromLatin1(".sl.%1").arg(fullVersion); + suffixes << QString::fromLatin1(".%1").arg(fullVersion); + } else { + suffixes << QLatin1String(".sl"); + } +#elif defined(Q_OS_AIX) + suffixes << ".a"; + +#elif defined(Q_OS_SYMBIAN) + suffixes << QLatin1String(".dll"); +#else + if (!fullVersion.isEmpty()) { + suffixes << QString::fromLatin1(".so.%1").arg(fullVersion); + } else { + suffixes << QLatin1String(".so"); + } +#endif +# ifdef Q_OS_MAC + if (!fullVersion.isEmpty()) { + suffixes << QString::fromLatin1(".%1.bundle").arg(fullVersion); + suffixes << QString::fromLatin1(".%1.dylib").arg(fullVersion); + } else { + suffixes << QLatin1String(".bundle") << QLatin1String(".dylib"); + } +#endif + } + int dlFlags = 0; +#if defined(QT_HPUX_LD) + dlFlags = DYNAMIC_PATH | BIND_NONFATAL; + if (loadHints & QLibrary::ResolveAllSymbolsHint) { + dlFlags |= BIND_IMMEDIATE; + } else { + dlFlags |= BIND_DEFERRED; + } +#else + if (loadHints & QLibrary::ResolveAllSymbolsHint) { + dlFlags |= RTLD_NOW; + } else { + dlFlags |= RTLD_LAZY; + } + if (loadHints & QLibrary::ExportExternalSymbolsHint) { + dlFlags |= RTLD_GLOBAL; + } +#if !defined(Q_OS_CYGWIN) + else { +#if defined(Q_OS_MAC) + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) +#endif + dlFlags |= RTLD_LOCAL; + } +#endif +#if defined(Q_OS_AIX) // Not sure if any other platform actually support this thing. + if (loadHints & QLibrary::LoadArchiveMemberHint) { + dlFlags |= RTLD_MEMBER; + } +#endif +#endif // QT_HPUX_LD + QString attempt; + bool retry = true; + for(int prefix = 0; retry && !pHnd && prefix < prefixes.size(); prefix++) { + for(int suffix = 0; retry && !pHnd && suffix < suffixes.size(); suffix++) { + if (!prefixes.at(prefix).isEmpty() && name.startsWith(prefixes.at(prefix))) + continue; + if (!suffixes.at(suffix).isEmpty() && name.endsWith(suffixes.at(suffix))) + continue; + if (loadHints & QLibrary::LoadArchiveMemberHint) { + attempt = name; + int lparen = attempt.indexOf(QLatin1Char('(')); + if (lparen == -1) + lparen = attempt.count(); + attempt = path + prefixes.at(prefix) + attempt.insert(lparen, suffixes.at(suffix)); + } else { + attempt = path + prefixes.at(prefix) + name + suffixes.at(suffix); + } +#if defined(QT_HPUX_LD) + pHnd = (void*)shl_load(QFile::encodeName(attempt), dlFlags, 0); +#else + pHnd = dlopen(QFile::encodeName(attempt), dlFlags); +#endif + +#if defined(Q_OS_SYMBIAN) + // Never try again in symbian, dlopen already handles the library search logic, + // and there is only one possible suffix. + retry = false; +#else + if (!pHnd && fileName.startsWith(QLatin1Char('/')) && QFile::exists(attempt)) { + // We only want to continue if dlopen failed due to that the shared library did not exist. + // However, we are only able to apply this check for absolute filenames (since they are + // not influenced by the content of LD_LIBRARY_PATH, /etc/ld.so.cache, DT_RPATH etc...) + // This is all because dlerror is flawed and cannot tell us the reason why it failed. + retry = false; + } +#endif + } + } + +#ifdef Q_OS_MAC + if (!pHnd) { + if (CFBundleRef bundle = CFBundleGetBundleWithIdentifier(QCFString(fileName))) { + QCFType<CFURLRef> url = CFBundleCopyExecutableURL(bundle); + QCFString str = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); + pHnd = dlopen(QFile::encodeName(str), dlFlags); + attempt = str; + } + } +# endif + if (!pHnd) { + errorString = QLibrary::tr("Cannot load library %1: %2").arg(fileName).arg(qdlerror()); + } + if (pHnd) { + qualifiedFileName = attempt; + errorString.clear(); + } + return (pHnd != 0); +} + +bool QLibraryPrivate::unload_sys() +{ +#if defined(QT_HPUX_LD) + if (shl_unload((shl_t)pHnd)) { +#else + if (dlclose(pHnd)) { +#endif + errorString = QLibrary::tr("Cannot unload library %1: %2").arg(fileName).arg(qdlerror()); + return false; + } + errorString.clear(); + return true; +} + +#ifdef Q_OS_MAC +Q_CORE_EXPORT void *qt_mac_resolve_sys(void *handle, const char *symbol) +{ + return dlsym(handle, symbol); +} +#endif + +void* QLibraryPrivate::resolve_sys(const char* symbol) +{ +#if defined(QT_AOUT_UNDERSCORE) + // older a.out systems add an underscore in front of symbols + char* undrscr_symbol = new char[strlen(symbol)+2]; + undrscr_symbol[0] = '_'; + strcpy(undrscr_symbol+1, symbol); + void* address = dlsym(pHnd, undrscr_symbol); + delete [] undrscr_symbol; +#elif defined(QT_HPUX_LD) + void* address = 0; + if (shl_findsym((shl_t*)&pHnd, symbol, TYPE_UNDEFINED, &address) < 0) + address = 0; +#else + void* address = dlsym(pHnd, symbol); +#endif + if (!address) { + errorString = QLibrary::tr("Cannot resolve symbol \"%1\" in %2: %3").arg( + QString::fromAscii(symbol)).arg(fileName).arg(qdlerror()); + } else { + errorString.clear(); + } + return address; +} + +QT_END_NAMESPACE + +#endif // QT_NO_LIBRARY diff --git a/src/corelib/plugin/qlibrary_win.cpp b/src/corelib/plugin/qlibrary_win.cpp new file mode 100644 index 0000000..bbd698d --- /dev/null +++ b/src/corelib/plugin/qlibrary_win.cpp @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" +#include "qlibrary_p.h" +#include "qfile.h" +#include "qdir.h" +#include "qfileinfo.h" +#include "qdir.h" + +#if defined(QT_NO_LIBRARY) && defined(Q_OS_WIN) +#undef QT_NO_LIBRARY +#pragma message("QT_NO_LIBRARY is not supported on Windows") +#endif + +#include "qt_windows.h" + +QT_BEGIN_NAMESPACE + +extern QString qt_error_string(int code); + +bool QLibraryPrivate::load_sys() +{ +#ifdef Q_OS_WINCE + QString attempt = QFileInfo(fileName).absoluteFilePath(); +#else + QString attempt = fileName; +#endif + + //avoid 'Bad Image' message box + UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + QT_WA({ + pHnd = LoadLibraryW((TCHAR*)QDir::toNativeSeparators(attempt).utf16()); + } , { + pHnd = LoadLibraryA(QFile::encodeName(QDir::toNativeSeparators(attempt)).data()); + }); + + if (pluginState != IsAPlugin) { +#if defined(Q_OS_WINCE) + if (!pHnd && ::GetLastError() == ERROR_MOD_NOT_FOUND) { + QString secondAttempt = fileName; + QT_WA({ + pHnd = LoadLibraryW((TCHAR*)QDir::toNativeSeparators(secondAttempt).utf16()); + } , { + pHnd = LoadLibraryA(QFile::encodeName(QDir::toNativeSeparators(secondAttempt)).data()); + }); + } +#endif + if (!pHnd && ::GetLastError() == ERROR_MOD_NOT_FOUND) { + attempt += QLatin1String(".dll"); + QT_WA({ + pHnd = LoadLibraryW((TCHAR*)QDir::toNativeSeparators(attempt).utf16()); + } , { + pHnd = LoadLibraryA(QFile::encodeName(QDir::toNativeSeparators(attempt)).data()); + }); + } + } + + SetErrorMode(oldmode); + if (!pHnd) { + errorString = QLibrary::tr("Cannot load library %1: %2").arg(fileName).arg(qt_error_string()); + } + if (pHnd) { + errorString.clear(); + QT_WA({ + TCHAR buffer[MAX_PATH + 1]; + ::GetModuleFileNameW(pHnd, buffer, MAX_PATH); + attempt = QString::fromUtf16(reinterpret_cast<const ushort *>(&buffer)); + }, { + char buffer[MAX_PATH + 1]; + ::GetModuleFileNameA(pHnd, buffer, MAX_PATH); + attempt = QString::fromLocal8Bit(buffer); + }); + const QDir dir = QFileInfo(fileName).dir(); + const QString realfilename = attempt.mid(attempt.lastIndexOf(QLatin1Char('\\')) + 1); + if (dir.path() == QLatin1String(".")) + qualifiedFileName = realfilename; + else + qualifiedFileName = dir.filePath(realfilename); + } + return (pHnd != 0); +} + +bool QLibraryPrivate::unload_sys() +{ + if (!FreeLibrary(pHnd)) { + errorString = QLibrary::tr("Cannot unload library %1: %2").arg(fileName).arg(qt_error_string()); + return false; + } + errorString.clear(); + return true; +} + +void* QLibraryPrivate::resolve_sys(const char* symbol) +{ +#ifdef Q_OS_WINCE + void* address = (void*)GetProcAddress(pHnd, (const wchar_t*)QString::fromLatin1(symbol).utf16()); +#else + void* address = (void*)GetProcAddress(pHnd, symbol); +#endif + if (!address) { + errorString = QLibrary::tr("Cannot resolve symbol \"%1\" in %2: %3").arg( + QString::fromAscii(symbol)).arg(fileName).arg(qt_error_string()); + } else { + errorString.clear(); + } + return address; +} +QT_END_NAMESPACE diff --git a/src/corelib/plugin/qplugin.h b/src/corelib/plugin/qplugin.h new file mode 100644 index 0000000..4d0e53c --- /dev/null +++ b/src/corelib/plugin/qplugin.h @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPLUGIN_H +#define QPLUGIN_H + +#include <QtCore/qobject.h> +#include <QtCore/qpointer.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +#ifndef Q_EXTERN_C +# ifdef __cplusplus +# define Q_EXTERN_C extern "C" +# else +# define Q_EXTERN_C extern +# endif +#endif + +typedef QObject *(*QtPluginInstanceFunction)(); + +void Q_CORE_EXPORT qRegisterStaticPluginInstanceFunction(QtPluginInstanceFunction function); + +#define Q_IMPORT_PLUGIN(PLUGIN) \ + extern QT_PREPEND_NAMESPACE(QObject) *qt_plugin_instance_##PLUGIN(); \ + class Static##PLUGIN##PluginInstance{ \ + public: \ + Static##PLUGIN##PluginInstance() { \ + qRegisterStaticPluginInstanceFunction(qt_plugin_instance_##PLUGIN); \ + } \ + }; \ + static Static##PLUGIN##PluginInstance static##PLUGIN##Instance; + +#define Q_PLUGIN_INSTANCE(IMPLEMENTATION) \ + { \ + static QT_PREPEND_NAMESPACE(QPointer)<QT_PREPEND_NAMESPACE(QObject)> _instance; \ + if (!_instance) \ + _instance = new IMPLEMENTATION; \ + return _instance; \ + } + +# define Q_EXPORT_PLUGIN(PLUGIN) \ + Q_EXPORT_PLUGIN2(PLUGIN, PLUGIN) + +# define Q_EXPORT_STATIC_PLUGIN(PLUGIN) \ + Q_EXPORT_STATIC_PLUGIN2(PLUGIN, PLUGIN) + +#if defined(QT_STATICPLUGIN) + +# define Q_EXPORT_PLUGIN2(PLUGIN, PLUGINCLASS) \ + QT_PREPEND_NAMESPACE(QObject) \ + *qt_plugin_instance_##PLUGIN() \ + Q_PLUGIN_INSTANCE(PLUGINCLASS) + +# define Q_EXPORT_STATIC_PLUGIN2(PLUGIN, PLUGINCLASS) \ + Q_EXPORT_PLUGIN2(PLUGIN, PLUGINCLASS) + +#else +// NOTE: if you change pattern, you MUST change the pattern in +// qlibrary.cpp as well. changing the pattern will break all +// backwards compatibility as well (no old plugins will be loaded). +# ifdef QPLUGIN_DEBUG_STR +# undef QPLUGIN_DEBUG_STR +# endif +# ifdef QT_NO_DEBUG +# define QPLUGIN_DEBUG_STR "false" +# else +# define QPLUGIN_DEBUG_STR "true" +# endif +# define Q_PLUGIN_VERIFICATION_DATA \ + static const char *qt_plugin_verification_data = \ + "pattern=""QT_PLUGIN_VERIFICATION_DATA""\n" \ + "version="QT_VERSION_STR"\n" \ + "debug="QPLUGIN_DEBUG_STR"\n" \ + "buildkey="QT_BUILD_KEY"\0"; + +# if defined (Q_OS_WIN32) && defined(Q_CC_BOR) +# define Q_STANDARD_CALL __stdcall +# else +# define Q_STANDARD_CALL +# endif + +# define Q_EXPORT_PLUGIN2(PLUGIN, PLUGINCLASS) \ + Q_PLUGIN_VERIFICATION_DATA \ + Q_EXTERN_C Q_DECL_EXPORT \ + const char * Q_STANDARD_CALL qt_plugin_query_verification_data() \ + { return qt_plugin_verification_data; } \ + Q_EXTERN_C Q_DECL_EXPORT QT_PREPEND_NAMESPACE(QObject) * Q_STANDARD_CALL qt_plugin_instance() \ + Q_PLUGIN_INSTANCE(PLUGINCLASS) + +# define Q_EXPORT_STATIC_PLUGIN2(PLUGIN, PLUGINCLASS) + +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // Q_PLUGIN_H diff --git a/src/corelib/plugin/qpluginloader.cpp b/src/corelib/plugin/qpluginloader.cpp new file mode 100644 index 0000000..a911f1d --- /dev/null +++ b/src/corelib/plugin/qpluginloader.cpp @@ -0,0 +1,402 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" + +#include "qplugin.h" +#include "qpluginloader.h" +#include <qfileinfo.h> +#include "qlibrary_p.h" +#include "qdebug.h" + +#ifndef QT_NO_LIBRARY + +QT_BEGIN_NAMESPACE + +/*! + \class QPluginLoader + \reentrant + \brief The QPluginLoader class loads a plugin at run-time. + + \mainclass + \ingroup plugins + + QPluginLoader provides access to a \l{How to Create Qt + Plugins}{Qt plugin}. A Qt plugin is stored in a shared library (a + DLL) and offers these benefits over shared libraries accessed + using QLibrary: + + \list + \o QPluginLoader checks that a plugin is linked against the same + version of Qt as the application. + \o QPluginLoader provides direct access to a root component object + (instance()), instead of forcing you to resolve a C function manually. + \endlist + + An instance of a QPluginLoader object operates on a single shared + library file, which we call a plugin. It provides access to the + functionality in the plugin in a platform-independent way. To + specify which plugin to load, either pass a file name in + the constructor or set it with setFileName(). + + The most important functions are load() to dynamically load the + plugin file, isLoaded() to check whether loading was successful, + and instance() to access the root component in the plugin. The + instance() function implicitly tries to load the plugin if it has + not been loaded yet. Multiple instances of QPluginLoader can be + used to access the same physical plugin. + + Once loaded, plugins remain in memory until all instances of + QPluginLoader has been unloaded, or until the application + terminates. You can attempt to unload a plugin using unload(), + but if other instances of QPluginLoader are using the same + library, the call will fail, and unloading will only happen when + every instance has called unload(). Right before the unloading + happen, the root component will also be deleted. + + In order to speed up loading and validation of plugins, some of + the information that is collected during loading is cached in + persistent memory (through QSettings). For instance, the result + of a load operation (e.g. succeeded or failed) is stored in the + cache, so that subsequent load operations don't try to load an + invalid plugin. However, if the "last modified" timestamp of + a plugin has changed, the plugin's cache entry is invalidated + and the plugin is reloaded regardless of the values in the cache + entry. The cache entry is then updated with the new result of the + load operation. + + This also means that the timestamp must be updated each time the + plugin or any dependent resources (such as a shared library) is + updated, since the dependent resources might influence the result + of loading a plugin. + + See \l{How to Create Qt Plugins} for more information about + how to make your application extensible through plugins. + + Note that the QPluginLoader cannot be used if your application is + statically linked against Qt. In this case, you will also have to + link to plugins statically. You can use QLibrary if you need to + load dynamic libraries in a statically linked application. + + \note In Symbian the plugin stub files must be used whenever a + path to plugin is needed. For the purposes of loading plugins, + the stubs can be considered to have the same name as the actual + plugin binary. In practice they have ".qtplugin" extension + instead of ".dll", but this difference is handled transparently + by QPluginLoader and QLibrary to avoid need for Symbian specific + plugin handling in most Qt applications. Plugin stubs are needed + because Symbian Platform Security denies all access to the directory + where the actual plugin binaries are located. + + \sa QLibrary, {Plug & Paint Example} +*/ + +/*! + Constructs a plugin loader with the given \a parent. +*/ +QPluginLoader::QPluginLoader(QObject *parent) + : QObject(parent), d(0), did_load(false) +{ +} + +/*! + Constructs a plugin loader with the given \a parent that will + load the plugin specified by \a fileName. + + To be loadable, the file's suffix must be a valid suffix for a + loadable library in accordance with the platform, e.g. \c .so on + Unix, - \c .dylib on Mac OS X, and \c .dll on Windows. The suffix + can be verified with QLibrary::isLibrary(). + + Note: In Symbian the \a fileName must point to plugin stub file. + + \sa setFileName() +*/ +QPluginLoader::QPluginLoader(const QString &fileName, QObject *parent) + : QObject(parent), d(0), did_load(false) +{ + setFileName(fileName); +} + +/*! + Destroys the QPluginLoader object. + + Unless unload() was called explicitly, the plugin stays in memory + until the application terminates. + + \sa isLoaded(), unload() +*/ +QPluginLoader::~QPluginLoader() +{ + if (d) + d->release(); +} + +/*! + Returns the root component object of the plugin. The plugin is + loaded if necessary. The function returns 0 if the plugin could + not be loaded or if the root component object could not be + instantiated. + + If the root component object was destroyed, calling this function + creates a new instance. + + The root component, returned by this function, is not deleted when + the QPluginLoader is destroyed. If you want to ensure that the root + component is deleted, you should call unload() as soon you don't + need to access the core component anymore. When the library is + finally unloaded, the root component will automatically be deleted. + + The component object is a QObject. Use qobject_cast() to access + interfaces you are interested in. + + \sa load() +*/ +QObject *QPluginLoader::instance() +{ + if (!load()) + return 0; + if (d->instance) + return d->instance(); + return 0; +} + +/*! + Loads the plugin and returns true if the plugin was loaded + successfully; otherwise returns false. Since instance() always + calls this function before resolving any symbols it is not + necessary to call it explicitly. In some situations you might want + the plugin loaded in advance, in which case you would use this + function. + + \sa unload() +*/ +bool QPluginLoader::load() +{ + if (!d || d->fileName.isEmpty()) + return false; + if (did_load) + return d->pHnd && d->instance; + if (!d->isPlugin()) + return false; + did_load = true; + return d->loadPlugin(); +} + + +/*! + Unloads the plugin and returns true if the plugin could be + unloaded; otherwise returns false. + + This happens automatically on application termination, so you + shouldn't normally need to call this function. + + If other instances of QPluginLoader are using the same plugin, the + call will fail, and unloading will only happen when every instance + has called unload(). + + Don't try to delete the root component. Instead rely on + that unload() will automatically delete it when needed. + + \sa instance(), load() +*/ +bool QPluginLoader::unload() +{ + if (did_load) { + did_load = false; + return d->unload(); + } + if (d) // Ouch + d->errorString = tr("The plugin was not loaded."); + return false; +} + +/*! + Returns true if the plugin is loaded; otherwise returns false. + + \sa load() + */ +bool QPluginLoader::isLoaded() const +{ + return d && d->pHnd && d->instance; +} + +/*! + \property QPluginLoader::fileName + \brief the file name of the plugin + + To be loadable, the file's suffix must be a valid suffix for a + loadable library in accordance with the platform, e.g. \c .so on + Unix, \c .dylib on Mac OS X, and \c .dll on Windows. The suffix + can be verified with QLibrary::isLibrary(). + + If the file name does not exist, it will not be set. This property + will then contain an empty string. + + By default, this property contains an empty string. + + Note: In Symbian the \a fileName must point to plugin stub file. + + \sa load() +*/ +void QPluginLoader::setFileName(const QString &fileName) +{ +#if defined(QT_SHARED) + QLibrary::LoadHints lh; + if (d) { + lh = d->loadHints; + d->release(); + d = 0; + did_load = false; + } + +#if defined(Q_OS_SYMBIAN) + // In Symbian we actually look for plugin stub, so modify the filename + // to make canonicalFilePath find the file, if .dll is specified. + QFileInfo fi(fileName); + + if (fi.suffix() == QLatin1String("dll")) { + QString stubName = fileName; + stubName.chop(3); + stubName += QLatin1String("qtplugin"); + fi = QFileInfo(stubName); + } + + QString fn = fi.canonicalFilePath(); +#else + QString fn = QFileInfo(fileName).canonicalFilePath(); +#endif + + d = QLibraryPrivate::findOrCreate(fn); + d->loadHints = lh; + if (fn.isEmpty()) + d->errorString = QLibrary::tr("The shared library was not found."); +#else + if (qt_debug_component()) { + qWarning("Cannot load %s into a statically linked Qt library.", + (const char*)QFile::encodeName(fileName)); + } + Q_UNUSED(fileName); +#endif +} + +QString QPluginLoader::fileName() const +{ + if (d) + return d->fileName; + return QString(); +} + +/*! + \since 4.2 + + Returns a text string with the description of the last error that occurred. +*/ +QString QPluginLoader::errorString() const +{ + return (!d || d->errorString.isEmpty()) ? tr("Unknown error") : d->errorString; +} + +typedef QList<QtPluginInstanceFunction> StaticInstanceFunctionList; +Q_GLOBAL_STATIC(StaticInstanceFunctionList, staticInstanceFunctionList) + +/*! \since 4.4 + + \property QPluginLoader::loadHints + \brief Give the load() function some hints on how it should behave. + + You can give hints on how the symbols in the plugin are + resolved. By default, none of the hints are set. + + See the documentation of QLibrary::loadHints for a complete + description of how this property works. + + \sa QLibrary::loadHints +*/ + +void QPluginLoader::setLoadHints(QLibrary::LoadHints loadHints) +{ + if (!d) { + d = QLibraryPrivate::findOrCreate(QString()); // ugly, but we need a d-ptr + d->errorString.clear(); + } + d->loadHints = loadHints; +} + +QLibrary::LoadHints QPluginLoader::loadHints() const +{ + if (!d) { + QPluginLoader *that = const_cast<QPluginLoader *>(this); + that->d = QLibraryPrivate::findOrCreate(QString()); // ugly, but we need a d-ptr + that->d->errorString.clear(); + } + return d->loadHints; +} + +/*! + \relates QPluginLoader + \since 4.4 + + Registers the given \a function with the plugin loader. +*/ +void Q_CORE_EXPORT qRegisterStaticPluginInstanceFunction(QtPluginInstanceFunction function) +{ + staticInstanceFunctionList()->append(function); +} + +/*! + Returns a list of static plugin instances (root components) held + by the plugin loader. +*/ +QObjectList QPluginLoader::staticInstances() +{ + QObjectList instances; + StaticInstanceFunctionList *functions = staticInstanceFunctionList(); + if (functions) { + for (int i = 0; i < functions->count(); ++i) + instances.append((*functions)[i]()); + } + return instances; +} + +QT_END_NAMESPACE + +#endif // QT_NO_LIBRARY diff --git a/src/corelib/plugin/qpluginloader.h b/src/corelib/plugin/qpluginloader.h new file mode 100644 index 0000000..7b8b9ed --- /dev/null +++ b/src/corelib/plugin/qpluginloader.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPLUGINLOADER_H +#define QPLUGINLOADER_H + +#include <QtCore/qlibrary.h> + +#if defined(QT_NO_LIBRARY) && defined(Q_OS_WIN) +#undef QT_NO_LIBRARY +#pragma message("QT_NO_LIBRARY is not supported on Windows") +#endif + +#ifndef QT_NO_LIBRARY + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QLibraryPrivate; + +class Q_CORE_EXPORT QPluginLoader : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString fileName READ fileName WRITE setFileName) + Q_PROPERTY(QLibrary::LoadHints loadHints READ loadHints WRITE setLoadHints) +public: + explicit QPluginLoader(QObject *parent = 0); + explicit QPluginLoader(const QString &fileName, QObject *parent = 0); + ~QPluginLoader(); + + QObject *instance(); + + static QObjectList staticInstances(); + + bool load(); + bool unload(); + bool isLoaded() const; + + void setFileName(const QString &fileName); + QString fileName() const; + + QString errorString() const; + + void setLoadHints(QLibrary::LoadHints loadHints); + QLibrary::LoadHints loadHints() const; + +private: + QLibraryPrivate *d; + bool did_load; + Q_DISABLE_COPY(QPluginLoader) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_LIBRARY + +#endif //QPLUGINLOADER_H diff --git a/src/corelib/plugin/quuid.cpp b/src/corelib/plugin/quuid.cpp new file mode 100644 index 0000000..4365c98 --- /dev/null +++ b/src/corelib/plugin/quuid.cpp @@ -0,0 +1,624 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "quuid.h" + +#include "qdatastream.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QUuid + \brief The QUuid class stores a Universally Unique Identifier (UUID). + + \reentrant + \ingroup misc + + Using \e{U}niversally \e{U}nique \e{ID}entifiers (UUID) is a + standard way to uniquely identify entities in a distributed + computing environment. A UUID is a 16-byte (128-bit) number + generated by some algorithm that is meant to guarantee that the + UUID will be unique in the distributed computing environment where + it is used. The acronym GUID is often used instead, \e{G}lobally + \e{U}nique \e{ID}entifiers, but it refers to the same thing. + + \target Variant field + Actually, the GUID is one \e{variant} of UUID. Multiple variants + are in use. Each UUID contains a bit field that specifies which + type (variant) of UUID it is. Call variant() to discover which + type of UUID an instance of QUuid contains. It extracts the three + most signifcant bits of byte 8 of the 16 bytes. In QUuid, byte 8 + is \c{QUuid::data4[0]}. If you create instances of QUuid using the + constructor that accepts all the numeric values as parameters, use + the following table to set the three most significant bits of + parameter \c{b1}, which becomes \c{QUuid::data4[0]} and contains + the variant field in its three most significant bits. In the + table, 'x' means \e {don't care}. + + \table + \header + \o msb0 + \o msb1 + \o msb2 + \o Variant + + \row + \o 0 + \o x + \o x + \o NCS (Network Computing System) + + \row + \o 1 + \o 0 + \o x + \o DCE (Distributed Computing Environment) + + \row + \o 1 + \o 1 + \o 0 + \o Microsoft (GUID) + + \row + \o 1 + \o 1 + \o 1 + \o Reserved for future expansion + + \endtable + + \target Version field + If variant() returns QUuid::DCE, the UUID also contains a + \e{version} field in the four most significant bits of + \c{QUuid::data3}, and you can call version() to discover which + version your QUuid contains. If you create instances of QUuid + using the constructor that accepts all the numeric values as + parameters, use the following table to set the four most + significant bits of parameter \c{w2}, which becomes + \c{QUuid::data3} and contains the version field in its four most + significant bits. + + \table + \header + \o msb0 + \o msb1 + \o msb2 + \o msb3 + \o Version + + \row + \o 0 + \o 0 + \o 0 + \o 1 + \o Time + + \row + \o 0 + \o 0 + \o 1 + \o 0 + \o Embedded POSIX + + \row + \o 0 + \o 0 + \o 1 + \o 1 + \o Name + + \row + \o 0 + \o 1 + \o 0 + \o 0 + \o Random + + \endtable + + The field layouts for the DCE versions listed in the table above + are specified in the \l{http://www.ietf.org/rfc/rfc4122.txt} + {Network Working Group UUID Specification}. + + Most platforms provide a tool for generating new UUIDs, e.g. \c + uuidgen and \c guidgen. You can also use createUuid(). UUIDs + generated by createUuid() are of the random type. Their + QUuid::Version bits are set to QUuid::Random, and their + QUuid::Variant bits are set to QUuid::DCE. The rest of the UUID is + composed of random numbers. Theoretically, this means there is a + small chance that a UUID generated by createUuid() will not be + unique. But it is + \l{http://en.wikipedia.org/wiki/Universally_Unique_Identifier#Random_UUID_probability_of_duplicates} + {a \e{very} small chance}. + + UUIDs can be constructed from numeric values or from strings, or + using the static createUuid() function. They can be converted to a + string with toString(). UUIDs have a variant() and a version(), + and null UUIDs return true from isNull(). +*/ + +/*! + \fn QUuid::QUuid(const GUID &guid) + + Casts a Windows \a guid to a Qt QUuid. + + \warning This function is only for Windows platforms. +*/ + +/*! + \fn QUuid &QUuid::operator=(const GUID &guid) + + Assigns a Windows \a guid to a Qt QUuid. + + \warning This function is only for Windows platforms. +*/ + +/*! + \fn QUuid::operator GUID() const + + Returns a Windows GUID from a QUuid. + + \warning This function is only for Windows platforms. +*/ + +/*! + \fn QUuid::QUuid() + + Creates the null UUID. toString() will output the null UUID + as "{00000000-0000-0000-0000-000000000000}". +*/ + +/*! + \fn QUuid::QUuid(uint l, ushort w1, ushort w2, uchar b1, uchar b2, uchar b3, uchar b4, uchar b5, uchar b6, uchar b7, uchar b8) + + Creates a UUID with the value specified by the parameters, \a l, + \a w1, \a w2, \a b1, \a b2, \a b3, \a b4, \a b5, \a b6, \a b7, \a + b8. + + Example: + \snippet doc/src/snippets/code/src_corelib_plugin_quuid.cpp 0 +*/ + +#ifndef QT_NO_QUUID_STRING +/*! + Creates a QUuid object from the string \a text, which must be + formatted as five hex fields separated by '-', e.g., + "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where 'x' is a hex + digit. The curly braces shown here are optional, but it is normal to + include them. If the conversion fails, a null UUID is created. See + toString() for an explanation of how the five hex fields map to the + public data members in QUuid. + + \sa toString(), QUuid() +*/ +QUuid::QUuid(const QString &text) +{ + bool ok; + if (text.isEmpty()) { + *this = QUuid(); + return; + } + QString temp = text.toUpper(); + if (temp[0] != QLatin1Char('{')) + temp = QLatin1Char('{') + text; + if (text[(int)text.length()-1] != QLatin1Char('}')) + temp += QLatin1Char('}'); + + data1 = temp.mid(1, 8).toULongLong(&ok, 16); + if (!ok) { + *this = QUuid(); + return; + } + + data2 = temp.mid(10, 4).toUInt(&ok, 16); + if (!ok) { + *this = QUuid(); + return; + } + data3 = temp.mid(15, 4).toUInt(&ok, 16); + if (!ok) { + *this = QUuid(); + return; + } + data4[0] = temp.mid(20, 2).toUInt(&ok, 16); + if (!ok) { + *this = QUuid(); + return; + } + data4[1] = temp.mid(22, 2).toUInt(&ok, 16); + if (!ok) { + *this = QUuid(); + return; + } + for (int i = 2; i<8; i++) { + data4[i] = temp.mid(25 + (i-2)*2, 2).toUShort(&ok, 16); + if (!ok) { + *this = QUuid(); + return; + } + } +} + +/*! + \internal +*/ +QUuid::QUuid(const char *text) +{ + *this = QUuid(QString::fromLatin1(text)); +} +#endif + +/*! + \fn bool QUuid::operator==(const QUuid &other) const + + Returns true if this QUuid and the \a other QUuid are identical; + otherwise returns false. +*/ + +/*! + \fn bool QUuid::operator!=(const QUuid &other) const + + Returns true if this QUuid and the \a other QUuid are different; + otherwise returns false. +*/ +#ifndef QT_NO_QUUID_STRING +/*! + \fn QUuid::operator QString() const + + Returns the string representation of the uuid. + + \sa toString() +*/ + +static QString uuidhex(uint data, int digits) +{ + return QString::number(data, 16).rightJustified(digits, QLatin1Char('0')); +} + +/*! + Returns the string representation of this QUuid. The string is + formatted as five hex fields separated by '-' and enclosed in + curly braces, i.e., "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" where + 'x' is a hex digit. From left to right, the five hex fields are + obtained from the four public data members in QUuid as follows: + + \table + \header + \o Field # + \o Source + + \row + \o 1 + \o data1 + + \row + \o 2 + \o data2 + + \row + \o 3 + \o data3 + + \row + \o 4 + \o data4[0] .. data4[1] + + \row + \o 5 + \o data4[2] .. data4[7] + + \endtable +*/ +QString QUuid::toString() const +{ + QString result; + + QChar dash = QLatin1Char('-'); + result = QLatin1Char('{') + uuidhex(data1,8); + result += dash; + result += uuidhex(data2,4); + result += dash; + result += uuidhex(data3,4); + result += dash; + result += uuidhex(data4[0],2); + result += uuidhex(data4[1],2); + result += dash; + for (int i = 2; i < 8; i++) + result += uuidhex(data4[i],2); + + return result + QLatin1Char('}'); +} +#endif + +#ifndef QT_NO_DATASTREAM +/*! + \relates QUuid + Writes the UUID \a id to the data stream \a s. +*/ +QDataStream &operator<<(QDataStream &s, const QUuid &id) +{ + s << (quint32)id.data1; + s << (quint16)id.data2; + s << (quint16)id.data3; + for (int i = 0; i < 8; i++) + s << (quint8)id.data4[i]; + return s; +} + +/*! + \relates QUuid + Reads a UUID from the stream \a s into \a id. +*/ +QDataStream &operator>>(QDataStream &s, QUuid &id) +{ + quint32 u32; + quint16 u16; + quint8 u8; + s >> u32; + id.data1 = u32; + s >> u16; + id.data2 = u16; + s >> u16; + id.data3 = u16; + for (int i = 0; i < 8; i++) { + s >> u8; + id.data4[i] = u8; + } + return s; +} +#endif + +/*! + Returns true if this is the null UUID + {00000000-0000-0000-0000-000000000000}; otherwise returns false. +*/ +bool QUuid::isNull() const +{ + return data4[0] == 0 && data4[1] == 0 && data4[2] == 0 && data4[3] == 0 && + data4[4] == 0 && data4[5] == 0 && data4[6] == 0 && data4[7] == 0 && + data1 == 0 && data2 == 0 && data3 == 0; +} + +/*! + \enum QUuid::Variant + + This enum defines the values used in the \l{Variant field} + {variant field} of the UUID. The value in the variant field + determines the layout of the 128-bit value. + + \value VarUnknown Variant is unknown + \value NCS Reserved for NCS (Network Computing System) backward compatibility + \value DCE Distributed Computing Environment, the scheme used by QUuid + \value Microsoft Reserved for Microsoft backward compatibility (GUID) + \value Reserved Reserved for future definition +*/ + +/*! + \enum QUuid::Version + + This enum defines the values used in the \l{Version field} + {version field} of the UUID. The version field is meaningful + only if the value in the \l{Variant field} {variant field} + is QUuid::DCE. + + \value VerUnknown Version is unknown + \value Time Time-based, by using timestamp, clock sequence, and + MAC network card address (if available) for the node sections + \value EmbeddedPOSIX DCE Security version, with embedded POSIX UUIDs + \value Name Name-based, by using values from a name for all sections + \value Random Random-based, by using random numbers for all sections +*/ + +/*! + \fn QUuid::Variant QUuid::variant() const + + Returns the value in the \l{Variant field} {variant field} of the + UUID. If the return value is QUuid::DCE, call version() to see + which layout it uses. The null UUID is considered to be of an + unknown variant. + + \sa version() +*/ +QUuid::Variant QUuid::variant() const +{ + if (isNull()) + return VarUnknown; + // Check the 3 MSB of data4[0] + if ((data4[0] & 0x80) == 0x00) return NCS; + else if ((data4[0] & 0xC0) == 0x80) return DCE; + else if ((data4[0] & 0xE0) == 0xC0) return Microsoft; + else if ((data4[0] & 0xE0) == 0xE0) return Reserved; + return VarUnknown; +} + +/*! + \fn QUuid::Version QUuid::version() const + + Returns the \l{Version field} {version field} of the UUID, if the + UUID's \l{Variant field} {variant field} is QUuid::DCE. Otherwise + it returns QUuid::VerUnknown. + + \sa variant() +*/ +QUuid::Version QUuid::version() const +{ + // Check the 4 MSB of data3 + Version ver = (Version)(data3>>12); + if (isNull() + || (variant() != DCE) + || ver < Time + || ver > Random) + return VerUnknown; + return ver; +} + +/*! + \fn bool QUuid::operator<(const QUuid &other) const + + Returns true if this QUuid has the same \l{Variant field} + {variant field} as the \a other QUuid and is lexicographically + \e{before} the \a other QUuid. If the \a other QUuid has a + different variant field, the return value is determined by + comparing the two \l{QUuid::Variant} {variants}. + + \sa variant() +*/ +#define ISLESS(f1, f2) if (f1!=f2) return (f1<f2); +bool QUuid::operator<(const QUuid &other) const +{ + if (variant() != other.variant()) + return variant() < other.variant(); + + ISLESS(data1, other.data1); + ISLESS(data2, other.data2); + ISLESS(data3, other.data3); + for (int n = 0; n < 8; n++) { + ISLESS(data4[n], other.data4[n]); + } + return false; +} + +/*! + \fn bool QUuid::operator>(const QUuid &other) const + + Returns true if this QUuid has the same \l{Variant field} + {variant field} as the \a other QUuid and is lexicographically + \e{after} the \a other QUuid. If the \a other QUuid has a + different variant field, the return value is determined by + comparing the two \l{QUuid::Variant} {variants}. + + \sa variant() +*/ +#define ISMORE(f1, f2) if (f1!=f2) return (f1>f2); +bool QUuid::operator>(const QUuid &other) const +{ + if (variant() != other.variant()) + return variant() > other.variant(); + + ISMORE(data1, other.data1); + ISMORE(data2, other.data2); + ISMORE(data3, other.data3); + for (int n = 0; n < 8; n++) { + ISMORE(data4[n], other.data4[n]); + } + return false; +} + +/*! + \fn QUuid QUuid::createUuid() + + On any platform other than Windows, this function returns a new + UUID with variant QUuid::DCE and version QUuid::Random. The random + numbers used to construct the UUID are obtained from the local + pseudo-random generator, which is usually not a cryptographic + quality random number generator. Therefore, a UUID generated by + this function can't be guaranteed to be unique. + + On a Windows platform, a GUID is generated, which almost certainly + \e{will} be unique, on this or any other system, networked or not. + + \sa variant(), version() +*/ +#if defined(Q_OS_WIN32) && ! defined(Q_CC_MWERKS) + +QT_BEGIN_INCLUDE_NAMESPACE +#include <objbase.h> // For CoCreateGuid +QT_END_INCLUDE_NAMESPACE + +QUuid QUuid::createUuid() +{ + GUID guid; + CoCreateGuid(&guid); + QUuid result = guid; + return result; +} + +#else // !Q_OS_WIN32 + +QT_BEGIN_INCLUDE_NAMESPACE +#include "qdatetime.h" +#include "stdlib.h" // For srand/rand +QT_END_INCLUDE_NAMESPACE + +QUuid QUuid::createUuid() +{ + static const int intbits = sizeof(int)*8; + static int randbits = 0; + if (!randbits) { + int max = RAND_MAX; + do { ++randbits; } while ((max=max>>1)); + qsrand((uint)QDateTime::currentDateTime().toTime_t()); + qrand(); // Skip first + } + + QUuid result; + uint *data = &(result.data1); + int chunks = 16 / sizeof(uint); + while (chunks--) { + uint randNumber = 0; + for (int filled = 0; filled < intbits; filled += randbits) + randNumber |= qrand()<<filled; + *(data+chunks) = randNumber; + } + + result.data4[0] = (result.data4[0] & 0x3F) | 0x80; // UV_DCE + result.data3 = (result.data3 & 0x0FFF) | 0x4000; // UV_Random + + return result; +} +#endif // !Q_OS_WIN32 + +/*! + \fn bool QUuid::operator==(const GUID &guid) const + + Returns true if this UUID is equal to the Windows GUID \a guid; + otherwise returns false. +*/ + +/*! + \fn bool QUuid::operator!=(const GUID &guid) const + + Returns true if this UUID is not equal to the Windows GUID \a + guid; otherwise returns false. +*/ + +QT_END_NAMESPACE diff --git a/src/corelib/plugin/quuid.h b/src/corelib/plugin/quuid.h new file mode 100644 index 0000000..95716d4 --- /dev/null +++ b/src/corelib/plugin/quuid.h @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QUUID_H +#define QUUID_H + +#include <QtCore/qstring.h> + +QT_BEGIN_HEADER + +#if defined(Q_OS_WIN) +#ifndef GUID_DEFINED +#define GUID_DEFINED +typedef struct _GUID +{ + ulong Data1; + ushort Data2; + ushort Data3; + uchar Data4[8]; +} GUID, *REFGUID, *LPGUID; +#endif +#endif + + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +struct Q_CORE_EXPORT QUuid +{ + enum Variant { + VarUnknown =-1, + NCS = 0, // 0 - - + DCE = 2, // 1 0 - + Microsoft = 6, // 1 1 0 + Reserved = 7 // 1 1 1 + }; + + enum Version { + VerUnknown =-1, + Time = 1, // 0 0 0 1 + EmbeddedPOSIX = 2, // 0 0 1 0 + Name = 3, // 0 0 1 1 + Random = 4 // 0 1 0 0 + }; + + QUuid() + { + data1 = 0; + data2 = 0; + data3 = 0; + for(int i = 0; i < 8; i++) + data4[i] = 0; + } + QUuid(uint l, ushort w1, ushort w2, uchar b1, uchar b2, uchar b3, uchar b4, uchar b5, uchar b6, uchar b7, uchar b8) + { + data1 = l; + data2 = w1; + data3 = w2; + data4[0] = b1; + data4[1] = b2; + data4[2] = b3; + data4[3] = b4; + data4[4] = b5; + data4[5] = b6; + data4[6] = b7; + data4[7] = b8; + } +#ifndef QT_NO_QUUID_STRING + QUuid(const QString &); + QUuid(const char *); + QString toString() const; + operator QString() const { return toString(); } +#endif + bool isNull() const; + + bool operator==(const QUuid &orig) const + { + uint i; + if (data1 != orig.data1 || data2 != orig.data2 || + data3 != orig.data3) + return false; + + for(i = 0; i < 8; i++) + if (data4[i] != orig.data4[i]) + return false; + + return true; + } + + bool operator!=(const QUuid &orig) const + { + return !(*this == orig); + } + + bool operator<(const QUuid &other) const; + bool operator>(const QUuid &other) const; + +#if defined(Q_OS_WIN) + // On Windows we have a type GUID that is used by the platform API, so we + // provide convenience operators to cast from and to this type. + QUuid(const GUID &guid) + { + data1 = guid.Data1; + data2 = guid.Data2; + data3 = guid.Data3; + for(int i = 0; i < 8; i++) + data4[i] = guid.Data4[i]; + } + + QUuid &operator=(const GUID &guid) + { + *this = QUuid(guid); + return *this; + } + + operator GUID() const + { + GUID guid = { data1, data2, data3, { data4[0], data4[1], data4[2], data4[3], data4[4], data4[5], data4[6], data4[7] } }; + return guid; + } + + bool operator==(const GUID &guid) const + { + return *this == QUuid(guid); + } + + bool operator!=(const GUID &guid) const + { + return !(*this == guid); + } +#endif + static QUuid createUuid(); + QUuid::Variant variant() const; + QUuid::Version version() const; + + uint data1; + ushort data2; + ushort data3; + uchar data4[8]; +}; + +#ifndef QT_NO_DATASTREAM +Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QUuid &); +Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QUuid &); +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QUUID_H |