From 2bea9b74ba4894c372b0587c0c5433b713b53e3a Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sat, 11 Sep 2021 16:50:33 -0500 Subject: QPlugin: keep the CBOR data as CBOR Since QJsonValue and QCborValue use the same backend, we may as well use the CBOR frontend classes, which means we avoid an unnecessary conversion until later. Change-Id: I2de1b4dfacd443148279fffd16a3e2f56cd74c0b Reviewed-by: Oswald Buddenhagen Reviewed-by: Lars Knoll --- src/corelib/plugin/qfactoryloader.cpp | 92 ++++++++++++++++++----------------- src/corelib/plugin/qfactoryloader_p.h | 38 ++++++++++++--- src/corelib/plugin/qlibrary.cpp | 21 ++++---- src/corelib/plugin/qlibrary_p.h | 10 ++-- src/corelib/plugin/qplugin_p.h | 10 +++- src/corelib/plugin/qpluginloader.cpp | 17 ++++--- 6 files changed, 110 insertions(+), 78 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/plugin/qfactoryloader.cpp b/src/corelib/plugin/qfactoryloader.cpp index 02c9cafbed..824bf60f7d 100644 --- a/src/corelib/plugin/qfactoryloader.cpp +++ b/src/corelib/plugin/qfactoryloader.cpp @@ -46,8 +46,12 @@ #include "private/qcoreapplication_p.h" #include "private/qduplicatetracker_p.h" #include "private/qobject_p.h" +#include "qcborarray.h" #include "qcbormap.h" #include "qcborvalue.h" +#include "qcborvalue.h" +#include "qdir.h" +#include "qfileinfo.h" #include "qjsonarray.h" #include "qjsondocument.h" #include "qjsonobject.h" @@ -57,63 +61,61 @@ #include "qplugin.h" #include "qplugin_p.h" #include "qpluginloader.h" -#include -#include + +#if QT_CONFIG(library) +# include "qlibrary_p.h" +#endif #include QT_BEGIN_NAMESPACE -QJsonDocument qJsonFromRawLibraryMetaData(const char *raw, qsizetype size, QString *errMsg) +bool QPluginParsedMetaData::parse(QByteArrayView raw) { - // extract the keys not stored in CBOR QPluginMetaData::Header header; - Q_ASSERT(size >= qsizetype(sizeof(header))); - memcpy(&header, raw, sizeof(header)); - if (Q_UNLIKELY(header.version > QPluginMetaData::CurrentMetaDataVersion)) { - *errMsg = QStringLiteral("Invalid metadata version"); - return QJsonDocument(); - } - - raw += sizeof(header); - size -= sizeof(header); - QByteArray ba = QByteArray::fromRawData(raw, int(size)); + Q_ASSERT(raw.size() >= qsizetype(sizeof(header))); + memcpy(&header, raw.data(), sizeof(header)); + if (Q_UNLIKELY(header.version > QPluginMetaData::CurrentMetaDataVersion)) + return setError(QFactoryLoader::tr("Invalid metadata version")); + + // use fromRawData to keep QCborStreamReader from copying + raw = raw.sliced(sizeof(header)); + QByteArray ba = QByteArray::fromRawData(raw.data(), raw.size()); QCborParserError err; QCborValue metadata = QCborValue::fromCbor(ba, &err); - if (err.error != QCborError::NoError) { - *errMsg = QLatin1String("Metadata parsing error: ") + err.error.toString(); - return QJsonDocument(); - } - - if (!metadata.isMap()) { - *errMsg = QStringLiteral("Unexpected metadata contents"); - return QJsonDocument(); - } + if (err.error != QCborError::NoError) + return setError(QFactoryLoader::tr("Metadata parsing error: %1").arg(err.error.toString())); + if (!metadata.isMap()) + return setError(QFactoryLoader::tr("Unexpected metadata contents")); + QCborMap map = metadata.toMap(); + metadata = {}; DecodedArchRequirements archReq = header.version == 0 ? decodeVersion0ArchRequirements(header.plugin_arch_requirements) : decodeVersion1ArchRequirements(header.plugin_arch_requirements); - QJsonObject o; - o.insert(QLatin1String("version"), - QT_VERSION_CHECK(header.qt_major_version, header.qt_minor_version, 0)); - o.insert(QLatin1String("debug"), archReq.isDebug); - o.insert(QLatin1String("archlevel"), archReq.level); + // insert the keys not stored in the top-level CBOR map + map[int(QtPluginMetaDataKeys::QtVersion)] = + QT_VERSION_CHECK(header.qt_major_version, header.qt_minor_version, 0); + map[int(QtPluginMetaDataKeys::IsDebug)] = archReq.isDebug; + map[int(QtPluginMetaDataKeys::Requirements)] = archReq.level; + + data = std::move(map); + return true; +} - // convert the top-level map integer keys - for (auto it : metadata.toMap()) { +QJsonObject QPluginParsedMetaData::toJson() const +{ + // convert from the internal CBOR representation to an external JSON one + QJsonObject o; + for (auto it : data.toMap()) { QString key; if (it.first.isInteger()) { switch (it.first.toInteger()) { #define CONVERT_TO_STRING(IntKey, StringKey, Description) \ case int(IntKey): key = QStringLiteral(StringKey); break; QT_PLUGIN_FOREACH_METADATA(CONVERT_TO_STRING) -#undef CONVERT_TO_STRING - - case int(QtPluginMetaDataKeys::Requirements): - // ignore, handled above - break; } } else { key = it.first.toString(); @@ -122,7 +124,7 @@ QJsonDocument qJsonFromRawLibraryMetaData(const char *raw, qsizetype size, QStri if (!key.isEmpty()) o.insert(key, it.second.toJsonValue()); } - return QJsonDocument(o); + return o; } class QFactoryLoaderPrivate : public QObjectPrivate @@ -227,12 +229,12 @@ void QFactoryLoader::update() QStringList keys; bool metaDataOk = false; - QString iid = library->metaData.value(QLatin1String("IID")).toString(); + QString iid = library->metaData.value(QtPluginMetaDataKeys::IID).toString(); if (iid == QLatin1String(d->iid.constData(), d->iid.size())) { - QJsonObject object = library->metaData.value(QLatin1String("MetaData")).toObject(); + QCborMap object = library->metaData.value(QtPluginMetaDataKeys::MetaData).toMap(); metaDataOk = true; - QJsonArray k = object.value(QLatin1String("Keys")).toArray(); + QCborArray k = object.value(QLatin1String("Keys")).toArray(); for (int i = 0; i < k.size(); ++i) keys += d->cs ? k.at(i).toString() : k.at(i).toString().toLower(); } @@ -251,14 +253,14 @@ void QFactoryLoader::update() // library was built with a future Qt version, // whereas the new one has a Qt version that fits // better + constexpr int QtVersionNoPatch = QT_VERSION_CHECK(QT_VERSION_MAJOR, QT_VERSION_MINOR, 0); const QString &key = keys.at(k); QLibraryPrivate *previous = d->keyMap.value(key); int prev_qt_version = 0; - if (previous) { - prev_qt_version = (int)previous->metaData.value(QLatin1String("version")).toDouble(); - } - int qt_version = (int)library->metaData.value(QLatin1String("version")).toDouble(); - if (!previous || (prev_qt_version > QT_VERSION && qt_version <= QT_VERSION)) { + if (previous) + prev_qt_version = int(previous->metaData.value(QtPluginMetaDataKeys::QtVersion).toInteger()); + int qt_version = int(library->metaData.value(QtPluginMetaDataKeys::QtVersion).toInteger()); + if (!previous || (prev_qt_version > QtVersionNoPatch && qt_version <= QtVersionNoPatch)) { d->keyMap[key] = library; ++keyUsageCount; } @@ -339,7 +341,7 @@ QList QFactoryLoader::metaData() const #if QT_CONFIG(library) QMutexLocker locker(&d->mutex); for (int i = 0; i < d->libraryList.size(); ++i) - metaData.append(d->libraryList.at(i)->metaData); + metaData.append(d->libraryList.at(i)->metaData.toJson()); #endif const auto staticPlugins = QPluginLoader::staticPlugins(); diff --git a/src/corelib/plugin/qfactoryloader_p.h b/src/corelib/plugin/qfactoryloader_p.h index 0ad62cc525..b7536d0349 100644 --- a/src/corelib/plugin/qfactoryloader_p.h +++ b/src/corelib/plugin/qfactoryloader_p.h @@ -1,6 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2021 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -54,19 +55,44 @@ #include "QtCore/qglobal.h" #ifndef QT_NO_QOBJECT +#include "QtCore/private/qplugin_p.h" +#include "QtCore/qcbormap.h" +#include "QtCore/qcborvalue.h" #include "QtCore/qmap.h" #include "QtCore/qobject.h" - -#if QT_CONFIG(library) -# include "qlibrary_p.h" -#endif +#include "QtCore/qplugin.h" QT_BEGIN_NAMESPACE class QJsonDocument; class QJsonObject; +class QLibraryPrivate; + +class QPluginParsedMetaData +{ + QCborValue data; + bool setError(const QString &errorString) Q_DECL_COLD_FUNCTION + { + data = errorString; + return false; + } +public: + QPluginParsedMetaData() = default; + QPluginParsedMetaData(QByteArrayView input) { parse(input); } + + bool isError() const { return !data.isMap(); } + QString errorString() const { return data.toString(); } + + bool parse(QByteArrayView input); + bool parse(QPluginMetaData metaData) + { return parse(QByteArrayView(reinterpret_cast(metaData.data), metaData.size)); } -QJsonDocument qJsonFromRawLibraryMetaData(const char *raw, qsizetype size, QString *errMsg); + QJsonObject toJson() const; + + // if data is not a map, toMap() returns empty, so shall these functions + QCborMap toCbor() const { return data.toMap(); } + QCborValue value(QtPluginMetaDataKeys k) const { return toCbor()[int(k)]; } +}; class QFactoryLoaderPrivate; class Q_CORE_EXPORT QFactoryLoader : public QObject diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp index 432b232d27..4eea6f0002 100644 --- a/src/corelib/plugin/qlibrary.cpp +++ b/src/corelib/plugin/qlibrary.cpp @@ -270,13 +270,13 @@ static bool findPatternUnloaded(const QString &library, QLibraryPrivate *lib) QString errMsg = library; QLibraryScanResult r = qt_find_pattern(filedata, fdlen, &errMsg); if (r.length) { - QJsonDocument doc = qJsonFromRawLibraryMetaData(filedata + r.pos, r.length, &errMsg); - if (doc.isNull()) { + if (!lib->metaData.parse(QByteArrayView(filedata + r.pos, r.length))) { + errMsg = lib->metaData.errorString(); qWarning("Found invalid metadata in lib %ls: %ls", qUtf16Printable(library), qUtf16Printable(errMsg)); } else { - lib->metaData = doc.object(); if (qt_debug_component()) { + QJsonDocument doc(lib->metaData.toJson()); qWarning("Found metadata in lib %s, metadata=\n%s\n", library.toLocal8Bit().constData(), doc.toJson().constData()); } @@ -711,13 +711,10 @@ static bool qt_get_metadata(QLibraryPrivate *priv, QString *errMsg) if (metaData.size < sizeof(QPluginMetaData::Header)) return error(QLibrary::tr("metadata too small")); - QJsonDocument doc = qJsonFromRawLibraryMetaData(reinterpret_cast(metaData.data), - metaData.size, errMsg); - if (doc.isNull()) - return false; // error message already set - - priv->metaData = doc.object(); - return true; + if (priv->metaData.parse(metaData)) + return true; + *errMsg = priv->metaData.errorString(); + return false; } bool QLibraryPrivate::isPlugin() @@ -773,8 +770,8 @@ void QLibraryPrivate::updatePluginState() pluginState = IsNotAPlugin; // be pessimistic - uint qt_version = (uint)metaData.value(QLatin1String("version")).toDouble(); - bool debug = metaData.value(QLatin1String("debug")).toBool(); + uint qt_version = uint(metaData.value(QtPluginMetaDataKeys::QtVersion).toInteger()); + bool debug = metaData.value(QtPluginMetaDataKeys::IsDebug).toBool(); if ((qt_version & 0x00ff00) > (QT_VERSION & 0x00ff00) || (qt_version & 0xff0000) != (QT_VERSION & 0xff0000)) { if (qt_debug_component()) { qWarning("In %s:\n" diff --git a/src/corelib/plugin/qlibrary_p.h b/src/corelib/plugin/qlibrary_p.h index b42816a469..3c43d79e25 100644 --- a/src/corelib/plugin/qlibrary_p.h +++ b/src/corelib/plugin/qlibrary_p.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. +** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -52,9 +52,9 @@ // We mean it. // -#include - #include "QtCore/qlibrary.h" + +#include "QtCore/private/qfactoryloader_p.h" #include "QtCore/qmutex.h" #include "QtCore/qplugin.h" #include "QtCore/qpointer.h" @@ -111,7 +111,7 @@ public: // the mutex protects the fields below QMutex mutex; QPointer inst; // used by QFactoryLoader - QJsonObject metaData; + QPluginParsedMetaData metaData; QString errorString; QString qualifiedFileName; diff --git a/src/corelib/plugin/qplugin_p.h b/src/corelib/plugin/qplugin_p.h index 80ee02e761..026992ba97 100644 --- a/src/corelib/plugin/qplugin_p.h +++ b/src/corelib/plugin/qplugin_p.h @@ -61,7 +61,8 @@ enum class QtPluginMetaDataKeys { IID, ClassName, MetaData, - URI + URI, + IsDebug, }; // F(IntKey, StringKey, Description) @@ -70,7 +71,12 @@ enum class QtPluginMetaDataKeys { F(QtPluginMetaDataKeys::IID, "IID", "Plugin's Interface ID") \ F(QtPluginMetaDataKeys::ClassName, "className", "Plugin class name") \ F(QtPluginMetaDataKeys::MetaData, "MetaData", "Other meta data") \ - F(QtPluginMetaDataKeys::URI, "URI", "Plugin URI") + F(QtPluginMetaDataKeys::URI, "URI", "Plugin URI") \ + /* not output by moc in CBOR */ \ + F(QtPluginMetaDataKeys::QtVersion, "version", "Qt version") \ + F(QtPluginMetaDataKeys::Requirements, "archlevel", "Architectural level") \ + F(QtPluginMetaDataKeys::IsDebug, "debug", "Debug-mode plugin") \ + /**/ namespace { struct DecodedArchRequirements diff --git a/src/corelib/plugin/qpluginloader.cpp b/src/corelib/plugin/qpluginloader.cpp index 9afdf0e537..eca85eb82e 100644 --- a/src/corelib/plugin/qpluginloader.cpp +++ b/src/corelib/plugin/qpluginloader.cpp @@ -47,6 +47,10 @@ #include "qfileinfo.h" #include "qjsondocument.h" +#if QT_CONFIG(library) +# include "qlibrary_p.h" +#endif + QT_BEGIN_NAMESPACE #if QT_CONFIG(library) @@ -185,7 +189,7 @@ QJsonObject QPluginLoader::metaData() const { if (!d) return QJsonObject(); - return d->metaData; + return d->metaData.toJson(); } /*! @@ -477,13 +481,10 @@ QList QPluginLoader::staticPlugins() */ QJsonObject QStaticPlugin::metaData() const { - auto ptr = static_cast(rawMetaData); - - QString errMsg; - QJsonDocument doc = qJsonFromRawLibraryMetaData(ptr, rawMetaDataSize, &errMsg); - Q_ASSERT(doc.isObject()); - Q_ASSERT(errMsg.isEmpty()); - return doc.object(); + QByteArrayView data(static_cast(rawMetaData), rawMetaDataSize); + QPluginParsedMetaData parsed(data); + Q_ASSERT(!parsed.isError()); + return parsed.toJson(); } QT_END_NAMESPACE -- cgit v1.2.3