diff options
-rw-r--r-- | src/corelib/mimetypes/mimetypes.qrc | 2 | ||||
-rw-r--r-- | src/corelib/mimetypes/qmimedatabase.cpp | 193 | ||||
-rw-r--r-- | src/corelib/mimetypes/qmimedatabase_p.h | 13 | ||||
-rw-r--r-- | src/corelib/mimetypes/qmimeglobpattern.cpp | 5 | ||||
-rw-r--r-- | src/corelib/mimetypes/qmimeglobpattern_p.h | 2 | ||||
-rw-r--r-- | src/corelib/mimetypes/qmimeprovider.cpp | 461 | ||||
-rw-r--r-- | src/corelib/mimetypes/qmimeprovider_p.h | 51 | ||||
-rw-r--r-- | src/corelib/mimetypes/qmimetype.cpp | 7 | ||||
-rw-r--r-- | src/corelib/mimetypes/qmimetype_p.h | 3 | ||||
-rw-r--r-- | src/corelib/mimetypes/qmimetypeparser.cpp | 1 | ||||
-rw-r--r-- | tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp | 2 |
11 files changed, 392 insertions, 348 deletions
diff --git a/src/corelib/mimetypes/mimetypes.qrc b/src/corelib/mimetypes/mimetypes.qrc index f0cf47cd49..19bc1d3e2a 100644 --- a/src/corelib/mimetypes/mimetypes.qrc +++ b/src/corelib/mimetypes/mimetypes.qrc @@ -1,5 +1,5 @@ <RCC> - <qresource prefix="/qt-project.org/qmime"> + <qresource prefix="/qt-project.org/qmime/packages"> <file alias="freedesktop.org.xml">mime/packages/freedesktop.org.xml</file> </qresource> </RCC> diff --git a/src/corelib/mimetypes/qmimedatabase.cpp b/src/corelib/mimetypes/qmimedatabase.cpp index 38b940d6db..864e9edc61 100644 --- a/src/corelib/mimetypes/qmimedatabase.cpp +++ b/src/corelib/mimetypes/qmimedatabase.cpp @@ -51,6 +51,7 @@ #include <QtCore/QFile> #include <QtCore/QFileInfo> #include <QtCore/QSet> +#include <QtCore/QStandardPaths> #include <QtCore/QBuffer> #include <QtCore/QUrl> #include <QtCore/QDebug> @@ -69,14 +70,13 @@ QMimeDatabasePrivate *QMimeDatabasePrivate::instance() } QMimeDatabasePrivate::QMimeDatabasePrivate() - : m_provider(0), m_defaultMimeType(QLatin1String("application/octet-stream")) + : m_defaultMimeType(QLatin1String("application/octet-stream")) { } QMimeDatabasePrivate::~QMimeDatabasePrivate() { - delete m_provider; - m_provider = 0; + qDeleteAll(m_providers); } Q_CORE_EXPORT int qmime_secondsBetweenChecks = 5; // exported for the unit test @@ -89,24 +89,80 @@ bool QMimeDatabasePrivate::shouldCheck() return true; } -QMimeProviderBase *QMimeDatabasePrivate::provider() -{ - Q_ASSERT(!mutex.tryLock()); // caller should have locked mutex - if (!m_provider) { - QMimeProviderBase *binaryProvider = new QMimeBinaryProvider(this); - if (binaryProvider->isValid()) { - m_provider = binaryProvider; +#if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY) +#define QT_USE_MMAP +#endif + +void QMimeDatabasePrivate::loadProviders() +{ + // We use QStandardPaths every time to check if new files appeared + QStringList mimeDirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QLatin1String("mime"), QStandardPaths::LocateDirectory); + const auto fdoIterator = std::find_if(mimeDirs.constBegin(), mimeDirs.constEnd(), [](const QString &mimeDir) -> bool { + return QFileInfo::exists(mimeDir + QStringLiteral("/packages/freedesktop.org.xml")); } + ); + if (fdoIterator == mimeDirs.constEnd()) + mimeDirs.prepend(QLatin1String(":/qt-project.org/qmime")); + //qDebug() << "mime dirs:" << mimeDirs; + + m_providers.reserve(mimeDirs.size()); + for (const QString &mimeDir : qAsConst(mimeDirs)) { + const QString cacheFile = mimeDir + QStringLiteral("/mime.cache"); + QFileInfo fileInfo(cacheFile); + // Check if we already have a provider for this dir + // [This could be optimized by keeping a copy of mimeDirs and comparing the stringlists] + const auto it = std::find_if(m_providers.begin(), m_providers.end(), [mimeDir](QMimeProviderBase *prov) { return prov->directory() == mimeDir; }); + if (it == m_providers.end()) { + QMimeProviderBase *provider = nullptr; +#if defined(QT_USE_MMAP) + if (qEnvironmentVariableIsEmpty("QT_NO_MIME_CACHE") && fileInfo.exists()) { + provider = new QMimeBinaryProvider(this, mimeDir); + //qDebug() << "Created binary provider for" << mimeDir; + if (!provider->isValid()) { + delete provider; + provider = nullptr; + } + } +#endif + if (!provider) { + provider = new QMimeXMLProvider(this, mimeDir); + //qDebug() << "Created XML provider for" << mimeDir; + } + m_providers.append(provider); } else { - delete binaryProvider; - m_provider = new QMimeXMLProvider(this); + QMimeProviderBase *provider = *it; + provider->ensureLoaded(); + if (!provider->isValid()) { + delete provider; + provider = new QMimeXMLProvider(this, mimeDir); + //qDebug() << "Created XML provider to replace binary provider for" << mimeDir; + *it = provider; + } } - m_provider->ensureLoaded(); + } +} + +QVector<QMimeProviderBase *> QMimeDatabasePrivate::providers() +{ + Q_ASSERT(!mutex.tryLock()); // caller should have locked mutex + if (m_providers.isEmpty()) { + loadProviders(); m_lastCheck.start(); } else { if (shouldCheck()) - m_provider->ensureLoaded(); + loadProviders(); + } + return m_providers; +} + +QString QMimeDatabasePrivate::resolveAlias(const QString &nameOrAlias) +{ + const auto allProviders = providers(); + for (QMimeProviderBase *provider : allProviders) { + const QString ret = provider->resolveAlias(nameOrAlias); + if (!ret.isEmpty()) + return ret; } - return m_provider; + return nameOrAlias; } /*! @@ -115,7 +171,14 @@ QMimeProviderBase *QMimeDatabasePrivate::provider() */ QMimeType QMimeDatabasePrivate::mimeTypeForName(const QString &nameOrAlias) { - return provider()->mimeTypeForName(provider()->resolveAlias(nameOrAlias)); + const auto allProviders = providers(); + const QString mimeName = resolveAlias(nameOrAlias); + for (QMimeProviderBase *provider : allProviders) { + const QMimeType mime = provider->mimeTypeForName(mimeName); + if (mime.isValid()) + return mime; + } + return {}; } QStringList QMimeDatabasePrivate::mimeTypeForFileName(const QString &fileName) @@ -123,44 +186,105 @@ QStringList QMimeDatabasePrivate::mimeTypeForFileName(const QString &fileName) if (fileName.endsWith(QLatin1Char('/'))) return QStringList() << QLatin1String("inode/directory"); - QStringList matchingMimeTypes = provider()->findByFileName(QFileInfo(fileName).fileName()).m_matchingMimeTypes; + const QString shortName = QFileInfo(fileName).fileName(); + const QMimeGlobMatchResult result = findByFileName(shortName); + QStringList matchingMimeTypes = result.m_matchingMimeTypes; matchingMimeTypes.sort(); // make it deterministic return matchingMimeTypes; } QMimeGlobMatchResult QMimeDatabasePrivate::findByFileName(const QString &fileName) { - return provider()->findByFileName(fileName); + QMimeGlobMatchResult result; + // TODO this parses in the order (local, global). Check that it handles "NOGLOBS" correctly. + const auto allProviders = providers(); + for (QMimeProviderBase *provider : allProviders) + provider->addFileNameMatches(fileName, result); + return result; } void QMimeDatabasePrivate::loadMimeTypePrivate(QMimeTypePrivate &mimePrivate) { QMutexLocker locker(&mutex); - provider()->loadMimeTypePrivate(mimePrivate); + if (!mimePrivate.loaded) { // XML provider sets loaded=true, binary provider does this on demand + Q_ASSERT(mimePrivate.fromCache); + QMimeBinaryProvider::loadMimeTypePrivate(mimePrivate); + } } void QMimeDatabasePrivate::loadGenericIcon(QMimeTypePrivate &mimePrivate) { QMutexLocker locker(&mutex); - provider()->loadGenericIcon(mimePrivate); + if (mimePrivate.fromCache) { + mimePrivate.genericIconName.clear(); + const auto allProviders = providers(); + for (QMimeProviderBase *provider : allProviders) { + provider->loadGenericIcon(mimePrivate); + if (!mimePrivate.genericIconName.isEmpty()) + break; + } + } } void QMimeDatabasePrivate::loadIcon(QMimeTypePrivate &mimePrivate) { QMutexLocker locker(&mutex); - provider()->loadIcon(mimePrivate); + if (mimePrivate.fromCache) { + mimePrivate.iconName.clear(); + const auto allProviders = providers(); + for (QMimeProviderBase *provider : allProviders) { + provider->loadIcon(mimePrivate); + if (!mimePrivate.iconName.isEmpty()) + break; + } + } } -QStringList QMimeDatabasePrivate::parents(const QString &mimeName) +static QString fallbackParent(const QString &mimeTypeName) +{ + const QStringRef myGroup = mimeTypeName.leftRef(mimeTypeName.indexOf(QLatin1Char('/'))); + // All text/* types are subclasses of text/plain. + if (myGroup == QLatin1String("text") && mimeTypeName != QLatin1String("text/plain")) + return QLatin1String("text/plain"); + // All real-file mimetypes implicitly derive from application/octet-stream + if (myGroup != QLatin1String("inode") && + // ignore non-file extensions + myGroup != QLatin1String("all") && myGroup != QLatin1String("fonts") && myGroup != QLatin1String("print") && myGroup != QLatin1String("uri") + && mimeTypeName != QLatin1String("application/octet-stream")) { + return QLatin1String("application/octet-stream"); + } + return QString(); +} + +QStringList QMimeDatabasePrivate::mimeParents(const QString &mimeName) { QMutexLocker locker(&mutex); - return provider()->parents(mimeName); + return parents(mimeName); +} + +QStringList QMimeDatabasePrivate::parents(const QString &mimeName) +{ + Q_ASSERT(!mutex.tryLock()); + QStringList result; + const auto allProviders = providers(); + for (QMimeProviderBase *provider : allProviders) + provider->addParents(mimeName, result); + if (result.isEmpty()) { + const QString parent = fallbackParent(mimeName); + if (!parent.isEmpty()) + result.append(parent); + } + return result; } QStringList QMimeDatabasePrivate::listAliases(const QString &mimeName) { QMutexLocker locker(&mutex); - return provider()->listAliases(mimeName); + QStringList result; + const auto allProviders = providers(); + for (QMimeProviderBase *provider : allProviders) + provider->addAliases(mimeName, result); + return result; } bool QMimeDatabasePrivate::mimeInherits(const QString &mime, const QString &parent) @@ -196,7 +320,10 @@ QMimeType QMimeDatabasePrivate::findByData(const QByteArray &data, int *accuracy } *accuracyPtr = 0; - QMimeType candidate = provider()->findByMagic(data, accuracyPtr); + QMimeType candidate; + const auto allProviders = providers(); + for (QMimeProviderBase *provider : allProviders) + provider->findByMagic(data, accuracyPtr, candidate); if (candidate.isValid()) return candidate; @@ -223,7 +350,7 @@ QMimeType QMimeDatabasePrivate::mimeTypeForFileNameAndData(const QString &fileNa if (fileName.endsWith(QLatin1Char('/'))) candidatesByName.addMatch(QLatin1String("inode/directory"), 100, QString()); else - candidatesByName = provider()->findByFileName(QFileInfo(fileName).fileName()); + candidatesByName = findByFileName(QFileInfo(fileName).fileName()); if (candidatesByName.m_allMatchingMimeTypes.count() == 1) { *accuracyPtr = 100; const QMimeType mime = mimeTypeForName(candidatesByName.m_matchingMimeTypes.at(0)); @@ -273,21 +400,25 @@ QMimeType QMimeDatabasePrivate::mimeTypeForFileNameAndData(const QString &fileNa QList<QMimeType> QMimeDatabasePrivate::allMimeTypes() { - return provider()->allMimeTypes(); + QList<QMimeType> result; + const auto allProviders = providers(); + for (QMimeProviderBase *provider : allProviders) + provider->addAllMimeTypes(result); + return result; } bool QMimeDatabasePrivate::inherits(const QString &mime, const QString &parent) { - const QString resolvedParent = provider()->resolveAlias(parent); - //Q_ASSERT(provider()->resolveAlias(mime) == mime); + const QString resolvedParent = resolveAlias(parent); std::stack<QString, QStringList> toCheck; toCheck.push(mime); while (!toCheck.empty()) { if (toCheck.top() == resolvedParent) return true; - const auto parents = provider()->parents(toCheck.top()); + const QString mimeName = toCheck.top(); toCheck.pop(); - for (const QString &par : parents) + const auto parentList = parents(mimeName); + for (const QString &par : parentList) toCheck.push(par); } return false; diff --git a/src/corelib/mimetypes/qmimedatabase_p.h b/src/corelib/mimetypes/qmimedatabase_p.h index 93bdd24b6f..1c38f46115 100644 --- a/src/corelib/mimetypes/qmimedatabase_p.h +++ b/src/corelib/mimetypes/qmimedatabase_p.h @@ -59,8 +59,9 @@ #include "qmimetype_p.h" #include "qmimeglobpattern_p.h" -#include <QtCore/qmutex.h> #include <QtCore/qelapsedtimer.h> +#include <QtCore/qmutex.h> +#include <QtCore/qvector.h> QT_BEGIN_NAMESPACE @@ -84,7 +85,8 @@ public: QList<QMimeType> allMimeTypes(); - + QString resolveAlias(const QString &nameOrAlias); + QStringList parents(const QString &mimeName); QMimeType mimeTypeForName(const QString &nameOrAlias); QMimeType mimeTypeForFileNameAndData(const QString &fileName, QIODevice *device, int *priorityPtr); QMimeType findByData(const QByteArray &data, int *priorityPtr); @@ -95,15 +97,16 @@ public: void loadMimeTypePrivate(QMimeTypePrivate &mimePrivate); void loadGenericIcon(QMimeTypePrivate &mimePrivate); void loadIcon(QMimeTypePrivate &mimePrivate); - QStringList parents(const QString &mimeName); + QStringList mimeParents(const QString &mimeName); QStringList listAliases(const QString &mimeName); bool mimeInherits(const QString &mime, const QString &parent); private: - QMimeProviderBase *provider(); + QVector<QMimeProviderBase *> providers(); bool shouldCheck(); + void loadProviders(); - mutable QMimeProviderBase *m_provider; + mutable QVector<QMimeProviderBase *> m_providers; QElapsedTimer m_lastCheck; public: diff --git a/src/corelib/mimetypes/qmimeglobpattern.cpp b/src/corelib/mimetypes/qmimeglobpattern.cpp index a4d2b046fa..e7b2b879a1 100644 --- a/src/corelib/mimetypes/qmimeglobpattern.cpp +++ b/src/corelib/mimetypes/qmimeglobpattern.cpp @@ -206,10 +206,9 @@ void QMimeGlobPatternList::match(QMimeGlobMatchResult &result, } } -QMimeGlobMatchResult QMimeAllGlobPatterns::matchingGlobs(const QString &fileName) const +void QMimeAllGlobPatterns::matchingGlobs(const QString &fileName, QMimeGlobMatchResult &result) const { // First try the high weight matches (>50), if any. - QMimeGlobMatchResult result; m_highWeightGlobs.match(result, fileName); // Now use the "fast patterns" dict, for simple *.foo patterns with weight 50 @@ -230,8 +229,6 @@ QMimeGlobMatchResult QMimeAllGlobPatterns::matchingGlobs(const QString &fileName // Finally, try the low weight matches (<=50) m_lowWeightGlobs.match(result, fileName); - - return result; } void QMimeAllGlobPatterns::clear() diff --git a/src/corelib/mimetypes/qmimeglobpattern_p.h b/src/corelib/mimetypes/qmimeglobpattern_p.h index 21332e71bc..103729c4ff 100644 --- a/src/corelib/mimetypes/qmimeglobpattern_p.h +++ b/src/corelib/mimetypes/qmimeglobpattern_p.h @@ -152,7 +152,7 @@ public: void addGlob(const QMimeGlobPattern &glob); void removeMimeType(const QString &mimeType); - QMimeGlobMatchResult matchingGlobs(const QString &fileName) const; + void matchingGlobs(const QString &fileName, QMimeGlobMatchResult &result) 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 cd9a2768ee..ec0a6bf0ef 100644 --- a/src/corelib/mimetypes/qmimeprovider.cpp +++ b/src/corelib/mimetypes/qmimeprovider.cpp @@ -61,37 +61,18 @@ static void initResources() QT_BEGIN_NAMESPACE -static QString fallbackParent(const QString &mimeTypeName) -{ - const QStringRef myGroup = mimeTypeName.leftRef(mimeTypeName.indexOf(QLatin1Char('/'))); - // All text/* types are subclasses of text/plain. - if (myGroup == QLatin1String("text") && mimeTypeName != QLatin1String("text/plain")) - return QLatin1String("text/plain"); - // All real-file mimetypes implicitly derive from application/octet-stream - if (myGroup != QLatin1String("inode") && - // ignore non-file extensions - myGroup != QLatin1String("all") && myGroup != QLatin1String("fonts") && myGroup != QLatin1String("print") && myGroup != QLatin1String("uri") - && mimeTypeName != QLatin1String("application/octet-stream")) { - return QLatin1String("application/octet-stream"); - } - return QString(); -} - -QMimeProviderBase::QMimeProviderBase(QMimeDatabasePrivate *db) - : m_db(db) +QMimeProviderBase::QMimeProviderBase(QMimeDatabasePrivate *db, const QString &directory) + : m_db(db), m_directory(directory) { } -QMimeBinaryProvider::QMimeBinaryProvider(QMimeDatabasePrivate *db) - : QMimeProviderBase(db), m_mimetypeListLoaded(false) +QMimeBinaryProvider::QMimeBinaryProvider(QMimeDatabasePrivate *db, const QString &directory) + : QMimeProviderBase(db, directory), m_mimetypeListLoaded(false) { + ensureLoaded(); } -#if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY) -#define QT_USE_MMAP -#endif - struct QMimeBinaryProvider::CacheFile { CacheFile(const QString &fileName); @@ -145,7 +126,6 @@ bool QMimeBinaryProvider::CacheFile::load() bool QMimeBinaryProvider::CacheFile::reload() { - //qDebug() << "reload!" << file->fileName(); m_valid = false; if (file.isOpen()) { file.close(); @@ -154,18 +134,14 @@ bool QMimeBinaryProvider::CacheFile::reload() return load(); } -QMimeBinaryProvider::CacheFile *QMimeBinaryProvider::CacheFileList::findCacheFile(const QString &fileName) const +QMimeBinaryProvider::~QMimeBinaryProvider() { - for (const_iterator it = begin(); it != end(); ++it) { - if ((*it)->file.fileName() == fileName) - return *it; - } - return 0; + delete m_cacheFile; } -QMimeBinaryProvider::~QMimeBinaryProvider() +bool QMimeBinaryProvider::isValid() { - qDeleteAll(m_cacheFiles); + return m_cacheFile != nullptr; } // Position of the "list offsets" values, at the beginning of the mime.cache file @@ -181,76 +157,33 @@ enum { PosGenericIconsListOffset = 36 }; -bool QMimeBinaryProvider::isValid() +bool QMimeBinaryProvider::checkCacheChanged() { -#if defined(QT_USE_MMAP) - if (!qEnvironmentVariableIsEmpty("QT_NO_MIME_CACHE")) - return false; - - Q_ASSERT(m_cacheFiles.isEmpty()); // this method is only ever called once - ensureLoaded(); - - if (m_cacheFiles.count() > 1) + QFileInfo fileInfo(m_cacheFile->file); + if (fileInfo.lastModified() > m_cacheFile->m_mtime) { + // Deletion can't happen by just running update-mime-database. + // But the user could use rm -rf :-) + m_cacheFile->reload(); // will mark itself as invalid on failure return true; - if (m_cacheFiles.isEmpty()) - return false; - - // We found exactly one file; is it the user-modified mimes, or a system file? - const QString foundFile = m_cacheFiles.constFirst()->file.fileName(); - const QString localCacheFile = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/mime/mime.cache"); - - return foundFile != localCacheFile; -#else - return false; -#endif -} - -bool QMimeBinaryProvider::CacheFileList::checkCacheChanged() -{ - bool somethingChanged = false; - for (CacheFile *cacheFile : qAsConst(*this)) { - QFileInfo fileInfo(cacheFile->file); - if (!fileInfo.exists() || fileInfo.lastModified() > cacheFile->m_mtime) { - // Deletion can't happen by just running update-mime-database. - // But the user could use rm -rf :-) - cacheFile->reload(); // will mark itself as invalid on failure - somethingChanged = true; - } } - if (somethingChanged) { - auto deleteIfNoLongerValid = [](CacheFile *cacheFile) -> bool { - const bool invalid = !cacheFile->isValid(); - if (invalid) - delete cacheFile; - return invalid; - }; - erase(std::remove_if(begin(), end(), deleteIfNoLongerValid), end()); - } - return somethingChanged; + return false; } void QMimeBinaryProvider::ensureLoaded() { - // First iterate over existing known cache files and check for uptodate - if (m_cacheFiles.checkCacheChanged()) - m_mimetypeListLoaded = false; - - // Then check if new cache files appeared - const QStringList cacheFileNames = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QLatin1String("mime/mime.cache")); - if (cacheFileNames != m_cacheFileNames) { - for (const QString &cacheFileName : cacheFileNames) { - CacheFile *cacheFile = m_cacheFiles.findCacheFile(cacheFileName); - if (!cacheFile) { - //qDebug() << "new file:" << cacheFileName; - cacheFile = new CacheFile(cacheFileName); - if (cacheFile->isValid()) // verify version - m_cacheFiles.append(cacheFile); - else - delete cacheFile; - } - } - m_cacheFileNames = cacheFileNames; + if (!m_cacheFile) { + const QString cacheFileName = m_directory + QLatin1String("/mime.cache"); + m_cacheFile = new CacheFile(cacheFileName); m_mimetypeListLoaded = false; + } else { + if (checkCacheChanged()) + m_mimetypeListLoaded = false; + else + return; // nothing to do + } + if (!m_cacheFile->isValid()) { // verify existence and version + delete m_cacheFile; + m_cacheFile = nullptr; } } @@ -258,6 +191,7 @@ static QMimeType mimeTypeForNameUnchecked(const QString &name) { QMimeTypePrivate data; data.name = name; + data.fromCache = true; // The rest is retrieved on demand. // comment and globPatterns: in loadMimeTypePrivate // iconName: in loadIcon @@ -274,27 +208,23 @@ QMimeType QMimeBinaryProvider::mimeTypeForName(const QString &name) return mimeTypeForNameUnchecked(name); } -QMimeGlobMatchResult QMimeBinaryProvider::findByFileName(const QString &fileName) +void QMimeBinaryProvider::addFileNameMatches(const QString &fileName, QMimeGlobMatchResult &result) { - QMimeGlobMatchResult result; if (fileName.isEmpty()) - return result; + return; + Q_ASSERT(m_cacheFile); const QString lowerFileName = fileName.toLower(); - // TODO this parses in the order (local, global). Check that it handles "NOGLOBS" correctly. - for (CacheFile *cacheFile : qAsConst(m_cacheFiles)) { - // Check literals (e.g. "Makefile") - matchGlobList(result, cacheFile, cacheFile->getUint32(PosLiteralListOffset), fileName); - // Check complex globs (e.g. "callgrind.out[0-9]*") - matchGlobList(result, cacheFile, cacheFile->getUint32(PosGlobListOffset), fileName); - // Check the very common *.txt cases with the suffix tree - const int reverseSuffixTreeOffset = cacheFile->getUint32(PosReverseSuffixTreeOffset); - const int numRoots = cacheFile->getUint32(reverseSuffixTreeOffset); - const int firstRootOffset = cacheFile->getUint32(reverseSuffixTreeOffset + 4); - matchSuffixTree(result, cacheFile, numRoots, firstRootOffset, lowerFileName, lowerFileName.length() - 1, false); - if (result.m_matchingMimeTypes.isEmpty()) - matchSuffixTree(result, cacheFile, numRoots, firstRootOffset, fileName, fileName.length() - 1, true); - } - return result; + // Check literals (e.g. "Makefile") + matchGlobList(result, m_cacheFile, m_cacheFile->getUint32(PosLiteralListOffset), fileName); + // Check complex globs (e.g. "callgrind.out[0-9]*") + matchGlobList(result, m_cacheFile, m_cacheFile->getUint32(PosGlobListOffset), fileName); + // Check the very common *.txt cases with the suffix tree + 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); + if (result.m_matchingMimeTypes.isEmpty()) + matchSuffixTree(result, m_cacheFile, numRoots, firstRootOffset, fileName, fileName.length() - 1, true); } void QMimeBinaryProvider::matchGlobList(QMimeGlobMatchResult &result, CacheFile *cacheFile, int off, const QString &fileName) @@ -392,120 +322,106 @@ bool QMimeBinaryProvider::matchMagicRule(QMimeBinaryProvider::CacheFile *cacheFi return false; } -QMimeType QMimeBinaryProvider::findByMagic(const QByteArray &data, int *accuracyPtr) -{ - for (CacheFile *cacheFile : qAsConst(m_cacheFiles)) { - const int magicListOffset = cacheFile->getUint32(PosMagicListOffset); - const int numMatches = cacheFile->getUint32(magicListOffset); - //const int maxExtent = cacheFile->getUint32(magicListOffset + 4); - const int firstMatchOffset = cacheFile->getUint32(magicListOffset + 8); - - for (int i = 0; i < numMatches; ++i) { - const int off = firstMatchOffset + i * 16; - const int numMatchlets = cacheFile->getUint32(off + 8); - const int firstMatchletOffset = cacheFile->getUint32(off + 12); - if (matchMagicRule(cacheFile, numMatchlets, firstMatchletOffset, data)) { - const int mimeTypeOffset = cacheFile->getUint32(off + 4); - const char *mimeType = cacheFile->getCharStar(mimeTypeOffset); - *accuracyPtr = 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?) - return mimeTypeForNameUnchecked(QLatin1String(mimeType)); - } +void QMimeBinaryProvider::findByMagic(const QByteArray &data, int *accuracyPtr, QMimeType &candidate) +{ + const int magicListOffset = m_cacheFile->getUint32(PosMagicListOffset); + const int numMatches = m_cacheFile->getUint32(magicListOffset); + //const int maxExtent = cacheFile->getUint32(magicListOffset + 4); + const int firstMatchOffset = m_cacheFile->getUint32(magicListOffset + 8); + + for (int i = 0; i < numMatches; ++i) { + const int off = firstMatchOffset + i * 16; + const int numMatchlets = m_cacheFile->getUint32(off + 8); + const int firstMatchletOffset = m_cacheFile->getUint32(off + 12); + if (matchMagicRule(m_cacheFile, numMatchlets, firstMatchletOffset, data)) { + const int mimeTypeOffset = m_cacheFile->getUint32(off + 4); + const char *mimeType = m_cacheFile->getCharStar(mimeTypeOffset); + *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?) + candidate = mimeTypeForNameUnchecked(QLatin1String(mimeType)); + return; } } - return QMimeType(); } -QStringList QMimeBinaryProvider::parents(const QString &mime) +void QMimeBinaryProvider::addParents(const QString &mime, QStringList &result) { const QByteArray mimeStr = mime.toLatin1(); - QStringList result; - for (CacheFile *cacheFile : qAsConst(m_cacheFiles)) { - const int parentListOffset = cacheFile->getUint32(PosParentListOffset); - const int numEntries = cacheFile->getUint32(parentListOffset); - - int begin = 0; - int end = numEntries - 1; - while (begin <= end) { - const int medium = (begin + end) / 2; - const int off = parentListOffset + 4 + 8 * medium; - const int mimeOffset = cacheFile->getUint32(off); - const char *aMime = cacheFile->getCharStar(mimeOffset); - const int cmp = qstrcmp(aMime, mimeStr); - if (cmp < 0) { - begin = medium + 1; - } else if (cmp > 0) { - end = medium - 1; - } else { - const int parentsOffset = cacheFile->getUint32(off + 4); - const int numParents = cacheFile->getUint32(parentsOffset); - for (int i = 0; i < numParents; ++i) { - const int parentOffset = cacheFile->getUint32(parentsOffset + 4 + 4 * i); - const char *aParent = cacheFile->getCharStar(parentOffset); - result.append(QString::fromLatin1(aParent)); - } - break; + const int parentListOffset = m_cacheFile->getUint32(PosParentListOffset); + const int numEntries = m_cacheFile->getUint32(parentListOffset); + + int begin = 0; + int end = numEntries - 1; + while (begin <= end) { + const int medium = (begin + end) / 2; + const int off = parentListOffset + 4 + 8 * medium; + const int mimeOffset = m_cacheFile->getUint32(off); + const char *aMime = m_cacheFile->getCharStar(mimeOffset); + const int cmp = qstrcmp(aMime, mimeStr); + if (cmp < 0) { + begin = medium + 1; + } else if (cmp > 0) { + end = medium - 1; + } else { + const int parentsOffset = m_cacheFile->getUint32(off + 4); + const int numParents = m_cacheFile->getUint32(parentsOffset); + for (int i = 0; i < numParents; ++i) { + const int parentOffset = m_cacheFile->getUint32(parentsOffset + 4 + 4 * i); + const char *aParent = m_cacheFile->getCharStar(parentOffset); + const QString strParent = QString::fromLatin1(aParent); + if (!result.contains(strParent)) + result.append(strParent); } + break; } } - if (result.isEmpty()) { - const QString parent = fallbackParent(mime); - if (!parent.isEmpty()) - result.append(parent); - } - return result; } QString QMimeBinaryProvider::resolveAlias(const QString &name) { const QByteArray input = name.toLatin1(); - for (CacheFile *cacheFile : qAsConst(m_cacheFiles)) { - const int aliasListOffset = cacheFile->getUint32(PosAliasListOffset); - const int numEntries = cacheFile->getUint32(aliasListOffset); - int begin = 0; - int end = numEntries - 1; - while (begin <= end) { - const int medium = (begin + end) / 2; - const int off = aliasListOffset + 4 + 8 * medium; - const int aliasOffset = cacheFile->getUint32(off); - const char *alias = cacheFile->getCharStar(aliasOffset); - const int cmp = qstrcmp(alias, input); - if (cmp < 0) { - begin = medium + 1; - } else if (cmp > 0) { - end = medium - 1; - } else { - const int mimeOffset = cacheFile->getUint32(off + 4); - const char *mimeType = cacheFile->getCharStar(mimeOffset); - return QLatin1String(mimeType); - } + const int aliasListOffset = m_cacheFile->getUint32(PosAliasListOffset); + const int numEntries = m_cacheFile->getUint32(aliasListOffset); + int begin = 0; + int end = numEntries - 1; + while (begin <= end) { + const int medium = (begin + end) / 2; + const int off = aliasListOffset + 4 + 8 * medium; + const int aliasOffset = m_cacheFile->getUint32(off); + const char *alias = m_cacheFile->getCharStar(aliasOffset); + const int cmp = qstrcmp(alias, input); + if (cmp < 0) { + begin = medium + 1; + } else if (cmp > 0) { + end = medium - 1; + } else { + const int mimeOffset = m_cacheFile->getUint32(off + 4); + const char *mimeType = m_cacheFile->getCharStar(mimeOffset); + return QLatin1String(mimeType); } } - return name; } -QStringList QMimeBinaryProvider::listAliases(const QString &name) +void QMimeBinaryProvider::addAliases(const QString &name, QStringList &result) { - QStringList result; const QByteArray input = name.toLatin1(); - for (CacheFile *cacheFile : qAsConst(m_cacheFiles)) { - const int aliasListOffset = cacheFile->getUint32(PosAliasListOffset); - const int numEntries = cacheFile->getUint32(aliasListOffset); - for (int pos = 0; pos < numEntries; ++pos) { - const int off = aliasListOffset + 4 + 8 * pos; - const int mimeOffset = cacheFile->getUint32(off + 4); - const char *mimeType = cacheFile->getCharStar(mimeOffset); - - if (input == mimeType) { - const int aliasOffset = cacheFile->getUint32(off); - const char *alias = cacheFile->getCharStar(aliasOffset); - result.append(QString::fromLatin1(alias)); - } + const int aliasListOffset = m_cacheFile->getUint32(PosAliasListOffset); + const int numEntries = m_cacheFile->getUint32(aliasListOffset); + for (int pos = 0; pos < numEntries; ++pos) { + const int off = aliasListOffset + 4 + 8 * pos; + const int mimeOffset = m_cacheFile->getUint32(off + 4); + const char *mimeType = m_cacheFile->getCharStar(mimeOffset); + + if (input == mimeType) { + const int aliasOffset = m_cacheFile->getUint32(off); + const char *alias = m_cacheFile->getCharStar(aliasOffset); + const QString strAlias = QString::fromLatin1(alias); + if (!result.contains(strAlias)) + result.append(strAlias); } } - return result; } void QMimeBinaryProvider::loadMimeTypeList() @@ -515,31 +431,30 @@ void QMimeBinaryProvider::loadMimeTypeList() m_mimetypeNames.clear(); // Unfortunately mime.cache doesn't have a full list of all mimetypes. // So we have to parse the plain-text files called "types". - const QStringList typesFilenames = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QLatin1String("mime/types")); - for (const QString &typeFilename : typesFilenames) { - QFile file(typeFilename); - if (file.open(QIODevice::ReadOnly)) { - QTextStream stream(&file); - stream.setCodec("ISO 8859-1"); - QString line; - while (stream.readLineInto(&line)) - m_mimetypeNames.insert(line); - } + QFile file(m_directory + QStringLiteral("/types")); + if (file.open(QIODevice::ReadOnly)) { + QTextStream stream(&file); + stream.setCodec("ISO 8859-1"); + QString line; + while (stream.readLineInto(&line)) + m_mimetypeNames.insert(line); } } } -QList<QMimeType> QMimeBinaryProvider::allMimeTypes() +void QMimeBinaryProvider::addAllMimeTypes(QList<QMimeType> &result) { - QList<QMimeType> result; loadMimeTypeList(); - result.reserve(m_mimetypeNames.count()); - - for (QSet<QString>::const_iterator it = m_mimetypeNames.constBegin(); - it != m_mimetypeNames.constEnd(); ++it) - result.append(mimeTypeForNameUnchecked(*it)); - - return result; + if (result.isEmpty()) { + result.reserve(m_mimetypeNames.count()); + for (const QString &name : m_mimetypeNames) + result.append(mimeTypeForNameUnchecked(name)); + } else { + for (const QString &name : m_mimetypeNames) + if (std::find_if(result.constBegin(), result.constEnd(), [name](const QMimeType &mime) -> bool { return mime.name() == name; }) + == result.constEnd()) + result.append(mimeTypeForNameUnchecked(name)); + } } void QMimeBinaryProvider::loadMimeTypePrivate(QMimeTypePrivate &data) @@ -664,33 +579,28 @@ QLatin1String QMimeBinaryProvider::iconForMime(CacheFile *cacheFile, int posList void QMimeBinaryProvider::loadIcon(QMimeTypePrivate &data) { const QByteArray inputMime = data.name.toLatin1(); - for (CacheFile *cacheFile : qAsConst(m_cacheFiles)) { - const QLatin1String icon = iconForMime(cacheFile, PosIconsListOffset, inputMime); - if (!icon.isEmpty()) { - data.iconName = icon; - return; - } + const QLatin1String icon = iconForMime(m_cacheFile, PosIconsListOffset, inputMime); + if (!icon.isEmpty()) { + data.iconName = icon; } } void QMimeBinaryProvider::loadGenericIcon(QMimeTypePrivate &data) { const QByteArray inputMime = data.name.toLatin1(); - for (CacheFile *cacheFile : qAsConst(m_cacheFiles)) { - const QLatin1String icon = iconForMime(cacheFile, PosGenericIconsListOffset, inputMime); - if (!icon.isEmpty()) { - data.genericIconName = icon; - return; - } + const QLatin1String icon = iconForMime(m_cacheFile, PosGenericIconsListOffset, inputMime); + if (!icon.isEmpty()) { + data.genericIconName = icon; } } //// -QMimeXMLProvider::QMimeXMLProvider(QMimeDatabasePrivate *db) - : QMimeProviderBase(db) +QMimeXMLProvider::QMimeXMLProvider(QMimeDatabasePrivate *db, const QString &directory) + : QMimeProviderBase(db, directory) { initResources(); + ensureLoaded(); } QMimeXMLProvider::~QMimeXMLProvider() @@ -699,6 +609,8 @@ QMimeXMLProvider::~QMimeXMLProvider() bool QMimeXMLProvider::isValid() { + // If you change this method, adjust the logic in QMimeDatabasePrivate::loadProviders, + // which assumes isValid==false is only possible in QMimeBinaryProvider. return true; } @@ -707,50 +619,38 @@ QMimeType QMimeXMLProvider::mimeTypeForName(const QString &name) return m_nameMimeTypeMap.value(name); } -QMimeGlobMatchResult QMimeXMLProvider::findByFileName(const QString &fileName) +void QMimeXMLProvider::addFileNameMatches(const QString &fileName, QMimeGlobMatchResult &result) { - return m_mimeTypeGlobs.matchingGlobs(fileName); + m_mimeTypeGlobs.matchingGlobs(fileName, result); } -QMimeType QMimeXMLProvider::findByMagic(const QByteArray &data, int *accuracyPtr) +void QMimeXMLProvider::findByMagic(const QByteArray &data, int *accuracyPtr, QMimeType &candidate) { - QString candidate; - + QString candidateName; + bool foundOne = false; for (const QMimeMagicRuleMatcher &matcher : qAsConst(m_magicMatchers)) { if (matcher.matches(data)) { const int priority = matcher.priority(); if (priority > *accuracyPtr) { *accuracyPtr = priority; - candidate = matcher.mimetype(); + candidateName = matcher.mimetype(); + foundOne = true; } } } - return mimeTypeForName(candidate); + if (foundOne) + candidate = mimeTypeForName(candidateName); } void QMimeXMLProvider::ensureLoaded() { - bool fdoXmlFound = false; QStringList allFiles; - - const QStringList packageDirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QLatin1String("mime/packages"), QStandardPaths::LocateDirectory); - //qDebug() << "packageDirs=" << packageDirs; - for (const QString &packageDir : packageDirs) { - QDir dir(packageDir); - const QStringList files = dir.entryList(QDir::Files | QDir::NoDotAndDotDot); - //qDebug() << static_cast<const void *>(this) << packageDir << files; - if (!fdoXmlFound) - fdoXmlFound = files.contains(QLatin1String("freedesktop.org.xml")); - QStringList::const_iterator endIt(files.constEnd()); - for (QStringList::const_iterator it(files.constBegin()); it != endIt; ++it) { - allFiles.append(packageDir + QLatin1Char('/') + *it); - } - } - - if (!fdoXmlFound) { - // We could instead install the file as part of installing Qt? - allFiles.prepend(QLatin1String(":/qt-project.org/qmime/freedesktop.org.xml")); - } + const QString packageDir = m_directory + QStringLiteral("/packages"); + QDir dir(packageDir); + const QStringList files = dir.entryList(QDir::Files | QDir::NoDotAndDotDot); + allFiles.reserve(files.count()); + for (const QString &xmlFile : files) + allFiles.append(packageDir + QLatin1Char('/') + xmlFile); if (m_allFiles == allFiles) return; @@ -798,18 +698,16 @@ void QMimeXMLProvider::addGlobPattern(const QMimeGlobPattern &glob) void QMimeXMLProvider::addMimeType(const QMimeType &mt) { + Q_ASSERT(!mt.d.data()->fromCache); m_nameMimeTypeMap.insert(mt.name(), mt); } -QStringList QMimeXMLProvider::parents(const QString &mime) +void QMimeXMLProvider::addParents(const QString &mime, QStringList &result) { - QStringList result = m_parents.value(mime); - if (result.isEmpty()) { - const QString parent = fallbackParent(mime); - if (!parent.isEmpty()) + for (const QString &parent : m_parents.value(mime)) { + if (!result.contains(parent)) result.append(parent); } - return result; } void QMimeXMLProvider::addParent(const QString &child, const QString &parent) @@ -817,10 +715,16 @@ void QMimeXMLProvider::addParent(const QString &child, const QString &parent) m_parents[child].append(parent); } -QStringList QMimeXMLProvider::listAliases(const QString &name) +void QMimeXMLProvider::addAliases(const QString &name, QStringList &result) { // Iterate through the whole hash. This method is rarely used. - return m_aliases.keys(name); + for (auto it = m_aliases.constBegin(), end = m_aliases.constEnd() ; it != end ; ++it) { + if (it.value() == name) { + if (!result.contains(it.key())) + result.append(it.key()); + } + } + } QString QMimeXMLProvider::resolveAlias(const QString &name) @@ -833,9 +737,18 @@ void QMimeXMLProvider::addAlias(const QString &alias, const QString &name) m_aliases.insert(alias, name); } -QList<QMimeType> QMimeXMLProvider::allMimeTypes() +void QMimeXMLProvider::addAllMimeTypes(QList<QMimeType> &result) { - return m_nameMimeTypeMap.values(); + if (result.isEmpty()) { // fast path + result = m_nameMimeTypeMap.values(); + } else { + for (auto it = m_nameMimeTypeMap.constBegin(), end = m_nameMimeTypeMap.constEnd() ; it != end ; ++it) { + const QString newMime = it.key(); + if (std::find_if(result.constBegin(), result.constEnd(), [newMime](const QMimeType &mime) -> bool { return mime.name() == newMime; }) + == result.constEnd()) + result.append(it.value()); + } + } } void QMimeXMLProvider::addMagicMatcher(const QMimeMagicRuleMatcher &matcher) diff --git a/src/corelib/mimetypes/qmimeprovider_p.h b/src/corelib/mimetypes/qmimeprovider_p.h index 7344d8b453..b2be545cf8 100644 --- a/src/corelib/mimetypes/qmimeprovider_p.h +++ b/src/corelib/mimetypes/qmimeprovider_p.h @@ -67,23 +67,25 @@ class QMimeMagicRuleMatcher; class QMimeProviderBase { public: - QMimeProviderBase(QMimeDatabasePrivate *db); + QMimeProviderBase(QMimeDatabasePrivate *db, const QString &directory); virtual ~QMimeProviderBase() {} virtual bool isValid() = 0; virtual QMimeType mimeTypeForName(const QString &name) = 0; - virtual QMimeGlobMatchResult findByFileName(const QString &fileName) = 0; - virtual QStringList parents(const QString &mime) = 0; + virtual void addFileNameMatches(const QString &fileName, QMimeGlobMatchResult &result) = 0; + virtual void addParents(const QString &mime, QStringList &result) = 0; virtual QString resolveAlias(const QString &name) = 0; - virtual QStringList listAliases(const QString &name) = 0; - virtual QMimeType findByMagic(const QByteArray &data, int *accuracyPtr) = 0; - virtual QList<QMimeType> allMimeTypes() = 0; - virtual void loadMimeTypePrivate(QMimeTypePrivate &) {} + virtual void addAliases(const QString &name, QStringList &result) = 0; + virtual void findByMagic(const QByteArray &data, int *accuracyPtr, QMimeType &candidate) = 0; + virtual void addAllMimeTypes(QList<QMimeType> &result) = 0; virtual void loadIcon(QMimeTypePrivate &) {} virtual void loadGenericIcon(QMimeTypePrivate &) {} virtual void ensureLoaded() {} + QString directory() const { return m_directory; } + QMimeDatabasePrivate *m_db; + QString m_directory; }; /* @@ -92,18 +94,18 @@ public: class QMimeBinaryProvider : public QMimeProviderBase { public: - QMimeBinaryProvider(QMimeDatabasePrivate *db); + QMimeBinaryProvider(QMimeDatabasePrivate *db, const QString &directory); virtual ~QMimeBinaryProvider(); virtual bool isValid() override; virtual QMimeType mimeTypeForName(const QString &name) override; - virtual QMimeGlobMatchResult findByFileName(const QString &fileName) override; - virtual QStringList parents(const QString &mime) override; + void addFileNameMatches(const QString &fileName, QMimeGlobMatchResult &result) override; + void addParents(const QString &mime, QStringList &result) override; virtual QString resolveAlias(const QString &name) override; - virtual QStringList listAliases(const QString &name) override; - virtual QMimeType findByMagic(const QByteArray &data, int *accuracyPtr) override; - virtual QList<QMimeType> allMimeTypes() override; - virtual void loadMimeTypePrivate(QMimeTypePrivate &) override; + void addAliases(const QString &name, QStringList &result) override; + void findByMagic(const QByteArray &data, int *accuracyPtr, QMimeType &candidate) override; + void addAllMimeTypes(QList<QMimeType> &result) override; + static void loadMimeTypePrivate(QMimeTypePrivate &); virtual void loadIcon(QMimeTypePrivate &) override; virtual void loadGenericIcon(QMimeTypePrivate &) override; void ensureLoaded() override; @@ -116,14 +118,9 @@ private: bool matchMagicRule(CacheFile *cacheFile, int numMatchlets, int firstOffset, const QByteArray &data); QLatin1String iconForMime(CacheFile *cacheFile, int posListOffset, const QByteArray &inputMime); void loadMimeTypeList(); + bool checkCacheChanged(); - class CacheFileList : public QList<CacheFile *> - { - public: - CacheFile *findCacheFile(const QString &fileName) const; - bool checkCacheChanged(); - }; - CacheFileList m_cacheFiles; + CacheFile *m_cacheFile = nullptr; QStringList m_cacheFileNames; QSet<QString> m_mimetypeNames; bool m_mimetypeListLoaded; @@ -135,17 +132,17 @@ private: class QMimeXMLProvider : public QMimeProviderBase { public: - QMimeXMLProvider(QMimeDatabasePrivate *db); + QMimeXMLProvider(QMimeDatabasePrivate *db, const QString &directory); ~QMimeXMLProvider(); virtual bool isValid() override; virtual QMimeType mimeTypeForName(const QString &name) override; - virtual QMimeGlobMatchResult findByFileName(const QString &fileName) override; - virtual QStringList parents(const QString &mime) override; + void addFileNameMatches(const QString &fileName, QMimeGlobMatchResult &result) override; + void addParents(const QString &mime, QStringList &result) override; virtual QString resolveAlias(const QString &name) override; - virtual QStringList listAliases(const QString &name) override; - virtual QMimeType findByMagic(const QByteArray &data, int *accuracyPtr) override; - virtual QList<QMimeType> allMimeTypes() override; + void addAliases(const QString &name, QStringList &result) override; + void findByMagic(const QByteArray &data, int *accuracyPtr, QMimeType &candidate) override; + void addAllMimeTypes(QList<QMimeType> &result) override; void ensureLoaded() override; bool load(const QString &fileName, QString *errorMessage); diff --git a/src/corelib/mimetypes/qmimetype.cpp b/src/corelib/mimetypes/qmimetype.cpp index 668b22e7cf..8f6237c1cb 100644 --- a/src/corelib/mimetypes/qmimetype.cpp +++ b/src/corelib/mimetypes/qmimetype.cpp @@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE QMimeTypePrivate::QMimeTypePrivate() - : loaded(false) + : loaded(false), fromCache(false) {} QMimeTypePrivate::QMimeTypePrivate(const QMimeType &other) @@ -76,7 +76,6 @@ void QMimeTypePrivate::clear() genericIconName.clear(); iconName.clear(); globPatterns.clear(); - loaded = false; } void QMimeTypePrivate::addGlobPattern(const QString &pattern) @@ -368,12 +367,12 @@ QStringList QMimeType::globPatterns() const */ QStringList QMimeType::parentMimeTypes() const { - return QMimeDatabasePrivate::instance()->parents(d->name); + return QMimeDatabasePrivate::instance()->mimeParents(d->name); } static void collectParentMimeTypes(const QString &mime, QStringList &allParents) { - const QStringList parents = QMimeDatabasePrivate::instance()->parents(mime); + const QStringList parents = QMimeDatabasePrivate::instance()->mimeParents(mime); for (const QString &parent : parents) { // I would use QSet, but since order matters I better not if (!allParents.contains(parent)) diff --git a/src/corelib/mimetypes/qmimetype_p.h b/src/corelib/mimetypes/qmimetype_p.h index b0bfad2f65..aa38a1adf5 100644 --- a/src/corelib/mimetypes/qmimetype_p.h +++ b/src/corelib/mimetypes/qmimetype_p.h @@ -74,6 +74,7 @@ public: void addGlobPattern(const QString &pattern); bool loaded; // QSharedData leaves a 4 byte gap, so don't put 8 byte members first + bool fromCache; // true if this comes from the binary provider QString name; LocaleHash localeComments; QString genericIconName; @@ -94,6 +95,7 @@ QT_END_NAMESPACE { \ QMimeTypePrivate qMimeTypeData; \ qMimeTypeData.name = name; \ + qMimeTypeData.loaded = true; \ qMimeTypeData.genericIconName = genericIconName; \ qMimeTypeData.iconName = iconName; \ qMimeTypeData.globPatterns = globPatterns; \ @@ -112,6 +114,7 @@ QT_END_NAMESPACE ) \ { \ QMimeTypePrivate qMimeTypeData; \ + qMimeTypeData.loaded = true; \ qMimeTypeData.name = std::move(name); \ qMimeTypeData.genericIconName = std::move(genericIconName); \ qMimeTypeData.iconName = std::move(iconName); \ diff --git a/src/corelib/mimetypes/qmimetypeparser.cpp b/src/corelib/mimetypes/qmimetypeparser.cpp index 5ecd339908..0a55560ab0 100644 --- a/src/corelib/mimetypes/qmimetypeparser.cpp +++ b/src/corelib/mimetypes/qmimetypeparser.cpp @@ -201,6 +201,7 @@ bool QMimeTypeParserBase::parse(QIODevice *dev, const QString &fileName, QString return false; #else QMimeTypePrivate data; + data.loaded = true; int priority = 50; QStack<QMimeMagicRule *> currentRules; // stack for the nesting of rules QList<QMimeMagicRule> rules; // toplevel rules diff --git a/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp b/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp index 8883b6360f..ad45daade9 100644 --- a/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp +++ b/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp @@ -148,7 +148,7 @@ void tst_QMimeDatabase::initTestCase() qDebug() << "\nGlobal XDG_DATA_DIRS: " << m_globalXdgDir; const QString freeDesktopXml = QStringLiteral("freedesktop.org.xml"); - const QString xmlFileName = QLatin1String(RESOURCE_PREFIX) + freeDesktopXml; + const QString xmlFileName = QLatin1String(RESOURCE_PREFIX "packages/") + freeDesktopXml; const QString xmlTargetFileName = globalPackageDir + QLatin1Char('/') + freeDesktopXml; QVERIFY2(copyResourceFile(xmlFileName, xmlTargetFileName, &errorMessage), qPrintable(errorMessage)); #endif |