diff --git a/src/libs/utils/mimetypes2/mimedatabase.cpp b/src/libs/utils/mimetypes2/mimedatabase.cpp index d77ce2b7045..a46d7c8f416 100644 --- a/src/libs/utils/mimetypes2/mimedatabase.cpp +++ b/src/libs/utils/mimetypes2/mimedatabase.cpp @@ -244,8 +244,9 @@ MimeGlobMatchResult MimeDatabasePrivate::findByFileName(const QString &fileName) { MimeGlobMatchResult result; const QString fileNameExcludingPath = QFileInfo(fileName).fileName(); + QList checkedMimeTypes; for (const auto &provider : providers()) - provider->addFileNameMatches(fileNameExcludingPath, result); + provider->addFileNameMatches(fileNameExcludingPath, result, checkedMimeTypes); return result; } @@ -325,13 +326,15 @@ QStringList MimeDatabasePrivate::parents(const QString &mimeName) { Q_ASSERT(!mutex.tryLock()); QStringList result; - for (const auto &provider : providers()) - provider->addParents(mimeName, result); - if (result.isEmpty()) { - const QString parent = fallbackParent(mimeName); - if (!parent.isEmpty()) - result.append(parent); + for (const auto &provider : providers()) { + if (provider->hasMimeTypeForName(mimeName)) { + provider->addParents(mimeName, result); + break; + } } + const QString parent = fallbackParent(mimeName); + if (!parent.isEmpty()) + result.append(parent); return result; } @@ -339,8 +342,12 @@ QStringList MimeDatabasePrivate::listAliases(const QString &mimeName) { QMutexLocker locker(&mutex); QStringList result; - for (const auto &provider : providers()) - provider->addAliases(mimeName, result); + for (const auto &provider : providers()) { + if (provider->hasMimeTypeForName(mimeName)) { + provider->addAliases(mimeName, result); + return result; + } + } return result; } @@ -378,8 +385,9 @@ MimeType MimeDatabasePrivate::findByData(const QByteArray &data, int *accuracyPt *accuracyPtr = 0; MimeType candidate; + QList checkedMimeTypes; for (const auto &provider : providers()) - provider->findByMagic(data, accuracyPtr, candidate); + provider->findByMagic(data, accuracyPtr, candidate, checkedMimeTypes); if (candidate.isValid()) return candidate; diff --git a/src/libs/utils/mimetypes2/mimeglobpattern.cpp b/src/libs/utils/mimetypes2/mimeglobpattern.cpp index 354de1fb037..601a4184a01 100644 --- a/src/libs/utils/mimetypes2/mimeglobpattern.cpp +++ b/src/libs/utils/mimetypes2/mimeglobpattern.cpp @@ -255,13 +255,16 @@ void MimeAllGlobPatterns::removeMimeType(const QString &mimeType) } void MimeGlobPatternList::match(MimeGlobMatchResult &result, - const QString &fileName) const + const QString &fileName, + const QList &ignoreMimeTypes) const { MimeGlobPatternList::const_iterator it = this->constBegin(); const MimeGlobPatternList::const_iterator endIt = this->constEnd(); for (; it != endIt; ++it) { const MimeGlobPattern &glob = *it; + if (ignoreMimeTypes.contains(glob.mimeType())) + continue; if (glob.matchFileName(fileName)) { const QString pattern = glob.pattern(); const int suffixLen = isSimplePattern(pattern) ? pattern.length() - 2 : 0; @@ -270,10 +273,12 @@ void MimeGlobPatternList::match(MimeGlobMatchResult &result, } } -void MimeAllGlobPatterns::matchingGlobs(const QString &fileName, MimeGlobMatchResult &result) const +void MimeAllGlobPatterns::matchingGlobs(const QString &fileName, + MimeGlobMatchResult &result, + const QList &ignoreMimeTypes) const { // First try the high weight matches (>50), if any. - m_highWeightGlobs.match(result, fileName); + m_highWeightGlobs.match(result, fileName, ignoreMimeTypes); // 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) @@ -285,14 +290,16 @@ void MimeAllGlobPatterns::matchingGlobs(const QString &fileName, MimeGlobMatchRe const QStringList matchingMimeTypes = m_fastPatterns.value(simpleExtension); const QString simplePattern = QLatin1String("*.") + simpleExtension; - for (const QString &mime : matchingMimeTypes) - result.addMatch(mime, 50, simplePattern, simpleExtension.size()); + for (const QString &mime : matchingMimeTypes) { + if (!ignoreMimeTypes.contains(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, ignoreMimeTypes); } void MimeAllGlobPatterns::clear() diff --git a/src/libs/utils/mimetypes2/mimeglobpattern_p.h b/src/libs/utils/mimetypes2/mimeglobpattern_p.h index b23e0f45ec2..a2f5a83a85b 100644 --- a/src/libs/utils/mimetypes2/mimeglobpattern_p.h +++ b/src/libs/utils/mimetypes2/mimeglobpattern_p.h @@ -140,7 +140,9 @@ public: erase(std::remove_if(begin(), end(), isMimeTypeEqual), end()); } - void match(MimeGlobMatchResult &result, const QString &fileName) const; + void match(MimeGlobMatchResult &result, + const QString &fileName, + const QList &ignoreMimeTypes) const; }; /*! @@ -157,7 +159,9 @@ public: void addGlob(const MimeGlobPattern &glob); void removeMimeType(const QString &mimeType); - void matchingGlobs(const QString &fileName, MimeGlobMatchResult &result) const; + void matchingGlobs(const QString &fileName, + MimeGlobMatchResult &result, + const QList &ignoreMimeTypes) const; void clear(); PatternsMap m_fastPatterns; // example: "doc" -> "application/msword", "text/plain" diff --git a/src/libs/utils/mimetypes2/mimeprovider.cpp b/src/libs/utils/mimetypes2/mimeprovider.cpp index 83c8a7a033d..1f2e7cd31f0 100644 --- a/src/libs/utils/mimetypes2/mimeprovider.cpp +++ b/src/libs/utils/mimetypes2/mimeprovider.cpp @@ -239,29 +239,62 @@ MimeType MimeBinaryProvider::mimeTypeForName(const QString &name) return mimeTypeForNameUnchecked(name); } -void MimeBinaryProvider::addFileNameMatches(const QString &fileName, MimeGlobMatchResult &result) +void MimeBinaryProvider::addFileNameMatches(const QString &fileName, + MimeGlobMatchResult &result, + QList &checkedMimeTypes) { + // TODO checkedMimeTypes if (fileName.isEmpty()) return; Q_ASSERT(m_cacheFile); const QString lowerFileName = fileName.toLower(); // Check literals (e.g. "Makefile") - matchGlobList(result, m_cacheFile, m_cacheFile->getUint32(PosLiteralListOffset), fileName); + matchGlobList(result, + m_cacheFile, + m_cacheFile->getUint32(PosLiteralListOffset), + fileName, + checkedMimeTypes); // Check the very common *.txt cases with the suffix tree if (result.m_matchingMimeTypes.isEmpty()) { const int reverseSuffixTreeOffset = m_cacheFile->getUint32(PosReverseSuffixTreeOffset); const int numRoots = m_cacheFile->getUint32(reverseSuffixTreeOffset); const int firstRootOffset = m_cacheFile->getUint32(reverseSuffixTreeOffset + 4); - matchSuffixTree(result, m_cacheFile, numRoots, firstRootOffset, lowerFileName, lowerFileName.length() - 1, false); + matchSuffixTree(result, + m_cacheFile, + numRoots, + firstRootOffset, + lowerFileName, + lowerFileName.length() - 1, + false, + checkedMimeTypes); if (result.m_matchingMimeTypes.isEmpty()) - matchSuffixTree(result, m_cacheFile, numRoots, firstRootOffset, fileName, fileName.length() - 1, true); + matchSuffixTree(result, + m_cacheFile, + numRoots, + firstRootOffset, + fileName, + fileName.length() - 1, + true, + checkedMimeTypes); } // Check complex globs (e.g. "callgrind.out[0-9]*" or "README*") if (result.m_matchingMimeTypes.isEmpty()) - matchGlobList(result, m_cacheFile, m_cacheFile->getUint32(PosGlobListOffset), fileName); + matchGlobList(result, + m_cacheFile, + m_cacheFile->getUint32(PosGlobListOffset), + fileName, + checkedMimeTypes); + // add all mime types from this provider to checkedMimeTypes, so they + // don't get checked again by another provider (if this provider overrides + // a mime type from another provider) + addAllMimeTypeNames(checkedMimeTypes); } -void MimeBinaryProvider::matchGlobList(MimeGlobMatchResult &result, CacheFile *cacheFile, int off, const QString &fileName) +void MimeBinaryProvider::matchGlobList(MimeGlobMatchResult &result, + CacheFile *cacheFile, + int off, + const QString &fileName, + const QList &ignoreMimeTypes) { const int numGlobs = cacheFile->getUint32(off); //qDebug() << "Loading" << numGlobs << "globs from" << cacheFile->file.fileName() << "at offset" << cacheFile->globListOffset; @@ -275,6 +308,8 @@ void MimeBinaryProvider::matchGlobList(MimeGlobMatchResult &result, CacheFile *c const QString pattern = QLatin1String(cacheFile->getCharStar(globOffset)); const char *mimeType = cacheFile->getCharStar(mimeTypeOffset); + if (ignoreMimeTypes.contains(QLatin1String(mimeType))) + continue; //qDebug() << pattern << mimeType << weight << caseSensitive; MimeGlobPattern glob(pattern, QString() /*unused*/, weight, qtCaseSensitive); @@ -283,7 +318,14 @@ void MimeBinaryProvider::matchGlobList(MimeGlobMatchResult &result, CacheFile *c } } -bool MimeBinaryProvider::matchSuffixTree(MimeGlobMatchResult &result, MimeBinaryProvider::CacheFile *cacheFile, int numEntries, int firstOffset, const QString &fileName, int charPos, bool caseSensitiveCheck) +bool MimeBinaryProvider::matchSuffixTree(MimeGlobMatchResult &result, + MimeBinaryProvider::CacheFile *cacheFile, + int numEntries, + int firstOffset, + const QString &fileName, + int charPos, + bool caseSensitiveCheck, + const QList &ignoreMimeTypes) { QChar fileChar = fileName[charPos]; int min = 0; @@ -302,7 +344,14 @@ bool MimeBinaryProvider::matchSuffixTree(MimeGlobMatchResult &result, MimeBinary int childrenOffset = cacheFile->getUint32(off + 8); bool success = false; if (charPos > 0) - success = matchSuffixTree(result, cacheFile, numChildren, childrenOffset, fileName, charPos, caseSensitiveCheck); + success = matchSuffixTree(result, + cacheFile, + numChildren, + childrenOffset, + fileName, + charPos, + caseSensitiveCheck, + ignoreMimeTypes); if (!success) { for (int i = 0; i < numChildren; ++i) { const int childOff = childrenOffset + 12 * i; @@ -311,6 +360,8 @@ bool MimeBinaryProvider::matchSuffixTree(MimeGlobMatchResult &result, MimeBinary break; const int mimeTypeOffset = cacheFile->getUint32(childOff + 4); const char *mimeType = cacheFile->getCharStar(mimeTypeOffset); + if (ignoreMimeTypes.contains(QLatin1String(mimeType))) + continue; const int flagsAndWeight = cacheFile->getUint32(childOff + 8); const int weight = flagsAndWeight & 0xff; const bool caseSensitive = flagsAndWeight & 0x100; @@ -355,7 +406,10 @@ bool MimeBinaryProvider::matchMagicRule(MimeBinaryProvider::CacheFile *cacheFile return false; } -void MimeBinaryProvider::findByMagic(const QByteArray &data, int *accuracyPtr, MimeType &candidate) +void MimeBinaryProvider::findByMagic(const QByteArray &data, + int *accuracyPtr, + MimeType &candidate, + QList &checkedMimeTypes) { const int magicListOffset = m_cacheFile->getUint32(PosMagicListOffset); const int numMatches = m_cacheFile->getUint32(magicListOffset); @@ -369,6 +423,8 @@ void MimeBinaryProvider::findByMagic(const QByteArray &data, int *accuracyPtr, M if (matchMagicRule(m_cacheFile, numMatchlets, firstMatchletOffset, data)) { const int mimeTypeOffset = m_cacheFile->getUint32(off + 4); const char *mimeType = m_cacheFile->getCharStar(mimeTypeOffset); + if (checkedMimeTypes.contains(QLatin1String(mimeType))) + continue; *accuracyPtr = m_cacheFile->getUint32(off); // Return the first match. We have no rules for conflicting magic data... // (mime.cache itself is sorted, but what about local overrides with a lower prio?) @@ -376,6 +432,10 @@ void MimeBinaryProvider::findByMagic(const QByteArray &data, int *accuracyPtr, M return; } } + // add all mime types from this provider to checkedMimeTypes, so they + // don't get checked again by another provider (if this provider overrides + // a mime type from another provider) + addAllMimeTypeNames(checkedMimeTypes); } void MimeBinaryProvider::addParents(const QString &mime, QStringList &result) @@ -713,16 +773,27 @@ MimeType MimeXMLProvider::mimeTypeForName(const QString &name) return m_nameMimeTypeMap.value(name); } -void MimeXMLProvider::addFileNameMatches(const QString &fileName, MimeGlobMatchResult &result) +void MimeXMLProvider::addFileNameMatches(const QString &fileName, + MimeGlobMatchResult &result, + QList &checkedMimeTypes) { - m_mimeTypeGlobs.matchingGlobs(fileName, result); + m_mimeTypeGlobs.matchingGlobs(fileName, result, checkedMimeTypes); + // add all mime types from this provider to checkedMimeTypes, so they + // don't get checked again by another provider (if this provider overrides + // a mime type from another provider) + addAllMimeTypeNames(checkedMimeTypes); } -void MimeXMLProvider::findByMagic(const QByteArray &data, int *accuracyPtr, MimeType &candidate) +void MimeXMLProvider::findByMagic(const QByteArray &data, + int *accuracyPtr, + MimeType &candidate, + QList &checkedMimeTypes) { QString candidateName; bool foundOne = false; for (const MimeMagicRuleMatcher &matcher : qAsConst(m_magicMatchers)) { + if (checkedMimeTypes.contains(matcher.mimetype())) + continue; if (matcher.matches(data)) { const int priority = matcher.priority(); if (priority > *accuracyPtr) { @@ -734,6 +805,10 @@ void MimeXMLProvider::findByMagic(const QByteArray &data, int *accuracyPtr, Mime } if (foundOne) candidate = mimeTypeForName(candidateName); + // add all mime types from this provider to checkedMimeTypes, so they + // don't get checked again by another provider (if this provider overrides + // a mime type from another provider) + addAllMimeTypeNames(checkedMimeTypes); } void MimeXMLProvider::ensureLoaded() @@ -884,4 +959,44 @@ MimeXMLProvider::MimeXMLProvider(MimeDatabasePrivate *db, } } +bool MimeBinaryProvider::hasMimeTypeForName(const QString &name) +{ + loadMimeTypeList(); + return m_mimetypeNames.contains(name); +} + +void MimeBinaryProvider::addAllMimeTypeNames(QList &result) +{ + // similar to addAllMimeTypes + loadMimeTypeList(); + if (result.isEmpty()) { // fast path + result = QList(m_mimetypeNames.cbegin(), m_mimetypeNames.cend()); + } else { + for (const QString &name : qAsConst(m_mimetypeNames)) + if (!result.contains(name)) + result.append(name); + } +} + +bool MimeXMLProvider::hasMimeTypeForName(const QString &name) +{ + return m_nameMimeTypeMap.contains(name); +} + +void MimeXMLProvider::addAllMimeTypeNames(QList &result) +{ + // similar to addAllMimeTypes + if (result.isEmpty()) { // fast path + result = m_nameMimeTypeMap.keys(); + } else { + for (auto it = m_nameMimeTypeMap.constBegin(), end = m_nameMimeTypeMap.constEnd(); + it != end; + ++it) { + const QString newMime = it.key(); + if (!result.contains(newMime)) + result.append(newMime); + } + } +} + } // namespace Utils diff --git a/src/libs/utils/mimetypes2/mimeprovider_p.h b/src/libs/utils/mimetypes2/mimeprovider_p.h index d298705cf02..f13fbc1340b 100644 --- a/src/libs/utils/mimetypes2/mimeprovider_p.h +++ b/src/libs/utils/mimetypes2/mimeprovider_p.h @@ -70,11 +70,18 @@ public: virtual bool isValid() = 0; virtual bool isInternalDatabase() const = 0; virtual MimeType mimeTypeForName(const QString &name) = 0; - virtual void addFileNameMatches(const QString &fileName, MimeGlobMatchResult &result) = 0; + virtual void addFileNameMatches(const QString &fileName, + MimeGlobMatchResult &result, + QList &checkedMimeTypes) + = 0; virtual void addParents(const QString &mime, QStringList &result) = 0; virtual QString resolveAlias(const QString &name) = 0; virtual void addAliases(const QString &name, QStringList &result) = 0; - virtual void findByMagic(const QByteArray &data, int *accuracyPtr, MimeType &candidate) = 0; + virtual void findByMagic(const QByteArray &data, + int *accuracyPtr, + MimeType &candidate, + QList &checkedMimeTypes) + = 0; virtual void addAllMimeTypes(QList &result) = 0; virtual bool loadMimeTypePrivate(MimeTypePrivate &) { return false; } virtual void loadIcon(MimeTypePrivate &) {} @@ -83,6 +90,10 @@ public: QString directory() const { return m_directory; } + // added for Qt Creator + virtual bool hasMimeTypeForName(const QString &name) = 0; + virtual void addAllMimeTypeNames(QList &result) = 0; + MimeDatabasePrivate *m_db; QString m_directory; }; @@ -99,22 +110,42 @@ public: bool isValid() override; bool isInternalDatabase() const override; MimeType mimeTypeForName(const QString &name) override; - void addFileNameMatches(const QString &fileName, MimeGlobMatchResult &result) override; + void addFileNameMatches(const QString &fileName, + MimeGlobMatchResult &result, + QList &checkedMimeTypes) override; void addParents(const QString &mime, QStringList &result) override; QString resolveAlias(const QString &name) override; void addAliases(const QString &name, QStringList &result) override; - void findByMagic(const QByteArray &data, int *accuracyPtr, MimeType &candidate) override; + void findByMagic(const QByteArray &data, + int *accuracyPtr, + MimeType &candidate, + QList &checkedMimeTypes) override; void addAllMimeTypes(QList &result) override; bool loadMimeTypePrivate(MimeTypePrivate &) override; void loadIcon(MimeTypePrivate &) override; void loadGenericIcon(MimeTypePrivate &) override; void ensureLoaded() override; + // added for Qt Creator + bool hasMimeTypeForName(const QString &name) override; + void addAllMimeTypeNames(QList &result) override; + private: struct CacheFile; - void matchGlobList(MimeGlobMatchResult &result, CacheFile *cacheFile, int offset, const QString &fileName); - bool matchSuffixTree(MimeGlobMatchResult &result, CacheFile *cacheFile, int numEntries, int firstOffset, const QString &fileName, int charPos, bool caseSensitiveCheck); + void matchGlobList(MimeGlobMatchResult &result, + CacheFile *cacheFile, + int offset, + const QString &fileName, + const QList &ignoreMimeTypes); + bool matchSuffixTree(MimeGlobMatchResult &result, + CacheFile *cacheFile, + int numEntries, + int firstOffset, + const QString &fileName, + int charPos, + bool caseSensitiveCheck, + const QList &ignoreMimeTypes); bool matchMagicRule(CacheFile *cacheFile, int numMatchlets, int firstOffset, const QByteArray &data); QLatin1String iconForMime(CacheFile *cacheFile, int posListOffset, const QByteArray &inputMime); void loadMimeTypeList(); @@ -153,11 +184,16 @@ public: bool isValid() override; bool isInternalDatabase() const override; MimeType mimeTypeForName(const QString &name) override; - void addFileNameMatches(const QString &fileName, MimeGlobMatchResult &result) override; + void addFileNameMatches(const QString &fileName, + MimeGlobMatchResult &result, + QList &checkedMimeTypes) override; void addParents(const QString &mime, QStringList &result) override; QString resolveAlias(const QString &name) override; void addAliases(const QString &name, QStringList &result) override; - void findByMagic(const QByteArray &data, int *accuracyPtr, MimeType &candidate) override; + void findByMagic(const QByteArray &data, + int *accuracyPtr, + MimeType &candidate, + QList &checkedMimeTypes) override; void addAllMimeTypes(QList &result) override; void ensureLoaded() override; @@ -170,6 +206,10 @@ public: void addAlias(const QString &alias, const QString &name); void addMagicMatcher(const MimeMagicRuleMatcher &matcher); + // added for Qt Creator + bool hasMimeTypeForName(const QString &name) override; + void addAllMimeTypeNames(QList &result) override; + private: void load(const QString &fileName); void load(const char *data, qsizetype len);