summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2023-11-13 15:43:17 -0800
committerThiago Macieira <thiago.macieira@intel.com>2023-11-28 03:14:03 -0800
commit878e3342e1c9bd8a4da6a2e9e1508dacbe0c7ab6 (patch)
tree76d12e9076237db635aecd9075b54153bcd7fdb5
parent90df0f48062310e29494df3449fd68c12e6694b5 (diff)
QFactoryLoader: add metaDataKeys() to return just the "Keys" entry
Without parsing the whole metadata structure into a QCborValue. QFactoryLoader::indexOf() is only used in the icon engine and accessibility loaders. QFactoryLoader::keyMap() has more users, but QFactoryLoader::metaData() is still by far the most used interface. Task-number: QTBUG-114253 Change-Id: I8bd6bb457b9c42218247fffd179753524fc9b6a5 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
-rw-r--r--src/corelib/plugin/qfactoryloader.cpp78
-rw-r--r--src/corelib/plugin/qfactoryloader_p.h1
-rw-r--r--tests/auto/corelib/plugin/qfactoryloader/tst_qfactoryloader.cpp50
3 files changed, 119 insertions, 10 deletions
diff --git a/src/corelib/plugin/qfactoryloader.cpp b/src/corelib/plugin/qfactoryloader.cpp
index 722fcce978..55d5bd4f9c 100644
--- a/src/corelib/plugin/qfactoryloader.cpp
+++ b/src/corelib/plugin/qfactoryloader.cpp
@@ -99,6 +99,45 @@ struct QFactoryLoaderIidSearch
return skip(reader);
}
};
+
+struct QFactoryLoaderMetaDataKeysExtractor : QFactoryLoaderIidSearch
+{
+ QCborArray keys;
+ QFactoryLoaderMetaDataKeysExtractor(QLatin1StringView iid)
+ : QFactoryLoaderIidSearch(iid)
+ {}
+
+ IterationResult::Result operator()(QtPluginMetaDataKeys key, QCborStreamReader &reader)
+ {
+ if (key == QtPluginMetaDataKeys::IID) {
+ QFactoryLoaderIidSearch::operator()(key, reader);
+ return IterationResult::ContinueSearch;
+ }
+ if (key != QtPluginMetaDataKeys::MetaData)
+ return skip(reader);
+
+ if (!matchesIid)
+ return IterationResult::FinishedSearch;
+ if (!reader.isMap() || !reader.isLengthKnown())
+ return IterationResult::InvalidHeaderItem;
+ if (!reader.enterContainer())
+ return IterationResult::ParsingError;
+ while (reader.isValid()) {
+ // the metadata is JSON, so keys are all strings
+ QString key = reader.toString();
+ if (key == "Keys"_L1) {
+ if (!reader.isArray() || !reader.isLengthKnown())
+ return IterationResult::InvalidHeaderItem;
+ keys = QCborValue::fromCbor(reader).toArray();
+ break;
+ }
+ skip(reader);
+ }
+ // warning: we may not have finished iterating over the header
+ return IterationResult::FinishedSearch;
+ }
+ using QFactoryLoaderIidSearch::operator();
+};
} // unnamed namespace
template <typename F> static IterationResult iterateInPluginMetaData(QByteArrayView raw, F &&f)
@@ -485,6 +524,35 @@ QFactoryLoader::MetaDataList QFactoryLoader::metaData() const
metaData.append(std::move(parsed));
}
+ // other portions of the code will cast to int (e.g., keyMap())
+ Q_ASSERT(metaData.size() <= std::numeric_limits<int>::max());
+ return metaData;
+}
+
+QList<QCborArray> QFactoryLoader::metaDataKeys() const
+{
+ Q_D(const QFactoryLoader);
+ QList<QCborArray> metaData;
+#if QT_CONFIG(library)
+ QMutexLocker locker(&d->mutex);
+ for (const auto &library : d->libraries) {
+ const QCborValue md = library->metaData.value(QtPluginMetaDataKeys::MetaData);
+ metaData.append(md["Keys"_L1].toArray());
+ }
+#endif
+
+ QLatin1StringView iid(d->iid.constData(), d->iid.size());
+ const auto staticPlugins = QPluginLoader::staticPlugins();
+ for (const QStaticPlugin &plugin : staticPlugins) {
+ QByteArrayView pluginData(static_cast<const char *>(plugin.rawMetaData),
+ plugin.rawMetaDataSize);
+ QFactoryLoaderMetaDataKeysExtractor extractor{ iid };
+ iterateInPluginMetaData(pluginData, extractor);
+ if (extractor.matchesIid)
+ metaData += std::move(extractor.keys);
+ }
+
+ // other portions of the code will cast to int (e.g., keyMap())
Q_ASSERT(metaData.size() <= std::numeric_limits<int>::max());
return metaData;
}
@@ -529,10 +597,9 @@ QObject *QFactoryLoader::instance(int index) const
QMultiMap<int, QString> QFactoryLoader::keyMap() const
{
QMultiMap<int, QString> result;
- const QList<QPluginParsedMetaData> metaDataList = metaData();
+ const QList<QCborArray> metaDataList = metaDataKeys();
for (int i = 0; i < int(metaDataList.size()); ++i) {
- const QCborMap metaData = metaDataList.at(i).value(QtPluginMetaDataKeys::MetaData).toMap();
- const QCborArray keys = metaData.value("Keys"_L1).toArray();
+ const QCborArray &keys = metaDataList[i];
for (QCborValueConstRef key : keys)
result.insert(i, key.toString());
}
@@ -541,10 +608,9 @@ QMultiMap<int, QString> QFactoryLoader::keyMap() const
int QFactoryLoader::indexOf(const QString &needle) const
{
- const QList<QPluginParsedMetaData> metaDataList = metaData();
+ const QList<QCborArray> metaDataList = metaDataKeys();
for (int i = 0; i < int(metaDataList.size()); ++i) {
- const QCborMap metaData = metaDataList.at(i).value(QtPluginMetaDataKeys::MetaData).toMap();
- const QCborArray keys = metaData.value("Keys"_L1).toArray();
+ const QCborArray &keys = metaDataList[i];
for (QCborValueConstRef key : keys) {
if (key.toString().compare(needle, Qt::CaseInsensitive) == 0)
return i;
diff --git a/src/corelib/plugin/qfactoryloader_p.h b/src/corelib/plugin/qfactoryloader_p.h
index fcfb4cf597..56dc7e6ad1 100644
--- a/src/corelib/plugin/qfactoryloader_p.h
+++ b/src/corelib/plugin/qfactoryloader_p.h
@@ -86,6 +86,7 @@ public:
using MetaDataList = QList<QPluginParsedMetaData>;
MetaDataList metaData() const;
+ QList<QCborArray> metaDataKeys() const;
QObject *instance(int index) const;
};
diff --git a/tests/auto/corelib/plugin/qfactoryloader/tst_qfactoryloader.cpp b/tests/auto/corelib/plugin/qfactoryloader/tst_qfactoryloader.cpp
index 32f14e7a0a..a17ecd73bb 100644
--- a/tests/auto/corelib/plugin/qfactoryloader/tst_qfactoryloader.cpp
+++ b/tests/auto/corelib/plugin/qfactoryloader/tst_qfactoryloader.cpp
@@ -5,6 +5,7 @@
#include <QtCore/qdir.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qplugin.h>
+#include <QtCore/qversionnumber.h>
#include <private/qfactoryloader_p.h>
#include <private/qlibrary_p.h>
#include "plugin1/plugininterface1.h"
@@ -48,21 +49,61 @@ void tst_QFactoryLoader::usingTwoFactoriesFromSameDir()
// set the library path to contain the directory where the 'bin' dir is located
QCoreApplication::setLibraryPaths( { QFileInfo(binFolder).absolutePath() });
#endif
+ auto versionNumber = [](const QCborValue &value) {
+ // Qt plugins only store major & minor versions in the metadata, so
+ // the low 8 bits are always zero.
+ qint64 v = value.toInteger();
+ return QVersionNumber(v >> 16, uchar(v >> 8));
+ };
+ QVersionNumber qtVersion(QT_VERSION_MAJOR, 0);
const QString suffix = QLatin1Char('/') + QLatin1String(binFolderC);
QFactoryLoader loader1(PluginInterface1_iid, suffix);
+ const QFactoryLoader::MetaDataList list1 = loader1.metaData();
+ const QList<QCborArray> keys1 = loader1.metaDataKeys();
+ QCOMPARE(list1.size(), 1);
+ QCOMPARE(keys1.size(), 1);
+ QCOMPARE_GE(versionNumber(list1[0].value(QtPluginMetaDataKeys::QtVersion)), qtVersion);
+ QCOMPARE(list1[0].value(QtPluginMetaDataKeys::IID), PluginInterface1_iid);
+ QCOMPARE(list1[0].value(QtPluginMetaDataKeys::ClassName), "Plugin1");
+
+ // plugin1's Q_PLUGIN_METADATA has FILE "plugin1.json"
+ QCborValue metadata1 = list1[0].value(QtPluginMetaDataKeys::MetaData);
+ QCOMPARE(metadata1.type(), QCborValue::Map);
+ QCOMPARE(metadata1["Keys"], QCborArray{ "plugin1" });
+ QCOMPARE(keys1[0], QCborArray{ "plugin1" });
+ QCOMPARE(loader1.indexOf("Plugin1"), 0);
+ QCOMPARE(loader1.indexOf("PLUGIN1"), 0);
+ QCOMPARE(loader1.indexOf("Plugin2"), -1);
- PluginInterface1 *plugin1 = qobject_cast<PluginInterface1 *>(loader1.instance(0));
+ QFactoryLoader loader2(PluginInterface2_iid, suffix);
+ const QFactoryLoader::MetaDataList list2 = loader2.metaData();
+ const QList<QCborArray> keys2 = loader2.metaDataKeys();
+ QCOMPARE(list2.size(), 1);
+ QCOMPARE(keys2.size(), 1);
+ QCOMPARE_GE(versionNumber(list2[0].value(QtPluginMetaDataKeys::QtVersion)), qtVersion);
+ QCOMPARE(list2[0].value(QtPluginMetaDataKeys::IID), PluginInterface2_iid);
+ QCOMPARE(list2[0].value(QtPluginMetaDataKeys::ClassName), "Plugin2");
+
+ // plugin2's Q_PLUGIN_METADATA does not have FILE
+ QCOMPARE(list2[0].value(QtPluginMetaDataKeys::MetaData), QCborValue());
+ QCOMPARE(keys2[0], QCborArray());
+ QCOMPARE(loader2.indexOf("Plugin1"), -1);
+ QCOMPARE(loader2.indexOf("Plugin2"), -1);
+
+ QObject *obj1 = loader1.instance(0);
+ PluginInterface1 *plugin1 = qobject_cast<PluginInterface1 *>(obj1);
QVERIFY2(plugin1,
qPrintable(QString::fromLatin1("Cannot load plugin '%1'")
.arg(QLatin1String(PluginInterface1_iid))));
+ QCOMPARE(obj1->metaObject()->className(), "Plugin1");
- QFactoryLoader loader2(PluginInterface2_iid, suffix);
-
- PluginInterface2 *plugin2 = qobject_cast<PluginInterface2 *>(loader2.instance(0));
+ QObject *obj2 = loader2.instance(0);
+ PluginInterface2 *plugin2 = qobject_cast<PluginInterface2 *>(obj2);
QVERIFY2(plugin2,
qPrintable(QString::fromLatin1("Cannot load plugin '%1'")
.arg(QLatin1String(PluginInterface2_iid))));
+ QCOMPARE(obj2->metaObject()->className(), "Plugin2");
QCOMPARE(plugin1->pluginName(), QLatin1String("Plugin1 ok"));
QCOMPARE(plugin2->pluginName(), QLatin1String("Plugin2 ok"));
@@ -167,6 +208,7 @@ void tst_QFactoryLoader::staticPlugin()
QCborValue metaData = map[int(QtPluginMetaDataKeys::MetaData)];
QVERIFY(metaData.isMap());
QCOMPARE(metaData["Keys"], QCborArray{ "Value" });
+ QCOMPARE(loader.metaDataKeys(), QList{ QCborArray{ "Value" } });
QCOMPARE(loader.indexOf("Value"), 0);
// instantiate