summaryrefslogtreecommitdiffstats
path: root/src/corelib/mimetypes/qmimeprovider.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/mimetypes/qmimeprovider.cpp')
-rw-r--r--src/corelib/mimetypes/qmimeprovider.cpp321
1 files changed, 168 insertions, 153 deletions
diff --git a/src/corelib/mimetypes/qmimeprovider.cpp b/src/corelib/mimetypes/qmimeprovider.cpp
index 177895ff6c..458cd46385 100644
--- a/src/corelib/mimetypes/qmimeprovider.cpp
+++ b/src/corelib/mimetypes/qmimeprovider.cpp
@@ -9,7 +9,6 @@
#include <qstandardpaths.h>
#include "qmimemagicrulematcher_p.h"
-#include <QMap>
#include <QXmlStreamReader>
#include <QBuffer>
#include <QDir>
@@ -51,24 +50,6 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-static inline void appendIfNew(QStringList &list, const QString &str)
-{
- if (!list.contains(str))
- list.push_back(str);
-}
-
-QMimeProviderBase::QMimeProviderBase(QMimeDatabasePrivate *db, const QString &directory)
- : m_db(db), m_directory(directory)
-{
-}
-
-
-QMimeBinaryProvider::QMimeBinaryProvider(QMimeDatabasePrivate *db, const QString &directory)
- : QMimeProviderBase(db, directory), m_mimetypeListLoaded(false)
-{
- ensureLoaded();
-}
-
struct QMimeBinaryProvider::CacheFile
{
CacheFile(const QString &fileName);
@@ -96,6 +77,43 @@ struct QMimeBinaryProvider::CacheFile
bool m_valid;
};
+static inline void appendIfNew(QStringList &list, const QString &str)
+{
+ if (!list.contains(str))
+ list.push_back(str);
+}
+
+QMimeProviderBase::QMimeProviderBase(QMimeDatabasePrivate *db, const QString &directory)
+ : m_db(db), m_directory(directory)
+{
+}
+
+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)
+{
+ ensureLoaded();
+}
+
QMimeBinaryProvider::CacheFile::CacheFile(const QString &fileName)
: file(fileName), m_valid(false)
{
@@ -186,25 +204,11 @@ void QMimeBinaryProvider::ensureLoaded()
m_cacheFile.reset();
}
-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
- // genericIconName: in loadGenericIcon
- return QMimeType(data);
-}
-
-QMimeType QMimeBinaryProvider::mimeTypeForName(const QString &name)
+bool QMimeBinaryProvider::knowsMimeType(const QString &name)
{
if (!m_mimetypeListLoaded)
loadMimeTypeList();
- if (!m_mimetypeNames.contains(name))
- return QMimeType(); // unknown mimetype
- return mimeTypeForNameUnchecked(name);
+ return m_mimetypeNames.contains(name);
}
void QMimeBinaryProvider::addFileNameMatches(const QString &fileName, QMimeGlobMatchResult &result)
@@ -212,40 +216,34 @@ void QMimeBinaryProvider::addFileNameMatches(const QString &fileName, QMimeGlobM
if (fileName.isEmpty())
return;
Q_ASSERT(m_cacheFile);
- const QString lowerFileName = fileName.toLower();
+ int numMatches = 0;
// Check literals (e.g. "Makefile")
- matchGlobList(result, m_cacheFile.get(), m_cacheFile->getUint32(PosLiteralListOffset),
- fileName);
+ numMatches = matchGlobList(result, m_cacheFile.get(),
+ m_cacheFile->getUint32(PosLiteralListOffset), fileName);
// Check the very common *.txt cases with the suffix tree
- if (result.m_matchingMimeTypes.isEmpty()) {
+ if (numMatches == 0) {
+ const QString lowerFileName = fileName.toLower();
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.get(), numRoots, firstRootOffset, lowerFileName,
- lowerFileName.size() - 1, false);
- if (result.m_matchingMimeTypes.isEmpty())
- matchSuffixTree(result, m_cacheFile.get(), numRoots, firstRootOffset, fileName,
- fileName.size() - 1, true);
+ if (matchSuffixTree(result, m_cacheFile.get(), numRoots, firstRootOffset, lowerFileName,
+ lowerFileName.size() - 1, false)) {
+ ++numMatches;
+ } else if (matchSuffixTree(result, m_cacheFile.get(), numRoots, firstRootOffset, fileName,
+ fileName.size() - 1, true)) {
+ ++numMatches;
+ }
}
// Check complex globs (e.g. "callgrind.out[0-9]*" or "README*")
- if (result.m_matchingMimeTypes.isEmpty())
+ if (numMatches == 0)
matchGlobList(result, m_cacheFile.get(), m_cacheFile->getUint32(PosGlobListOffset),
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);
-}
-
-void QMimeBinaryProvider::matchGlobList(QMimeGlobMatchResult &result, CacheFile *cacheFile, int off, const QString &fileName)
+int QMimeBinaryProvider::matchGlobList(QMimeGlobMatchResult &result, CacheFile *cacheFile, int off,
+ const QString &fileName)
{
+ int numMatches = 0;
const int numGlobs = cacheFile->getUint32(off);
//qDebug() << "Loading" << numGlobs << "globs from" << cacheFile->file.fileName() << "at offset" << cacheFile->globListOffset;
for (int i = 0; i < numGlobs; ++i) {
@@ -257,15 +255,18 @@ void 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);
+ if (glob.matchFileName(fileName)) {
+ result.addMatch(mimeType, weight, pattern);
+ ++numMatches;
+ }
}
+ return numMatches;
}
bool QMimeBinaryProvider::matchSuffixTree(QMimeGlobMatchResult &result,
@@ -298,15 +299,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;
}
@@ -346,7 +347,7 @@ bool QMimeBinaryProvider::matchMagicRule(QMimeBinaryProvider::CacheFile *cacheFi
return false;
}
-void QMimeBinaryProvider::findByMagic(const QByteArray &data, int *accuracyPtr, QMimeType &candidate)
+void QMimeBinaryProvider::findByMagic(const QByteArray &data, QMimeMagicResult &result)
{
const int magicListOffset = m_cacheFile->getUint32(PosMagicListOffset);
const int numMatches = m_cacheFile->getUint32(magicListOffset);
@@ -360,11 +361,13 @@ void QMimeBinaryProvider::findByMagic(const QByteArray &data, int *accuracyPtr,
if (matchMagicRule(m_cacheFile.get(), 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(QLatin1StringView(mimeType));
- return;
+ const int accuracy = static_cast<int>(m_cacheFile->getUint32(off));
+ if (accuracy > result.accuracy) {
+ result.accuracy = accuracy;
+ result.candidate = QString::fromLatin1(mimeType);
+ // Return the first match, mime.cache is sorted
+ return;
+ }
}
}
}
@@ -453,13 +456,14 @@ 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".
- QFile file(m_directory + QStringLiteral("/types"));
+ QFile file(m_directory + QStringView(u"/types"));
if (file.open(QIODevice::ReadOnly)) {
while (!file.atEnd()) {
- QByteArray line = file.readLine();
- if (line.endsWith('\n'))
- line.chop(1);
- m_mimetypeNames.insert(QString::fromLatin1(line));
+ const QByteArray line = file.readLine();
+ auto lineView = QByteArrayView(line);
+ if (lineView.endsWith('\n'))
+ lineView.chop(1);
+ m_mimetypeNames.insert(QString::fromLatin1(lineView));
}
}
}
@@ -471,49 +475,70 @@ void QMimeBinaryProvider::addAllMimeTypes(QList<QMimeType> &result)
if (result.isEmpty()) {
result.reserve(m_mimetypeNames.size());
for (const QString &name : std::as_const(m_mimetypeNames))
- result.append(mimeTypeForNameUnchecked(name));
+ result.append(QMimeType(QMimeTypePrivate(name)));
} else {
for (const QString &name : std::as_const(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));
+ result.append(QMimeType(QMimeTypePrivate(name)));
}
}
-bool QMimeBinaryProvider::loadMimeTypePrivate(QMimeTypePrivate &data)
+QMimeTypePrivate::LocaleHash QMimeBinaryProvider::localeComments(const QString &name)
{
-#if QT_CONFIG(xmlstreamreader)
- if (data.loaded)
- return true;
+ MimeTypeExtraMap::const_iterator it = loadMimeTypeExtra(name);
+ if (it != m_mimetypeExtra.cend())
+ return it->second.localeComments;
+ return {};
+}
+
+bool QMimeBinaryProvider::hasGlobDeleteAll(const QString &name)
+{
+ MimeTypeExtraMap::const_iterator it = loadMimeTypeExtra(name);
+ if (it != m_mimetypeExtra.cend())
+ return it->second.hasGlobDeleteAll;
+ return {};
+}
+
+QStringList QMimeBinaryProvider::globPatterns(const QString &name)
+{
+ MimeTypeExtraMap::const_iterator it = loadMimeTypeExtra(name);
+ if (it != m_mimetypeExtra.cend())
+ return it->second.globPatterns;
+ return {};
+}
- auto it = m_mimetypeExtra.constFind(data.name);
- if (it == m_mimetypeExtra.constEnd()) {
+QMimeBinaryProvider::MimeTypeExtraMap::const_iterator
+QMimeBinaryProvider::loadMimeTypeExtra(const QString &mimeName)
+{
+#if QT_CONFIG(xmlstreamreader)
+ auto it = m_mimetypeExtra.find(mimeName);
+ if (it == m_mimetypeExtra.cend()) {
// load comment and globPatterns
// shared-mime-info since 1.3 lowercases the xml files
- QString mimeFile = m_directory + u'/' + data.name.toLower() + ".xml"_L1;
+ QString mimeFile = m_directory + u'/' + mimeName.toLower() + ".xml"_L1;
if (!QFile::exists(mimeFile))
- mimeFile = m_directory + u'/' + data.name + ".xml"_L1; // pre-1.3
+ mimeFile = m_directory + u'/' + mimeName + ".xml"_L1; // pre-1.3
QFile qfile(mimeFile);
if (!qfile.open(QFile::ReadOnly))
- return false;
+ return m_mimetypeExtra.cend();
- auto insertIt = m_mimetypeExtra.insert(data.name, MimeTypeExtra{});
- it = insertIt;
- MimeTypeExtra &extra = insertIt.value();
+ it = m_mimetypeExtra.try_emplace(mimeName).first;
+ MimeTypeExtra &extra = it->second;
QString mainPattern;
QXmlStreamReader xml(&qfile);
if (xml.readNextStartElement()) {
if (xml.name() != "mime-type"_L1) {
- return false;
+ return m_mimetypeExtra.cend();
}
const auto name = xml.attributes().value("type"_L1);
if (name.isEmpty())
- return false;
- if (name.compare(data.name, Qt::CaseInsensitive))
- qWarning() << "Got name" << name << "in file" << mimeFile << "expected" << data.name;
+ return m_mimetypeExtra.cend();
+ if (name.compare(mimeName, Qt::CaseInsensitive))
+ qWarning() << "Got name" << name << "in file" << mimeFile << "expected" << mimeName;
while (xml.readNextStartElement()) {
const auto tag = xml.name();
@@ -526,8 +551,7 @@ bool QMimeBinaryProvider::loadMimeTypePrivate(QMimeTypePrivate &data)
extra.localeComments.insert(lang, text);
continue; // we called readElementText, so we're at the EndElement already.
} else if (tag == "glob-deleteall"_L1) { // as written out by shared-mime-info >= 0.70
- extra.globPatterns.clear();
- mainPattern.clear();
+ extra.hasGlobDeleteAll = true;
} else if (tag == "glob"_L1) { // as written out by shared-mime-info >= 0.70
const QString pattern = xml.attributes().value("pattern"_L1).toString();
if (mainPattern.isEmpty() && pattern.startsWith(u'*')) {
@@ -549,14 +573,11 @@ bool QMimeBinaryProvider::loadMimeTypePrivate(QMimeTypePrivate &data)
extra.globPatterns.prepend(mainPattern);
}
}
- const MimeTypeExtra &e = it.value();
- data.localeComments = e.localeComments;
- data.globPatterns = e.globPatterns;
- return true;
+ return it;
#else
- Q_UNUSED(data);
+ Q_UNUSED(mimeName);
qWarning("Cannot load mime type since QXmlStreamReader is not available.");
- return false;
+ return m_mimetypeExtra.cend();
#endif // feature xmlstreamreader
}
@@ -586,22 +607,16 @@ QLatin1StringView QMimeBinaryProvider::iconForMime(CacheFile *cacheFile, int pos
return QLatin1StringView();
}
-void QMimeBinaryProvider::loadIcon(QMimeTypePrivate &data)
+QString QMimeBinaryProvider::icon(const QString &name)
{
- const QByteArray inputMime = data.name.toLatin1();
- const QLatin1StringView icon = iconForMime(m_cacheFile.get(), PosIconsListOffset, inputMime);
- if (!icon.isEmpty()) {
- data.iconName = icon;
- }
+ const QByteArray inputMime = name.toLatin1();
+ return iconForMime(m_cacheFile.get(), PosIconsListOffset, inputMime);
}
-void QMimeBinaryProvider::loadGenericIcon(QMimeTypePrivate &data)
+QString QMimeBinaryProvider::genericIcon(const QString &name)
{
- const QByteArray inputMime = data.name.toLatin1();
- const QLatin1StringView icon = iconForMime(m_cacheFile.get(), PosGenericIconsListOffset, inputMime);
- if (!icon.isEmpty()) {
- data.genericIconName = icon;
- }
+ const QByteArray inputMime = name.toLatin1();
+ return iconForMime(m_cacheFile.get(), PosGenericIconsListOffset, inputMime);
}
////
@@ -686,38 +701,34 @@ bool QMimeXMLProvider::isInternalDatabase() const
#endif
}
-QMimeType QMimeXMLProvider::mimeTypeForName(const QString &name)
+bool QMimeXMLProvider::knowsMimeType(const QString &name)
{
- return m_nameMimeTypeMap.value(name);
+ return m_nameMimeTypeMap.contains(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, QMimeType &candidate)
+void QMimeXMLProvider::findByMagic(const QByteArray &data, QMimeMagicResult &result)
{
- QString candidateName;
- bool foundOne = false;
for (const QMimeMagicRuleMatcher &matcher : std::as_const(m_magicMatchers)) {
if (matcher.matches(data)) {
const int priority = matcher.priority();
- if (priority > *accuracyPtr) {
- *accuracyPtr = priority;
- candidateName = matcher.mimetype();
- foundOne = true;
+ if (priority > result.accuracy) {
+ result.accuracy = priority;
+ result.candidate = matcher.mimetype();
}
}
}
- if (foundOne)
- candidate = mimeTypeForName(candidateName);
}
void QMimeXMLProvider::ensureLoaded()
{
QStringList allFiles;
- const QString packageDir = m_directory + QStringLiteral("/packages");
+ const QString packageDir = m_directory + QStringView(u"/packages");
QDir dir(packageDir);
const QStringList files = dir.entryList(QDir::Files | QDir::NoDotAndDotDot);
allFiles.reserve(files.size());
@@ -733,7 +744,6 @@ void QMimeXMLProvider::ensureLoaded()
m_parents.clear();
m_mimeTypeGlobs.clear();
m_magicMatchers.clear();
- m_mimeTypesWithDeletedGlobs.clear();
//qDebug() << "Loading" << m_allFiles;
@@ -741,6 +751,31 @@ void QMimeXMLProvider::ensureLoaded()
load(file);
}
+QMimeTypePrivate::LocaleHash QMimeXMLProvider::localeComments(const QString &name)
+{
+ return m_nameMimeTypeMap.value(name).localeComments;
+}
+
+bool QMimeXMLProvider::hasGlobDeleteAll(const QString &name)
+{
+ return m_nameMimeTypeMap.value(name).hasGlobDeleteAll;
+}
+
+QStringList QMimeXMLProvider::globPatterns(const QString &name)
+{
+ return m_nameMimeTypeMap.value(name).globPatterns;
+}
+
+QString QMimeXMLProvider::icon(const QString &name)
+{
+ return m_nameMimeTypeMap.value(name).iconName;
+}
+
+QString QMimeXMLProvider::genericIcon(const QString &name)
+{
+ return m_nameMimeTypeMap.value(name).genericIconName;
+}
+
void QMimeXMLProvider::load(const QString &fileName)
{
QString errorMessage;
@@ -782,32 +817,9 @@ void QMimeXMLProvider::addGlobPattern(const QMimeGlobPattern &glob)
m_mimeTypeGlobs.addGlob(glob);
}
-void QMimeXMLProvider::addMimeType(const QMimeType &mt)
-{
- Q_ASSERT(!mt.d.data()->fromCache);
-
- QString name = mt.name();
- if (mt.d->hasGlobDeleteAll)
- appendIfNew(m_mimeTypesWithDeletedGlobs, 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)
+void QMimeXMLProvider::addMimeType(const QMimeTypeXMLData &mt)
{
- for (const auto &mt : toExclude) {
- auto it = m_nameMimeTypeMap.find(mt);
- if (it != m_nameMimeTypeMap.end())
- it->d->globPatterns.clear();
- m_mimeTypeGlobs.removeMimeType(mt);
- }
+ m_nameMimeTypeMap.insert(mt.name, mt);
}
void QMimeXMLProvider::addParents(const QString &mime, QStringList &result)
@@ -845,13 +857,16 @@ void QMimeXMLProvider::addAlias(const QString &alias, const QString &name)
void QMimeXMLProvider::addAllMimeTypes(QList<QMimeType> &result)
{
if (result.isEmpty()) { // fast path
- result = m_nameMimeTypeMap.values();
+ for (auto it = m_nameMimeTypeMap.constBegin(), end = m_nameMimeTypeMap.constEnd();
+ it != end; ++it) {
+ result.append(QMimeType(QMimeTypePrivate(it.value().name)));
+ }
} 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());
+ result.append(QMimeType(QMimeTypePrivate(it.value().name)));
}
}
}