diff options
Diffstat (limited to 'src/corelib/mimetypes/qmimedatabase.cpp')
-rw-r--r-- | src/corelib/mimetypes/qmimedatabase.cpp | 165 |
1 files changed, 89 insertions, 76 deletions
diff --git a/src/corelib/mimetypes/qmimedatabase.cpp b/src/corelib/mimetypes/qmimedatabase.cpp index 6d6b322229..d52ccacbe7 100644 --- a/src/corelib/mimetypes/qmimedatabase.cpp +++ b/src/corelib/mimetypes/qmimedatabase.cpp @@ -10,9 +10,9 @@ #include "qmimeprovider_p.h" #include "qmimetype_p.h" +#include <private/qduplicatetracker_p.h> #include <private/qfilesystementry_p.h> -#include <QtCore/QMap> #include <QtCore/QFile> #include <QtCore/QFileInfo> #include <QtCore/QStandardPaths> @@ -74,7 +74,7 @@ static QStringList locateMimeDirectories() return QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("mime"), QStandardPaths::LocateDirectory); } -#if defined(Q_OS_UNIX) && !defined(Q_OS_NACL) && !defined(Q_OS_INTEGRITY) +#if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY) # define QT_USE_MMAP #endif @@ -142,6 +142,13 @@ void QMimeDatabasePrivate::loadProviders() m_providers.push_back(std::move(*it)); } } + + auto it = m_providers.begin(); + (*it)->setOverrideProvider(nullptr); + ++it; + const auto end = m_providers.end(); + for (; it != end; ++it) + (*it)->setOverrideProvider((it - 1)->get()); } const QMimeDatabasePrivate::Providers &QMimeDatabasePrivate::providers() @@ -177,9 +184,8 @@ QMimeType QMimeDatabasePrivate::mimeTypeForName(const QString &nameOrAlias) { const QString mimeName = resolveAlias(nameOrAlias); for (const auto &provider : providers()) { - const QMimeType mime = provider->mimeTypeForName(mimeName); - if (mime.isValid()) - return mime; + if (provider->knowsMimeType(mimeName)) + return QMimeType(QMimeTypePrivate(mimeName)); } return {}; } @@ -204,54 +210,54 @@ QMimeGlobMatchResult QMimeDatabasePrivate::findByFileName(const QString &fileNam return result; } -void QMimeDatabasePrivate::loadMimeTypePrivate(QMimeTypePrivate &mimePrivate) +QMimeTypePrivate::LocaleHash QMimeDatabasePrivate::localeComments(const QString &name) { QMutexLocker locker(&mutex); - if (mimePrivate.name.isEmpty()) - return; // invalid mimetype - if (!mimePrivate.loaded) { // XML provider sets loaded=true, binary provider does this on demand - Q_ASSERT(mimePrivate.fromCache); - bool found = false; - for (const auto &provider : providers()) { - if (provider->loadMimeTypePrivate(mimePrivate)) { - found = true; - break; - } - } - if (!found) { - const QString file = mimePrivate.name + ".xml"_L1; - qWarning() << "No file found for" << file << ", even though update-mime-info said it would exist.\n" - "Either it was just removed, or the directory doesn't have executable permission..." - << locateMimeDirectories(); - } - mimePrivate.loaded = true; + for (const auto &provider : providers()) { + auto comments = provider->localeComments(name); + if (!comments.isEmpty()) + return comments; // maybe we want to merge in comments from more global providers, in + // case of more translations? } + return {}; } -void QMimeDatabasePrivate::loadGenericIcon(QMimeTypePrivate &mimePrivate) +QStringList QMimeDatabasePrivate::globPatterns(const QString &name) { QMutexLocker locker(&mutex); - if (mimePrivate.fromCache) { - mimePrivate.genericIconName.clear(); - for (const auto &provider : providers()) { - provider->loadGenericIcon(mimePrivate); - if (!mimePrivate.genericIconName.isEmpty()) - break; - } + QStringList patterns; + const auto &providerList = providers(); + // reverse iteration because we start from most global, add up, clear if delete-all, and add up + // again. + for (auto rit = providerList.rbegin(); rit != providerList.rend(); ++rit) { + auto *provider = rit->get(); + if (provider->hasGlobDeleteAll(name)) + patterns.clear(); + patterns += provider->globPatterns(name); } + return patterns; } -void QMimeDatabasePrivate::loadIcon(QMimeTypePrivate &mimePrivate) +QString QMimeDatabasePrivate::genericIcon(const QString &name) { QMutexLocker locker(&mutex); - if (mimePrivate.fromCache) { - mimePrivate.iconName.clear(); - for (const auto &provider : providers()) { - provider->loadIcon(mimePrivate); - if (!mimePrivate.iconName.isEmpty()) - break; - } + for (const auto &provider : providers()) { + QString genericIconName = provider->genericIcon(name); + if (!genericIconName.isEmpty()) + return genericIconName; } + return {}; +} + +QString QMimeDatabasePrivate::icon(const QString &name) +{ + QMutexLocker locker(&mutex); + for (const auto &provider : providers()) { + QString iconName = provider->icon(name); + if (!iconName.isEmpty()) + return iconName; + } + return {}; } QString QMimeDatabasePrivate::fallbackParent(const QString &mimeTypeName) const @@ -331,13 +337,14 @@ QMimeType QMimeDatabasePrivate::findByData(const QByteArray &data, int *accuracy return mimeTypeForName(QStringLiteral("application/x-zerosize")); } - *accuracyPtr = 0; - QMimeType candidate; + QMimeMagicResult result; for (const auto &provider : providers()) - provider->findByMagic(data, accuracyPtr, candidate); + provider->findByMagic(data, result); - if (candidate.isValid()) - return candidate; + if (result.isValid()) { + *accuracyPtr = result.accuracy; + return QMimeType(QMimeTypePrivate(result.candidate)); + } if (isTextFile(data)) { *accuracyPtr = 5; @@ -357,7 +364,7 @@ QMimeType QMimeDatabasePrivate::mimeTypeForFileNameAndData(const QString &fileNa // Pass 1) Try to match on the file name QMimeGlobMatchResult candidatesByName = findByFileName(fileName); - if (candidatesByName.m_allMatchingMimeTypes.count() == 1) { + if (candidatesByName.m_allMatchingMimeTypes.size() == 1) { const QMimeType mime = mimeTypeForName(candidatesByName.m_matchingMimeTypes.at(0)); if (mime.isValid()) return mime; @@ -386,7 +393,7 @@ QMimeType QMimeDatabasePrivate::mimeTypeForFileNameAndData(const QString &fileNa if (candidatesByName.m_matchingMimeTypes.contains(sniffedMime)) { return candidateByData; } - for (const QString &m : qAsConst(candidatesByName.m_allMatchingMimeTypes)) { + for (const QString &m : std::as_const(candidatesByName.m_allMatchingMimeTypes)) { if (inherits(m, sniffedMime)) { // We have magic + pattern pointing to this, so it's a pretty good match return mimeTypeForName(m); @@ -399,7 +406,7 @@ QMimeType QMimeDatabasePrivate::mimeTypeForFileNameAndData(const QString &fileNa } } - if (candidatesByName.m_allMatchingMimeTypes.count() > 1) { + if (candidatesByName.m_allMatchingMimeTypes.size() > 1) { candidatesByName.m_matchingMimeTypes.sort(); // make it deterministic const QMimeType mime = mimeTypeForName(candidatesByName.m_matchingMimeTypes.at(0)); if (mime.isValid()) @@ -444,31 +451,32 @@ QMimeType QMimeDatabasePrivate::mimeTypeForData(QIODevice *device) } QMimeType QMimeDatabasePrivate::mimeTypeForFile(const QString &fileName, - [[maybe_unused]] const QFileInfo *fileInfo, + const QFileInfo &fileInfo, QMimeDatabase::MatchMode mode) { + if (false) { #ifdef Q_OS_UNIX - // Cannot access statBuf.st_mode from the filesystem engine, so we have to stat again. - // In addition we want to follow symlinks. - const QByteArray nativeFilePath = QFile::encodeName(fileName); - QT_STATBUF statBuffer; - if (QT_STAT(nativeFilePath.constData(), &statBuffer) == 0) { - if (S_ISDIR(statBuffer.st_mode)) - return mimeTypeForName(directoryMimeType()); - if (S_ISCHR(statBuffer.st_mode)) - return mimeTypeForName(QStringLiteral("inode/chardevice")); - if (S_ISBLK(statBuffer.st_mode)) - return mimeTypeForName(QStringLiteral("inode/blockdevice")); - if (S_ISFIFO(statBuffer.st_mode)) - return mimeTypeForName(QStringLiteral("inode/fifo")); - if (S_ISSOCK(statBuffer.st_mode)) - return mimeTypeForName(QStringLiteral("inode/socket")); - } -#else - const bool isDirectory = fileInfo ? fileInfo->isDir() : QFileInfo(fileName).isDir(); - if (isDirectory) - return mimeTypeForName(directoryMimeType()); + } else if (fileInfo.isNativePath()) { + // If this is a local file, we'll want to do a stat() ourselves so we can + // detect additional inode types. In addition we want to follow symlinks. + const QByteArray nativeFilePath = QFile::encodeName(fileName); + QT_STATBUF statBuffer; + if (QT_STAT(nativeFilePath.constData(), &statBuffer) == 0) { + if (S_ISDIR(statBuffer.st_mode)) + return mimeTypeForName(directoryMimeType()); + if (S_ISCHR(statBuffer.st_mode)) + return mimeTypeForName(QStringLiteral("inode/chardevice")); + if (S_ISBLK(statBuffer.st_mode)) + return mimeTypeForName(QStringLiteral("inode/blockdevice")); + if (S_ISFIFO(statBuffer.st_mode)) + return mimeTypeForName(QStringLiteral("inode/fifo")); + if (S_ISSOCK(statBuffer.st_mode)) + return mimeTypeForName(QStringLiteral("inode/socket")); + } #endif + } else if (fileInfo.isDir()) { + return mimeTypeForName(directoryMimeType()); + } switch (mode) { case QMimeDatabase::MatchDefault: @@ -495,6 +503,7 @@ QList<QMimeType> QMimeDatabasePrivate::allMimeTypes() bool QMimeDatabasePrivate::inherits(const QString &mime, const QString &parent) { const QString resolvedParent = resolveAlias(parent); + QDuplicateTracker<QString> seen; std::stack<QString, QStringList> toCheck; toCheck.push(mime); while (!toCheck.empty()) { @@ -503,8 +512,11 @@ bool QMimeDatabasePrivate::inherits(const QString &mime, const QString &parent) const QString mimeName = toCheck.top(); toCheck.pop(); const auto parentList = parents(mimeName); - for (const QString &par : parentList) - toCheck.push(resolveAlias(par)); + for (const QString &par : parentList) { + const QString resolvedPar = resolveAlias(par); + if (!seen.hasSeen(resolvedPar)) + toCheck.push(resolvedPar); + } } return false; } @@ -546,7 +558,7 @@ bool QMimeDatabasePrivate::inherits(const QString &mime, const QString &parent) \snippet code/src_corelib_mimetype_qmimedatabase.cpp 0 - \sa QMimeType, {MIME Type Browser Example} + \sa QMimeType, {MIME Type Browser} */ /*! @@ -615,7 +627,7 @@ QMimeType QMimeDatabase::mimeTypeForFile(const QFileInfo &fileInfo, MatchMode mo { QMutexLocker locker(&d->mutex); - return d->mimeTypeForFile(fileInfo.filePath(), &fileInfo, mode); + return d->mimeTypeForFile(fileInfo.filePath(), fileInfo, mode); } /*! @@ -630,7 +642,8 @@ QMimeType QMimeDatabase::mimeTypeForFile(const QString &fileName, MatchMode mode if (mode == MatchExtension) { return d->mimeTypeForFileExtension(fileName); } else { - return d->mimeTypeForFile(fileName, nullptr, mode); + QFileInfo fileInfo(fileName); + return d->mimeTypeForFile(fileName, fileInfo, mode); } } @@ -652,7 +665,7 @@ QList<QMimeType> QMimeDatabase::mimeTypesForFileName(const QString &fileName) co const QStringList matches = d->mimeTypeForFileName(fileName); QList<QMimeType> mimes; - mimes.reserve(matches.count()); + mimes.reserve(matches.size()); for (const QString &mime : matches) mimes.append(d->mimeTypeForName(mime)); return mimes; @@ -666,7 +679,7 @@ QList<QMimeType> QMimeDatabase::mimeTypesForFileName(const QString &fileName) co QString QMimeDatabase::suffixForFileName(const QString &fileName) const { QMutexLocker locker(&d->mutex); - const int suffixLength = d->findByFileName(fileName).m_knownSuffixLength; + const qsizetype suffixLength = d->findByFileName(fileName).m_knownSuffixLength; return fileName.right(suffixLength); } |