diff --git a/src/corelib/mimetypes/qmimedatabase.cpp b/src/corelib/mimetypes/qmimedatabase.cpp index a549cd3acf8..68628eaa59d 100644 --- a/src/corelib/mimetypes/qmimedatabase.cpp +++ b/src/corelib/mimetypes/qmimedatabase.cpp @@ -144,18 +144,12 @@ void QMimeDatabasePrivate::loadProviders() } } - // Handle mimetypes with glob-deleteall tags (from XML providers) auto it = m_providers.begin(); + (*it)->setOverrideProvider(nullptr); + ++it; const auto end = m_providers.end(); - for (;it != end; ++it) { - const QStringList &list = (*it)->m_mimeTypesWithDeletedGlobs; - if (list.isEmpty()) - continue; - // Each Provider affects Providers with lower precedence - auto nextIt = it + 1; - for (; nextIt != end; ++nextIt) - (*nextIt)->excludeMimeTypeGlobs(list); - } + for (; it != end; ++it) + (*it)->setOverrideProvider((it - 1)->get()); } const QMimeDatabasePrivate::Providers &QMimeDatabasePrivate::providers() diff --git a/src/corelib/mimetypes/qmimeglobpattern.cpp b/src/corelib/mimetypes/qmimeglobpattern.cpp index d42b6e6d10d..80be35e8ea4 100644 --- a/src/corelib/mimetypes/qmimeglobpattern.cpp +++ b/src/corelib/mimetypes/qmimeglobpattern.cpp @@ -220,11 +220,11 @@ void QMimeAllGlobPatterns::removeMimeType(const QString &mimeType) m_lowWeightGlobs.removeMimeType(mimeType); } -void QMimeGlobPatternList::match(QMimeGlobMatchResult &result, - const QString &fileName) const +void QMimeGlobPatternList::match(QMimeGlobMatchResult &result, const QString &fileName, + const AddMatchFilterFunc &filterFunc) const { for (const QMimeGlobPattern &glob : *this) { - if (glob.matchFileName(fileName)) { + if (glob.matchFileName(fileName) && filterFunc(glob.mimeType())) { const QString pattern = glob.pattern(); const qsizetype suffixLen = isSimplePattern(pattern) ? pattern.size() - strlen("*.") : 0; result.addMatch(glob.mimeType(), glob.weight(), pattern, suffixLen); @@ -232,10 +232,11 @@ void QMimeGlobPatternList::match(QMimeGlobMatchResult &result, } } -void QMimeAllGlobPatterns::matchingGlobs(const QString &fileName, QMimeGlobMatchResult &result) const +void QMimeAllGlobPatterns::matchingGlobs(const QString &fileName, QMimeGlobMatchResult &result, + const AddMatchFilterFunc &filterFunc) const { // First try the high weight matches (>50), if any. - m_highWeightGlobs.match(result, fileName); + m_highWeightGlobs.match(result, fileName, filterFunc); // Now use the "fast patterns" dict, for simple *.foo patterns with weight 50 // (which is most of them, so this optimization is definitely worth it) @@ -247,14 +248,17 @@ void QMimeAllGlobPatterns::matchingGlobs(const QString &fileName, QMimeGlobMatch const QStringList matchingMimeTypes = m_fastPatterns.value(simpleExtension); const QString simplePattern = "*."_L1 + simpleExtension; - for (const QString &mime : matchingMimeTypes) - result.addMatch(mime, 50, simplePattern, simpleExtension.size()); + for (const QString &mime : matchingMimeTypes) { + if (filterFunc(mime)) { + result.addMatch(mime, 50, simplePattern, simpleExtension.size()); + } + } // Can't return yet; *.tar.bz2 has to win over *.bz2, so we need the low-weight mimetypes anyway, // at least those with weight 50. } // Finally, try the low weight matches (<=50) - m_lowWeightGlobs.match(result, fileName); + m_lowWeightGlobs.match(result, fileName, filterFunc); } void QMimeAllGlobPatterns::clear() diff --git a/src/corelib/mimetypes/qmimeglobpattern_p.h b/src/corelib/mimetypes/qmimeglobpattern_p.h index 8aaed665a91..4064700e396 100644 --- a/src/corelib/mimetypes/qmimeglobpattern_p.h +++ b/src/corelib/mimetypes/qmimeglobpattern_p.h @@ -87,6 +87,8 @@ private: }; Q_DECLARE_SHARED(QMimeGlobPattern) +using AddMatchFilterFunc = std::function; + class QMimeGlobPatternList : public QList { public: @@ -111,7 +113,8 @@ public: removeIf(isMimeTypeEqual); } - void match(QMimeGlobMatchResult &result, const QString &fileName) const; + void match(QMimeGlobMatchResult &result, const QString &fileName, + const AddMatchFilterFunc &filterFunc) const; }; /*! @@ -128,7 +131,8 @@ public: void addGlob(const QMimeGlobPattern &glob); void removeMimeType(const QString &mimeType); - void matchingGlobs(const QString &fileName, QMimeGlobMatchResult &result) const; + void matchingGlobs(const QString &fileName, QMimeGlobMatchResult &result, + const AddMatchFilterFunc &filterFunc) const; void clear(); PatternsMap m_fastPatterns; // example: "doc" -> "application/msword", "text/plain" diff --git a/src/corelib/mimetypes/qmimeprovider.cpp b/src/corelib/mimetypes/qmimeprovider.cpp index 8c97c4f16bc..1d92d759f92 100644 --- a/src/corelib/mimetypes/qmimeprovider.cpp +++ b/src/corelib/mimetypes/qmimeprovider.cpp @@ -62,6 +62,25 @@ QMimeProviderBase::QMimeProviderBase(QMimeDatabasePrivate *db, const QString &di { } +QMimeProviderBase *QMimeProviderBase::overrideProvider() const +{ + return m_overrideProvider; +} + +void QMimeProviderBase::setOverrideProvider(QMimeProviderBase *provider) +{ + m_overrideProvider = provider; +} + +bool QMimeProviderBase::isMimeTypeGlobsExcluded(const QString &name) const +{ + if (m_overrideProvider) { + if (m_overrideProvider->hasGlobDeleteAll(name)) + return true; + return m_overrideProvider->isMimeTypeGlobsExcluded(name); + } + return false; +} QMimeBinaryProvider::QMimeBinaryProvider(QMimeDatabasePrivate *db, const QString &directory) : QMimeProviderBase(db, directory), m_mimetypeListLoaded(false) @@ -222,17 +241,6 @@ void QMimeBinaryProvider::addFileNameMatches(const QString &fileName, QMimeGlobM fileName); } -bool QMimeBinaryProvider::isMimeTypeGlobsExcluded(const char *mimeTypeName) -{ - return m_mimeTypesWithExcludedGlobs.contains(QLatin1StringView(mimeTypeName)); -} - -void QMimeBinaryProvider::excludeMimeTypeGlobs(const QStringList &toExclude) -{ - for (const auto &mt : toExclude) - appendIfNew(m_mimeTypesWithExcludedGlobs, mt); -} - int QMimeBinaryProvider::matchGlobList(QMimeGlobMatchResult &result, CacheFile *cacheFile, int off, const QString &fileName) { @@ -248,14 +256,14 @@ int QMimeBinaryProvider::matchGlobList(QMimeGlobMatchResult &result, CacheFile * const Qt::CaseSensitivity qtCaseSensitive = caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive; const QString pattern = QLatin1StringView(cacheFile->getCharStar(globOffset)); - const char *mimeType = cacheFile->getCharStar(mimeTypeOffset); + const QLatin1StringView mimeType(cacheFile->getCharStar(mimeTypeOffset)); //qDebug() << pattern << mimeType << weight << caseSensitive; if (isMimeTypeGlobsExcluded(mimeType)) continue; QMimeGlobPattern glob(pattern, QString() /*unused*/, weight, qtCaseSensitive); if (glob.matchFileName(fileName)) { - result.addMatch(QLatin1StringView(mimeType), weight, pattern); + result.addMatch(mimeType, weight, pattern); ++numMatches; } } @@ -292,15 +300,15 @@ bool QMimeBinaryProvider::matchSuffixTree(QMimeGlobMatchResult &result, if (mch != 0) break; const int mimeTypeOffset = cacheFile->getUint32(childOff + 4); - const char *mimeType = cacheFile->getCharStar(mimeTypeOffset); + const QLatin1StringView mimeType(cacheFile->getCharStar(mimeTypeOffset)); if (isMimeTypeGlobsExcluded(mimeType)) continue; const int flagsAndWeight = cacheFile->getUint32(childOff + 8); const int weight = flagsAndWeight & 0xff; const bool caseSensitive = flagsAndWeight & 0x100; if (caseSensitiveCheck || !caseSensitive) { - result.addMatch(QLatin1StringView(mimeType), weight, - u'*' + QStringView{fileName}.mid(charPos + 1), + result.addMatch(mimeType, weight, + u'*' + QStringView{ fileName }.mid(charPos + 1), fileName.size() - charPos - 2); success = true; } @@ -705,7 +713,8 @@ bool QMimeXMLProvider::knowsMimeType(const QString &name) void QMimeXMLProvider::addFileNameMatches(const QString &fileName, QMimeGlobMatchResult &result) { - m_mimeTypeGlobs.matchingGlobs(fileName, result); + auto filterFunc = [this](const QString &name) { return !isMimeTypeGlobsExcluded(name); }; + m_mimeTypeGlobs.matchingGlobs(fileName, result, filterFunc); } void QMimeXMLProvider::findByMagic(const QByteArray &data, int *accuracyPtr, QString *candidate) @@ -740,7 +749,6 @@ void QMimeXMLProvider::ensureLoaded() m_parents.clear(); m_mimeTypeGlobs.clear(); m_magicMatchers.clear(); - m_mimeTypesWithDeletedGlobs.clear(); //qDebug() << "Loading" << m_allFiles; @@ -816,29 +824,9 @@ void QMimeXMLProvider::addGlobPattern(const QMimeGlobPattern &glob) void QMimeXMLProvider::addMimeType(const QMimeTypeXMLData &mt) { - if (mt.hasGlobDeleteAll) - appendIfNew(m_mimeTypesWithDeletedGlobs, mt.name); m_nameMimeTypeMap.insert(mt.name, mt); } -/* - \a toExclude is a list of mime type names that should have the the glob patterns - associated with them cleared (because there are mime types with the same names - in a higher precedence Provider that have glob-deleteall tags). - - This method is called from QMimeDatabasePrivate::loadProviders() to exclude mime - type glob patterns in lower precedence Providers. -*/ -void QMimeXMLProvider::excludeMimeTypeGlobs(const QStringList &toExclude) -{ - for (const auto &mt : toExclude) { - auto it = m_nameMimeTypeMap.find(mt); - if (it != m_nameMimeTypeMap.end()) - it->globPatterns.clear(); - m_mimeTypeGlobs.removeMimeType(mt); - } -} - void QMimeXMLProvider::addParents(const QString &mime, QStringList &result) { for (const QString &parent : m_parents.value(mime)) { diff --git a/src/corelib/mimetypes/qmimeprovider_p.h b/src/corelib/mimetypes/qmimeprovider_p.h index 755737eaafa..4fbd63af921 100644 --- a/src/corelib/mimetypes/qmimeprovider_p.h +++ b/src/corelib/mimetypes/qmimeprovider_p.h @@ -29,6 +29,7 @@ QT_BEGIN_NAMESPACE class QMimeMagicRuleMatcher; class QMimeTypeXMLData; +class QMimeProviderBase; class QMimeProviderBase { @@ -53,38 +54,16 @@ public: virtual QString icon(const QString &name) = 0; virtual QString genericIcon(const QString &name) = 0; virtual void ensureLoaded() { } - virtual void excludeMimeTypeGlobs(const QStringList &) { } QString directory() const { return m_directory; } + QMimeProviderBase *overrideProvider() const; + void setOverrideProvider(QMimeProviderBase *provider); + bool isMimeTypeGlobsExcluded(const QString &name) const; + QMimeDatabasePrivate *m_db; QString m_directory; - - /* - MimeTypes with "glob-deleteall" tags are handled differently by each provider - sub-class: - - QMimeBinaryProvider parses glob-deleteall tags lazily, i.e. only when hasGlobDeleteAll() - is called, and clears the glob patterns associated with mimetypes that have this tag - - QMimeXMLProvider parses glob-deleteall from the start, i.e. when a XML file is - parsed with QMimeTypeParser - - The two lists below are used to let both provider types (XML and Binary) communicate - about mimetypes with glob-deleteall. - */ - /* - List of mimetypes in _this_ Provider that have a "glob-deleteall" tag, - glob patterns for those mimetypes should be ignored in all _other_ lower - precedence Providers. - */ - QStringList m_mimeTypesWithDeletedGlobs; - - /* - List of mimetypes with glob patterns that are "overwritten" in _this_ Provider, - by a "glob-deleteall" tag in a mimetype definition in a _higher precedence_ - Provider. With QMimeBinaryProvider, we can't change the data in the binary mmap'ed - file, hence the need for this list. - */ - QStringList m_mimeTypesWithExcludedGlobs; + QMimeProviderBase *m_overrideProvider = nullptr; // more "local" than this one }; /* @@ -111,7 +90,6 @@ public: QString icon(const QString &name) override; QString genericIcon(const QString &name) override; void ensureLoaded() override; - void excludeMimeTypeGlobs(const QStringList &toExclude) override; private: struct CacheFile; @@ -121,7 +99,6 @@ private: bool matchSuffixTree(QMimeGlobMatchResult &result, CacheFile *cacheFile, int numEntries, int firstOffset, const QString &fileName, qsizetype charPos, bool caseSensitiveCheck); - bool isMimeTypeGlobsExcluded(const char *name); bool matchMagicRule(CacheFile *cacheFile, int numMatchlets, int firstOffset, const QByteArray &data); QLatin1StringView iconForMime(CacheFile *cacheFile, int posListOffset, const QByteArray &inputMime); @@ -180,7 +157,6 @@ public: // Called by the mimetype xml parser void addMimeType(const QMimeTypeXMLData &mt); - void excludeMimeTypeGlobs(const QStringList &toExclude) override; void addGlobPattern(const QMimeGlobPattern &glob); void addParent(const QString &child, const QString &parent); void addAlias(const QString &alias, const QString &name); diff --git a/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp b/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp index b1e9f51a25e..0e99bd98337 100644 --- a/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp +++ b/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp @@ -1221,10 +1221,6 @@ void tst_QMimeDatabase::installNewLocalMimeType() { // QTBUG-101755 QList mimes = db.mimeTypesForFileName(u"foo.webm"_s); // "*.webm" glob pattern is deleted with "glob-deleteall" - if (m_isUsingCacheProvider && useLocalBinaryCache) - QEXPECT_FAIL("with_binary_cache", - "BUG, glob-deleteall isn't handled correctly between binary providers", - Continue); QVERIFY2(mimes.isEmpty(), qPrintable(mimeTypeNames(mimes).join(u','))); mimes = db.mimeTypesForFileName(u"foo.videowebm"_s); QCOMPARE(mimes.size(), 1);