Update mime database from Qt

qtbase/4e9944e6c8a456353d243ab268cb0f01ff006faa
  QMimeDatabase: collect glob patterns from all locations

The original patch needs some adaptions for Qt Creator's
custom setPreferredSuffix and setGlobPatternsForMimeType

Change-Id: I9a7a2cbe79bd732a63f3a88fc81ff4d0b18c75c8
Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
This commit is contained in:
Eike Ziller
2024-08-29 13:57:20 +02:00
parent 770e1ba311
commit c713a28c43
9 changed files with 265 additions and 242 deletions

View File

@@ -77,10 +77,12 @@ bool MimeDatabasePrivate::shouldCheck()
return m_forceLoad; return m_forceLoad;
} }
#if 0
static QStringList locateMimeDirectories() static QStringList locateMimeDirectories()
{ {
return QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("mime"), QStandardPaths::LocateDirectory); return QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("mime"), QStandardPaths::LocateDirectory);
} }
#endif
#if defined(Q_OS_UNIX) && !defined(Q_OS_NACL) && !defined(Q_OS_INTEGRITY) #if defined(Q_OS_UNIX) && !defined(Q_OS_NACL) && !defined(Q_OS_INTEGRITY)
# define QT_USE_MMAP # define QT_USE_MMAP
@@ -246,9 +248,8 @@ MimeType MimeDatabasePrivate::mimeTypeForName(const QString &nameOrAlias)
{ {
const QString mimeName = resolveAlias(nameOrAlias); const QString mimeName = resolveAlias(nameOrAlias);
for (const auto &provider : providers()) { for (const auto &provider : providers()) {
MimeType mime = provider->mimeTypeForName(mimeName); if (provider->knowsMimeType(mimeName))
if (mime.isValid()) return MimeType(MimeTypePrivate(mimeName));
return mime;
} }
return {}; return {};
} }
@@ -273,54 +274,70 @@ MimeGlobMatchResult MimeDatabasePrivate::findByFileName(const QString &fileName)
return result; return result;
} }
void MimeDatabasePrivate::loadMimeTypePrivate(MimeTypePrivate &mimePrivate) MimeTypePrivate::LocaleHash MimeDatabasePrivate::localeComments(const QString &name)
{ {
QMutexLocker locker(&mutex); QMutexLocker locker(&mutex);
if (mimePrivate.name.isEmpty()) for (const auto &provider : providers()) {
return; // invalid mimetype auto comments = provider->localeComments(name);
if (!mimePrivate.loaded) { // XML provider sets loaded=true, binary provider does this on demand if (!comments.isEmpty())
Q_ASSERT(mimePrivate.fromCache); return comments; // maybe we want to merge in comments from more global providers, in
bool found = false; // case of more translations?
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;
} }
return {};
} }
void MimeDatabasePrivate::loadGenericIcon(MimeTypePrivate &mimePrivate) QStringList MimeDatabasePrivate::globPatterns(const QString &name)
{ {
QMutexLocker locker(&mutex); QMutexLocker locker(&mutex);
if (mimePrivate.fromCache) { QStringList patterns;
mimePrivate.genericIconName.clear(); const auto &providerList = providers();
for (const auto &provider : providers()) { // reverse iteration because we start from most global, add up, clear if delete-all, and add up
provider->loadGenericIcon(mimePrivate); // again.
if (!mimePrivate.genericIconName.isEmpty()) for (auto rit = providerList.rbegin(); rit != providerList.rend(); ++rit) {
break; auto *provider = rit->get();
} if (provider->hasGlobDeleteAll(name))
patterns.clear();
// handle MIME type overriding from Qt Creator
if (!provider->m_overriddenMimeTypes.contains(name))
patterns += provider->globPatterns(name);
} }
// added for Qt Creator, overriding preferred suffix (first pattern in the list)
const QString preferredSuffix = m_preferredSuffix.value(name);
if (!preferredSuffix.isEmpty()) {
auto it = std::find_if(patterns.begin(),
patterns.end(),
[preferredSuffix](const QString &pattern) {
return MimeType::suffixFromPattern(pattern) == preferredSuffix;
});
if (it != patterns.end())
patterns.erase(it);
patterns.prepend(QLatin1String("*.") + preferredSuffix);
}
return patterns;
} }
void MimeDatabasePrivate::loadIcon(MimeTypePrivate &mimePrivate) QString MimeDatabasePrivate::genericIcon(const QString &name)
{ {
QMutexLocker locker(&mutex); QMutexLocker locker(&mutex);
if (mimePrivate.fromCache) { for (const auto &provider : providers()) {
mimePrivate.iconName.clear(); QString genericIconName = provider->genericIcon(name);
for (const auto &provider : providers()) { if (!genericIconName.isEmpty())
provider->loadIcon(mimePrivate); return genericIconName;
if (!mimePrivate.iconName.isEmpty())
break;
}
} }
return {};
}
QString MimeDatabasePrivate::icon(const QString &name)
{
QMutexLocker locker(&mutex);
for (const auto &provider : providers()) {
QString iconName = provider->icon(name);
if (!iconName.isEmpty())
return iconName;
}
return {};
} }
QString MimeDatabasePrivate::fallbackParent(const QString &mimeTypeName) const QString MimeDatabasePrivate::fallbackParent(const QString &mimeTypeName) const
@@ -411,12 +428,12 @@ MimeType MimeDatabasePrivate::findByData(const QByteArray &data, int *accuracyPt
#endif #endif
*accuracyPtr = 0; *accuracyPtr = 0;
MimeType candidate; QString candidate;
for (const auto &provider : providers()) for (const auto &provider : providers())
provider->findByMagic(data, accuracyPtr, candidate); provider->findByMagic(data, accuracyPtr, &candidate);
if (candidate.isValid()) if (!candidate.isEmpty())
return candidate; return MimeType(MimeTypePrivate(candidate));
if (isTextFile(data)) { if (isTextFile(data)) {
*accuracyPtr = 5; *accuracyPtr = 5;
@@ -937,6 +954,12 @@ void MimeDatabasePrivate::setGlobPatternsForMimeType(const MimeType &mimeType,
} }
} }
void MimeDatabasePrivate::setPreferredSuffix(const QString &mimeName, const QString &suffix)
{
QMutexLocker locker(&mutex);
m_preferredSuffix.insert(mimeName, suffix);
}
void MimeDatabasePrivate::checkInitPhase(const QString &info) void MimeDatabasePrivate::checkInitPhase(const QString &info)
{ {
QReadLocker locker(&m_initMutex); QReadLocker locker(&m_initMutex);

View File

@@ -70,9 +70,10 @@ public:
MimeGlobMatchResult findByFileName(const QString &fileName); MimeGlobMatchResult findByFileName(const QString &fileName);
// API for MimeType. Takes care of locking the mutex. // API for MimeType. Takes care of locking the mutex.
void loadMimeTypePrivate(MimeTypePrivate &mimePrivate); MimeTypePrivate::LocaleHash localeComments(const QString &name);
void loadGenericIcon(MimeTypePrivate &mimePrivate); QStringList globPatterns(const QString &name);
void loadIcon(MimeTypePrivate &mimePrivate); QString genericIcon(const QString &name);
QString icon(const QString &name);
QStringList mimeParents(const QString &mimeName); QStringList mimeParents(const QString &mimeName);
QStringList listAliases(const QString &mimeName); QStringList listAliases(const QString &mimeName);
bool mimeInherits(const QString &mime, const QString &parent); bool mimeInherits(const QString &mime, const QString &parent);
@@ -83,6 +84,7 @@ public:
void setMagicRulesForMimeType(const MimeType &mimeType, void setMagicRulesForMimeType(const MimeType &mimeType,
const QMap<int, QList<MimeMagicRule>> &rules); const QMap<int, QList<MimeMagicRule>> &rules);
void setGlobPatternsForMimeType(const MimeType &mimeType, const QStringList &patterns); void setGlobPatternsForMimeType(const MimeType &mimeType, const QStringList &patterns);
void setPreferredSuffix(const QString &mimeName, const QString &suffix);
void checkInitPhase(const QString &info); void checkInitPhase(const QString &info);
void addInitializer(const std::function<void()> &init); void addInitializer(const std::function<void()> &init);
@@ -94,7 +96,7 @@ private:
QString fallbackParent(const QString &mimeTypeName) const; QString fallbackParent(const QString &mimeTypeName) const;
const QString m_defaultMimeType; const QString m_defaultMimeType;
mutable Providers m_providers; mutable Providers m_providers; // most local first, most global last
QElapsedTimer m_lastCheck; QElapsedTimer m_lastCheck;
// added for Qt Creator // added for Qt Creator
@@ -109,6 +111,7 @@ public:
QReadWriteLock m_initMutex; QReadWriteLock m_initMutex;
std::atomic_bool m_initialized = false; std::atomic_bool m_initialized = false;
int m_startupPhase = 0; int m_startupPhase = 0;
QHash<QString, QString> m_preferredSuffix; // MIME name -> suffix
}; };
} // namespace Utils } // namespace Utils

View File

@@ -186,25 +186,11 @@ void MimeBinaryProvider::ensureLoaded()
m_cacheFile.reset(); m_cacheFile.reset();
} }
static MimeType mimeTypeForNameUnchecked(const QString &name) bool MimeBinaryProvider::knowsMimeType(const QString &name)
{
MimeTypePrivate 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 MimeType(data);
}
MimeType MimeBinaryProvider::mimeTypeForName(const QString &name)
{ {
if (!m_mimetypeListLoaded) if (!m_mimetypeListLoaded)
loadMimeTypeList(); loadMimeTypeList();
if (!m_mimetypeNames.contains(name)) return m_mimetypeNames.contains(name);
return MimeType(); // unknown mimetype
return mimeTypeForNameUnchecked(name);
} }
void MimeBinaryProvider::addFileNameMatches(const QString &fileName, MimeGlobMatchResult &result) void MimeBinaryProvider::addFileNameMatches(const QString &fileName, MimeGlobMatchResult &result)
@@ -368,7 +354,7 @@ bool MimeBinaryProvider::matchMagicRule(MimeBinaryProvider::CacheFile *cacheFile
return false; return false;
} }
void MimeBinaryProvider::findByMagic(const QByteArray &data, int *accuracyPtr, MimeType &candidate) void MimeBinaryProvider::findByMagic(const QByteArray &data, int *accuracyPtr, QString *candidate)
{ {
const int magicListOffset = m_cacheFile->getUint32(PosMagicListOffset); const int magicListOffset = m_cacheFile->getUint32(PosMagicListOffset);
const int numMatches = m_cacheFile->getUint32(magicListOffset); const int numMatches = m_cacheFile->getUint32(magicListOffset);
@@ -387,7 +373,7 @@ void MimeBinaryProvider::findByMagic(const QByteArray &data, int *accuracyPtr, M
*accuracyPtr = m_cacheFile->getUint32(off); *accuracyPtr = m_cacheFile->getUint32(off);
// Return the first match. We have no rules for conflicting magic data... // 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?) // (mime.cache itself is sorted, but what about local overrides with a lower prio?)
candidate = mimeTypeForNameUnchecked(QLatin1StringView(mimeType)); *candidate = QString::fromLatin1(mimeType);
return; return;
} }
} }
@@ -496,35 +482,63 @@ void MimeBinaryProvider::addAllMimeTypes(QList<MimeType> &result)
if (result.isEmpty()) { if (result.isEmpty()) {
result.reserve(m_mimetypeNames.size()); result.reserve(m_mimetypeNames.size());
for (const QString &name : std::as_const(m_mimetypeNames)) for (const QString &name : std::as_const(m_mimetypeNames))
result.append(mimeTypeForNameUnchecked(name)); result.append(MimeType(MimeTypePrivate(name)));
} else { } else {
for (const QString &name : std::as_const(m_mimetypeNames)) for (const QString &name : std::as_const(m_mimetypeNames))
if (std::find_if(result.constBegin(), result.constEnd(), [name](const MimeType &mime) -> bool { return mime.name() == name; }) if (std::find_if(result.constBegin(), result.constEnd(), [name](const MimeType &mime) -> bool { return mime.name() == name; })
== result.constEnd()) == result.constEnd())
result.append(mimeTypeForNameUnchecked(name)); result.append(MimeType(MimeTypePrivate(name)));
} }
} }
bool MimeBinaryProvider::loadMimeTypePrivate(MimeTypePrivate &data) MimeTypePrivate::LocaleHash MimeBinaryProvider::localeComments(const QString &name)
{
MimeTypeExtraMap::const_iterator it = loadMimeTypeExtra(name);
if (it != m_mimetypeExtra.constEnd()) {
const MimeTypeExtra &e = it.value();
return e.localeComments;
}
return {};
}
bool MimeBinaryProvider::hasGlobDeleteAll(const QString &name)
{
MimeTypeExtraMap::const_iterator it = loadMimeTypeExtra(name);
if (it != m_mimetypeExtra.constEnd()) {
const MimeTypeExtra &e = it.value();
return e.hasGlobDeleteAll;
}
return {};
}
QStringList MimeBinaryProvider::globPatterns(const QString &name)
{
MimeTypeExtraMap::const_iterator it = loadMimeTypeExtra(name);
if (it != m_mimetypeExtra.constEnd()) {
const MimeTypeExtra &e = it.value();
return e.globPatterns;
}
return {};
}
MimeBinaryProvider::MimeTypeExtraMap::const_iterator
MimeBinaryProvider::loadMimeTypeExtra(const QString &mimeName)
{ {
#if QT_CONFIG(xmlstreamreader) #if QT_CONFIG(xmlstreamreader)
if (data.loaded) auto it = m_mimetypeExtra.constFind(mimeName);
return true;
auto it = m_mimetypeExtra.constFind(data.name);
if (it == m_mimetypeExtra.constEnd()) { if (it == m_mimetypeExtra.constEnd()) {
// load comment and globPatterns // load comment and globPatterns
// shared-mime-info since 1.3 lowercases the xml files // 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 (!QFileInfo::exists(mimeFile)) if (!QFileInfo::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); QFile qfile(mimeFile);
if (!qfile.open(QFile::ReadOnly)) if (!qfile.open(QFile::ReadOnly))
return false; return m_mimetypeExtra.constEnd();
auto insertIt = m_mimetypeExtra.insert(data.name, MimeTypeExtra{}); auto insertIt = m_mimetypeExtra.insert(mimeName, MimeTypeExtra{});
it = insertIt; it = insertIt;
MimeTypeExtra &extra = insertIt.value(); MimeTypeExtra &extra = insertIt.value();
QString mainPattern; QString mainPattern;
@@ -532,13 +546,13 @@ bool MimeBinaryProvider::loadMimeTypePrivate(MimeTypePrivate &data)
QXmlStreamReader xml(&qfile); QXmlStreamReader xml(&qfile);
if (xml.readNextStartElement()) { if (xml.readNextStartElement()) {
if (xml.name() != "mime-type"_L1) { if (xml.name() != "mime-type"_L1) {
return false; return m_mimetypeExtra.constEnd();
} }
const auto name = xml.attributes().value("type"_L1); const auto name = xml.attributes().value("type"_L1);
if (name.isEmpty()) if (name.isEmpty())
return false; return m_mimetypeExtra.constEnd();
if (name.compare(data.name, Qt::CaseInsensitive)) if (name.compare(mimeName, Qt::CaseInsensitive))
qWarning() << "Got name" << name << "in file" << mimeFile << "expected" << data.name; qWarning() << "Got name" << name << "in file" << mimeFile << "expected" << mimeName;
while (xml.readNextStartElement()) { while (xml.readNextStartElement()) {
const auto tag = xml.name(); const auto tag = xml.name();
@@ -551,8 +565,7 @@ bool MimeBinaryProvider::loadMimeTypePrivate(MimeTypePrivate &data)
extra.localeComments.insert(lang, text); extra.localeComments.insert(lang, text);
continue; // we called readElementText, so we're at the EndElement already. 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 } else if (tag == "glob-deleteall"_L1) { // as written out by shared-mime-info >= 0.70
extra.globPatterns.clear(); extra.hasGlobDeleteAll = true;
mainPattern.clear();
} else if (tag == "glob"_L1) { // as written out by shared-mime-info >= 0.70 } else if (tag == "glob"_L1) { // as written out by shared-mime-info >= 0.70
const QString pattern = xml.attributes().value("pattern"_L1).toString(); const QString pattern = xml.attributes().value("pattern"_L1).toString();
if (mainPattern.isEmpty() && pattern.startsWith(u'*')) { if (mainPattern.isEmpty() && pattern.startsWith(u'*')) {
@@ -574,14 +587,11 @@ bool MimeBinaryProvider::loadMimeTypePrivate(MimeTypePrivate &data)
extra.globPatterns.prepend(mainPattern); extra.globPatterns.prepend(mainPattern);
} }
} }
const MimeTypeExtra &e = it.value(); return it;
data.localeComments = e.localeComments;
data.globPatterns = e.globPatterns;
return true;
#else #else
Q_UNUSED(data); Q_UNUSED(mimeName);
qWarning("Cannot load mime type since QXmlStreamReader is not available."); qWarning("Cannot load mime type since QXmlStreamReader is not available.");
return false; return m_mimetypeExtra.constEnd();
#endif // feature xmlstreamreader #endif // feature xmlstreamreader
} }
@@ -611,22 +621,16 @@ QLatin1StringView MimeBinaryProvider::iconForMime(CacheFile *cacheFile, int posL
return QLatin1StringView(); return QLatin1StringView();
} }
void MimeBinaryProvider::loadIcon(MimeTypePrivate &data) QString MimeBinaryProvider::icon(const QString &name)
{ {
const QByteArray inputMime = data.name.toLatin1(); const QByteArray inputMime = name.toLatin1();
const QLatin1StringView icon = iconForMime(m_cacheFile.get(), PosIconsListOffset, inputMime); return iconForMime(m_cacheFile.get(), PosIconsListOffset, inputMime);
if (!icon.isEmpty()) {
data.iconName = icon;
}
} }
void MimeBinaryProvider::loadGenericIcon(MimeTypePrivate &data) QString MimeBinaryProvider::genericIcon(const QString &name)
{ {
const QByteArray inputMime = data.name.toLatin1(); const QByteArray inputMime = name.toLatin1();
const QLatin1StringView icon = iconForMime(m_cacheFile.get(), PosGenericIconsListOffset, inputMime); return iconForMime(m_cacheFile.get(), PosGenericIconsListOffset, inputMime);
if (!icon.isEmpty()) {
data.genericIconName = icon;
}
} }
//// ////
@@ -722,9 +726,9 @@ bool MimeXMLProvider::isInternalDatabase() const
#endif #endif
} }
MimeType MimeXMLProvider::mimeTypeForName(const QString &name) bool MimeXMLProvider::knowsMimeType(const QString &name)
{ {
return m_nameMimeTypeMap.value(name); return m_nameMimeTypeMap.contains(name);
} }
void MimeXMLProvider::addFileNameMatches(const QString &fileName, MimeGlobMatchResult &result) void MimeXMLProvider::addFileNameMatches(const QString &fileName, MimeGlobMatchResult &result)
@@ -732,10 +736,8 @@ void MimeXMLProvider::addFileNameMatches(const QString &fileName, MimeGlobMatchR
m_mimeTypeGlobs.matchingGlobs(fileName, result, m_overriddenMimeTypes); m_mimeTypeGlobs.matchingGlobs(fileName, result, m_overriddenMimeTypes);
} }
void MimeXMLProvider::findByMagic(const QByteArray &data, int *accuracyPtr, MimeType &candidate) void MimeXMLProvider::findByMagic(const QByteArray &data, int *accuracyPtr, QString *candidate)
{ {
QString candidateName;
bool foundOne = false;
for (const MimeMagicRuleMatcher &matcher : std::as_const(m_magicMatchers)) { for (const MimeMagicRuleMatcher &matcher : std::as_const(m_magicMatchers)) {
if (m_overriddenMimeTypes.contains(matcher.mimetype())) if (m_overriddenMimeTypes.contains(matcher.mimetype()))
continue; continue;
@@ -743,13 +745,10 @@ void MimeXMLProvider::findByMagic(const QByteArray &data, int *accuracyPtr, Mime
const int priority = matcher.priority(); const int priority = matcher.priority();
if (priority > *accuracyPtr) { if (priority > *accuracyPtr) {
*accuracyPtr = priority; *accuracyPtr = priority;
candidateName = matcher.mimetype(); *candidate = matcher.mimetype();
foundOne = true;
} }
} }
} }
if (foundOne)
candidate = mimeTypeForName(candidateName);
} }
void MimeXMLProvider::ensureLoaded() void MimeXMLProvider::ensureLoaded()
@@ -779,6 +778,31 @@ void MimeXMLProvider::ensureLoaded()
load(file); load(file);
} }
MimeTypePrivate::LocaleHash MimeXMLProvider::localeComments(const QString &name)
{
return m_nameMimeTypeMap.value(name).localeComments;
}
bool MimeXMLProvider::hasGlobDeleteAll(const QString &name)
{
return m_nameMimeTypeMap.value(name).hasGlobDeleteAll;
}
QStringList MimeXMLProvider::globPatterns(const QString &name)
{
return m_nameMimeTypeMap.value(name).globPatterns;
}
QString MimeXMLProvider::icon(const QString &name)
{
return m_nameMimeTypeMap.value(name).iconName;
}
QString MimeXMLProvider::genericIcon(const QString &name)
{
return m_nameMimeTypeMap.value(name).genericIconName;
}
void MimeXMLProvider::load(const QString &fileName) void MimeXMLProvider::load(const QString &fileName)
{ {
QString errorMessage; QString errorMessage;
@@ -820,14 +844,11 @@ void MimeXMLProvider::addGlobPattern(const MimeGlobPattern &glob)
m_mimeTypeGlobs.addGlob(glob); m_mimeTypeGlobs.addGlob(glob);
} }
void MimeXMLProvider::addMimeType(const MimeType &mt) void MimeXMLProvider::addMimeType(const MimeTypeXMLData &mt)
{ {
Q_ASSERT(!mt.d.data()->fromCache); if (mt.hasGlobDeleteAll)
appendIfNew(m_mimeTypesWithDeletedGlobs, mt.name);
QString name = mt.name(); m_nameMimeTypeMap.insert(mt.name, mt);
if (mt.d->hasGlobDeleteAll)
appendIfNew(m_mimeTypesWithDeletedGlobs, name);
m_nameMimeTypeMap.insert(mt.name(), mt);
} }
/* /*
@@ -843,7 +864,7 @@ void MimeXMLProvider::excludeMimeTypeGlobs(const QStringList &toExclude)
for (const auto &mt : toExclude) { for (const auto &mt : toExclude) {
auto it = m_nameMimeTypeMap.find(mt); auto it = m_nameMimeTypeMap.find(mt);
if (it != m_nameMimeTypeMap.end()) if (it != m_nameMimeTypeMap.end())
it->d->globPatterns.clear(); it->globPatterns.clear();
m_mimeTypeGlobs.removeMimeType(mt); m_mimeTypeGlobs.removeMimeType(mt);
} }
} }
@@ -883,13 +904,16 @@ void MimeXMLProvider::addAlias(const QString &alias, const QString &name)
void MimeXMLProvider::addAllMimeTypes(QList<MimeType> &result) void MimeXMLProvider::addAllMimeTypes(QList<MimeType> &result)
{ {
if (result.isEmpty()) { // fast path if (result.isEmpty()) { // fast path
result = m_nameMimeTypeMap.values(); for (auto it = m_nameMimeTypeMap.constBegin(), end = m_nameMimeTypeMap.constEnd();
it != end; ++it) {
result.append(MimeType(MimeTypePrivate(it.value().name)));
}
} else { } else {
for (auto it = m_nameMimeTypeMap.constBegin(), end = m_nameMimeTypeMap.constEnd() ; it != end ; ++it) { for (auto it = m_nameMimeTypeMap.constBegin(), end = m_nameMimeTypeMap.constEnd() ; it != end ; ++it) {
const QString newMime = it.key(); const QString newMime = it.key();
if (std::find_if(result.constBegin(), result.constEnd(), [newMime](const MimeType &mime) -> bool { return mime.name() == newMime; }) if (std::find_if(result.constBegin(), result.constEnd(), [newMime](const MimeType &mime) -> bool { return mime.name() == newMime; })
== result.constEnd()) == result.constEnd())
result.append(it.value()); result.append(MimeType(MimeTypePrivate(it.value().name)));
} }
} }
} }
@@ -1003,9 +1027,7 @@ void MimeXMLProvider::setGlobPatternsForMimeType(const MimeType &mimeType,
// add new patterns as case-insensitive default-weight patterns // add new patterns as case-insensitive default-weight patterns
for (const QString &pattern : patterns) for (const QString &pattern : patterns)
addGlobPattern(MimeGlobPattern(pattern, mimeType.name())); addGlobPattern(MimeGlobPattern(pattern, mimeType.name()));
// the following is safe, because for XML provider mimetype private is always "loaded" m_nameMimeTypeMap[mimeType.name()].globPatterns = patterns;
// (see comment in MimeDatabasePrivate::loadMimeTypePrivate)
mimeType.d->globPatterns = patterns;
} }
} // namespace Utils } // namespace Utils

View File

@@ -25,6 +25,7 @@
namespace Utils { namespace Utils {
class MimeMagicRuleMatcher; class MimeMagicRuleMatcher;
class MimeTypeXMLData;
class MimeProviderBase class MimeProviderBase
{ {
@@ -36,18 +37,20 @@ public:
virtual bool isValid() = 0; virtual bool isValid() = 0;
virtual bool isInternalDatabase() const = 0; virtual bool isInternalDatabase() const = 0;
virtual MimeType mimeTypeForName(const QString &name) = 0; virtual bool knowsMimeType(const QString &name) = 0;
virtual void addFileNameMatches(const QString &fileName, MimeGlobMatchResult &result) = 0; virtual void addFileNameMatches(const QString &fileName, MimeGlobMatchResult &result) = 0;
virtual void addParents(const QString &mime, QStringList &result) = 0; virtual void addParents(const QString &mime, QStringList &result) = 0;
virtual QString resolveAlias(const QString &name) = 0; virtual QString resolveAlias(const QString &name) = 0;
virtual void addAliases(const QString &name, QStringList &result) = 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, QString *candidate) = 0;
virtual void addAllMimeTypes(QList<MimeType> &result) = 0; virtual void addAllMimeTypes(QList<MimeType> &result) = 0;
virtual bool loadMimeTypePrivate(MimeTypePrivate &) { return false; } virtual MimeTypePrivate::LocaleHash localeComments(const QString &name) = 0;
virtual void loadIcon(MimeTypePrivate &) {} virtual bool hasGlobDeleteAll(const QString &name) = 0;
virtual void loadGenericIcon(MimeTypePrivate &) {} virtual QStringList globPatterns(const QString &name) = 0;
virtual void ensureLoaded() {} virtual QString icon(const QString &name) = 0;
virtual void excludeMimeTypeGlobs(const QStringList &) {} virtual QString genericIcon(const QString &name) = 0;
virtual void ensureLoaded() { }
virtual void excludeMimeTypeGlobs(const QStringList &) { }
QString directory() const { return m_directory; } QString directory() const { return m_directory; }
@@ -66,9 +69,9 @@ public:
/* /*
MimeTypes with "glob-deleteall" tags are handled differently by each provider MimeTypes with "glob-deleteall" tags are handled differently by each provider
sub-class: sub-class:
- QMimeBinaryProvider parses glob-deleteall tags lazily, i.e. only when loadMimeTypePrivate() - QMimeBinaryProvider parses glob-deleteall tags lazily, i.e. only when hasGlobDeleteAll()
is called, and clears the glob patterns associated with mimetypes that have this tag is called, and clears the glob patterns associated with mimetypes that have this tag
- QMimeXMLProvider parses glob-deleteall from the the start, i.e. when a XML file is - QMimeXMLProvider parses glob-deleteall from the start, i.e. when a XML file is
parsed with QMimeTypeParser parsed with QMimeTypeParser
The two lists below are used to let both provider types (XML and Binary) communicate The two lists below are used to let both provider types (XML and Binary) communicate
@@ -104,16 +107,18 @@ public:
bool isValid() override; bool isValid() override;
bool isInternalDatabase() const override; bool isInternalDatabase() const override;
MimeType mimeTypeForName(const QString &name) override; bool knowsMimeType(const QString &name) override;
void addFileNameMatches(const QString &fileName, MimeGlobMatchResult &result) override; void addFileNameMatches(const QString &fileName, MimeGlobMatchResult &result) override;
void addParents(const QString &mime, QStringList &result) override; void addParents(const QString &mime, QStringList &result) override;
QString resolveAlias(const QString &name) override; QString resolveAlias(const QString &name) override;
void addAliases(const QString &name, QStringList &result) 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, QString *candidate) override;
void addAllMimeTypes(QList<MimeType> &result) override; void addAllMimeTypes(QList<MimeType> &result) override;
bool loadMimeTypePrivate(MimeTypePrivate &) override; MimeTypePrivate::LocaleHash localeComments(const QString &name) override;
void loadIcon(MimeTypePrivate &) override; bool hasGlobDeleteAll(const QString &name) override;
void loadGenericIcon(MimeTypePrivate &) override; QStringList globPatterns(const QString &name) override;
QString icon(const QString &name) override;
QString genericIcon(const QString &name) override;
void ensureLoaded() override; void ensureLoaded() override;
void excludeMimeTypeGlobs(const QStringList &toExclude) override; void excludeMimeTypeGlobs(const QStringList &toExclude) override;
@@ -137,9 +142,10 @@ private:
const QString &fileName, const QString &fileName,
qsizetype charPos, qsizetype charPos,
bool caseSensitiveCheck); bool caseSensitiveCheck);
bool matchMagicRule(CacheFile *cacheFile, int numMatchlets, int firstOffset, const QByteArray &data);
bool isMimeTypeGlobsExcluded(const char *name); bool isMimeTypeGlobsExcluded(const char *name);
QLatin1StringView iconForMime(CacheFile *cacheFile, int posListOffset, const QByteArray &inputMime); bool matchMagicRule(CacheFile *cacheFile, int numMatchlets, int firstOffset,
const QByteArray &data);
QLatin1StringView iconForMime(CacheFile *cacheFile, int posListOffset, const QByteArray &inputMime);
void loadMimeTypeList(); void loadMimeTypeList();
bool checkCacheChanged(); bool checkCacheChanged();
@@ -149,11 +155,14 @@ private:
bool m_mimetypeListLoaded; bool m_mimetypeListLoaded;
struct MimeTypeExtra struct MimeTypeExtra
{ {
// Both retrieved on demand in loadMimeTypePrivate
QHash<QString, QString> localeComments; QHash<QString, QString> localeComments;
QStringList globPatterns; QStringList globPatterns;
bool hasGlobDeleteAll = false;
}; };
QMap<QString, MimeTypeExtra> m_mimetypeExtra; using MimeTypeExtraMap = QMap<QString, MimeTypeExtra>;
MimeTypeExtraMap m_mimetypeExtra;
MimeTypeExtraMap::const_iterator loadMimeTypeExtra(const QString &mimeName);
}; };
/* /*
@@ -176,19 +185,24 @@ public:
bool isValid() override; bool isValid() override;
bool isInternalDatabase() const override; bool isInternalDatabase() const override;
MimeType mimeTypeForName(const QString &name) override; bool knowsMimeType(const QString &name) override;
void addFileNameMatches(const QString &fileName, MimeGlobMatchResult &result) override; void addFileNameMatches(const QString &fileName, MimeGlobMatchResult &result) override;
void addParents(const QString &mime, QStringList &result) override; void addParents(const QString &mime, QStringList &result) override;
QString resolveAlias(const QString &name) override; QString resolveAlias(const QString &name) override;
void addAliases(const QString &name, QStringList &result) 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, QString *candidate) override;
void addAllMimeTypes(QList<MimeType> &result) override; void addAllMimeTypes(QList<MimeType> &result) override;
void ensureLoaded() override; void ensureLoaded() override;
MimeTypePrivate::LocaleHash localeComments(const QString &name) override;
bool hasGlobDeleteAll(const QString &name) override;
QStringList globPatterns(const QString &name) override;
QString icon(const QString &name) override;
QString genericIcon(const QString &name) override;
bool load(const QString &fileName, QString *errorMessage); bool load(const QString &fileName, QString *errorMessage);
// Called by the mimetype xml parser // Called by the mimetype xml parser
void addMimeType(const MimeType &mt); void addMimeType(const MimeTypeXMLData &mt);
void excludeMimeTypeGlobs(const QStringList &toExclude) override; void excludeMimeTypeGlobs(const QStringList &toExclude) override;
void addGlobPattern(const MimeGlobPattern &glob); void addGlobPattern(const MimeGlobPattern &glob);
void addParent(const QString &child, const QString &parent); void addParent(const QString &child, const QString &parent);
@@ -207,7 +221,7 @@ private:
void load(const QString &fileName); void load(const QString &fileName);
void load(const char *data, qsizetype len); void load(const char *data, qsizetype len);
typedef QHash<QString, MimeType> NameMimeTypeMap; typedef QHash<QString, MimeTypeXMLData> NameMimeTypeMap;
NameMimeTypeMap m_nameMimeTypeMap; NameMimeTypeMap m_nameMimeTypeMap;
typedef QHash<QString, QString> AliasHash; typedef QHash<QString, QString> AliasHash;

View File

@@ -6,9 +6,6 @@
#include "mimetype_p.h" #include "mimetype_p.h"
#include "mimedatabase_p.h" #include "mimedatabase_p.h"
#include "mimeprovider_p.h"
#include "mimeglobpattern_p.h"
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QLocale> #include <QtCore/QLocale>
@@ -20,7 +17,7 @@ using namespace Qt::StringLiterals;
namespace Utils { namespace Utils {
static QString suffixFromPattern(const QString &pattern) QString MimeType::suffixFromPattern(const QString &pattern)
{ {
// Not a simple suffix if it looks like: README or *. or *.* or *.JP*G or *.JP? // Not a simple suffix if it looks like: README or *. or *.* or *.JP*G or *.JP?
if (pattern.startsWith("*."_L1) && if (pattern.startsWith("*."_L1) &&
@@ -31,33 +28,6 @@ static QString suffixFromPattern(const QString &pattern)
return {}; return {};
} }
MimeTypePrivate::MimeTypePrivate()
: loaded(false), fromCache(false)
{}
MimeTypePrivate::MimeTypePrivate(const MimeType &other)
: loaded(other.d->loaded),
name(other.d->name),
localeComments(other.d->localeComments),
genericIconName(other.d->genericIconName),
iconName(other.d->iconName),
globPatterns(other.d->globPatterns)
{}
void MimeTypePrivate::clear()
{
name.clear();
localeComments.clear();
genericIconName.clear();
iconName.clear();
globPatterns.clear();
}
void MimeTypePrivate::addGlobPattern(const QString &pattern)
{
globPatterns.append(pattern);
}
/*! /*!
\class MimeType \class MimeType
\inmodule QtCore \inmodule QtCore
@@ -230,7 +200,7 @@ QString MimeType::name() const
*/ */
QString MimeType::comment() const QString MimeType::comment() const
{ {
MimeDatabasePrivate::instance()->loadMimeTypePrivate(const_cast<MimeTypePrivate&>(*d)); const auto localeComments = MimeDatabasePrivate::instance()->localeComments(d->name);
QStringList languageList = QLocale().uiLanguages(); QStringList languageList = QLocale().uiLanguages();
qsizetype defaultIndex = languageList.indexOf(u"en-US"_s); qsizetype defaultIndex = languageList.indexOf(u"en-US"_s);
@@ -255,13 +225,13 @@ QString MimeType::comment() const
// uiLanguages() uses '-' as separator, MIME database uses '_' // uiLanguages() uses '-' as separator, MIME database uses '_'
const QString lang const QString lang
= language == "C"_L1 ? u"en_US"_s : QString(language).replace(u'-', u'_'); = language == "C"_L1 ? u"en_US"_s : QString(language).replace(u'-', u'_');
QString comm = d->localeComments.value(lang); QString comm = localeComments.value(lang);
if (!comm.isEmpty()) if (!comm.isEmpty())
return comm; return comm;
const qsizetype cut = lang.indexOf(u'_'); const qsizetype cut = lang.indexOf(u'_');
// If "de_CH" is missing, check for "de" (and similar): // If "de_CH" is missing, check for "de" (and similar):
if (cut != -1) { if (cut != -1) {
comm = d->localeComments.value(lang.left(cut)); comm = localeComments.value(lang.left(cut));
if (!comm.isEmpty()) if (!comm.isEmpty())
return comm; return comm;
} }
@@ -287,8 +257,8 @@ QString MimeType::comment() const
*/ */
QString MimeType::genericIconName() const QString MimeType::genericIconName() const
{ {
MimeDatabasePrivate::instance()->loadGenericIcon(const_cast<MimeTypePrivate&>(*d)); QString genericIconName = MimeDatabasePrivate::instance()->genericIcon(d->name);
if (d->genericIconName.isEmpty()) { if (genericIconName.isEmpty()) {
// From the spec: // From the spec:
// If the generic icon name is empty (not specified by the mimetype definition) // If the generic icon name is empty (not specified by the mimetype definition)
// then the mimetype is used to generate the generic icon by using the top-level // then the mimetype is used to generate the generic icon by using the top-level
@@ -301,7 +271,7 @@ QString MimeType::genericIconName() const
groupRef = groupRef.left(slashindex); groupRef = groupRef.left(slashindex);
return groupRef + "-x-generic"_L1; return groupRef + "-x-generic"_L1;
} }
return d->genericIconName; return genericIconName;
} }
static QString make_default_icon_name_from_mimetype_name(QString iconName) static QString make_default_icon_name_from_mimetype_name(QString iconName)
@@ -323,11 +293,11 @@ static QString make_default_icon_name_from_mimetype_name(QString iconName)
*/ */
QString MimeType::iconName() const QString MimeType::iconName() const
{ {
MimeDatabasePrivate::instance()->loadIcon(const_cast<MimeTypePrivate&>(*d)); QString iconName = MimeDatabasePrivate::instance()->icon(d->name);
if (d->iconName.isEmpty()) { if (iconName.isEmpty()) {
return make_default_icon_name_from_mimetype_name(name()); return make_default_icon_name_from_mimetype_name(name());
} }
return d->iconName; return iconName;
} }
/*! /*!
@@ -339,8 +309,7 @@ QString MimeType::iconName() const
*/ */
QStringList MimeType::globPatterns() const QStringList MimeType::globPatterns() const
{ {
MimeDatabasePrivate::instance()->loadMimeTypePrivate(const_cast<MimeTypePrivate&>(*d)); return MimeDatabasePrivate::instance()->globPatterns(d->name);
return d->globPatterns;
} }
/*! /*!
@@ -434,10 +403,11 @@ QStringList MimeType::aliases() const
*/ */
QStringList MimeType::suffixes() const QStringList MimeType::suffixes() const
{ {
MimeDatabasePrivate::instance()->loadMimeTypePrivate(const_cast<MimeTypePrivate&>(*d)); const QStringList patterns = globPatterns();
QStringList result; QStringList result;
for (const QString &pattern : std::as_const(d->globPatterns)) { result.reserve(patterns.size());
for (const QString &pattern : patterns) {
const QString suffix = suffixFromPattern(pattern); const QString suffix = suffixFromPattern(pattern);
if (!suffix.isEmpty()) if (!suffix.isEmpty())
result.append(suffix); result.append(suffix);
@@ -473,15 +443,15 @@ QString MimeType::preferredSuffix() const
*/ */
QString MimeType::filterString() const QString MimeType::filterString() const
{ {
MimeDatabasePrivate::instance()->loadMimeTypePrivate(const_cast<MimeTypePrivate&>(*d)); const QStringList patterns = globPatterns();
QString filter; QString filter;
if (!d->globPatterns.empty()) { if (!patterns.empty()) {
filter += comment() + " ("_L1; filter += comment() + " ("_L1;
for (int i = 0; i < d->globPatterns.size(); ++i) { for (int i = 0; i < patterns.size(); ++i) {
if (i != 0) if (i != 0)
filter += u' '; filter += u' ';
filter += d->globPatterns.at(i); filter += patterns.at(i);
} }
filter += u')'; filter += u')';
} }
@@ -522,16 +492,7 @@ bool MimeType::matchesName(const QString &nameOrAlias) const
*/ */
void MimeType::setPreferredSuffix(const QString &suffix) void MimeType::setPreferredSuffix(const QString &suffix)
{ {
MimeDatabasePrivate::instance()->loadMimeTypePrivate(const_cast<MimeTypePrivate&>(*d)); MimeDatabasePrivate::instance()->setPreferredSuffix(d->name, suffix);
auto it = std::find_if(d->globPatterns.begin(),
d->globPatterns.end(),
[suffix](const QString &pattern) {
return suffixFromPattern(pattern) == suffix;
});
if (it != d->globPatterns.end())
d->globPatterns.erase(it);
d->globPatterns.prepend(QLatin1String("*.") + suffix);
} }
QDebug operator<<(QDebug debug, const Utils::MimeType &mime) QDebug operator<<(QDebug debug, const Utils::MimeType &mime)

View File

@@ -82,6 +82,7 @@ public:
// Qt Creator additions // Qt Creator additions
bool matchesName(const QString &nameOrAlias) const; bool matchesName(const QString &nameOrAlias) const;
void setPreferredSuffix(const QString &suffix); void setPreferredSuffix(const QString &suffix);
static QString suffixFromPattern(const QString &pattern);
protected: protected:
friend class MimeTypeParserBase; friend class MimeTypeParserBase;

View File

@@ -14,54 +14,24 @@
// We mean it. // We mean it.
// //
#include "mimetype.h" #include <QtCore/qshareddata.h>
#include <QtCore/qhash.h> #include <QtCore/qhash.h>
#include <QtCore/qstringlist.h> #include <QtCore/qstringlist.h>
namespace Utils { namespace Utils {
class MimeBinaryProvider;
class MimeTypePrivate : public QSharedData class MimeTypePrivate : public QSharedData
{ {
public: public:
typedef QHash<QString, QString> LocaleHash; typedef QHash<QString, QString> LocaleHash;
MimeTypePrivate(); MimeTypePrivate() { }
explicit MimeTypePrivate(const MimeType &other); explicit MimeTypePrivate(const QString &name) : name(name) { }
void clear();
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
bool hasGlobDeleteAll = false; // true if the mimetype has a glob-deleteall tag
QString name; QString name;
LocaleHash localeComments;
QString genericIconName;
QString iconName;
QStringList globPatterns;
}; };
} // namespace Utils } // namespace Utils
#if 0
#define QMIMETYPE_BUILDER_FROM_RVALUE_REFS \
QT_BEGIN_NAMESPACE \
static QMimeType buildQMimeType ( \
QString &&name, \
QString &&genericIconName, \
QString &&iconName, \
QStringList &&globPatterns \
) \
{ \
QMimeTypePrivate qMimeTypeData; \
qMimeTypeData.loaded = true; \
qMimeTypeData.name = std::move(name); \
qMimeTypeData.genericIconName = std::move(genericIconName); \
qMimeTypeData.iconName = std::move(iconName); \
qMimeTypeData.globPatterns = std::move(globPatterns); \
return QMimeType(qMimeTypeData); \
} \
QT_END_NAMESPACE
#endif

View File

@@ -163,8 +163,7 @@ static CreateMagicMatchRuleResult createMagicMatchRule(const QXmlStreamAttribute
bool MimeTypeParserBase::parse(QIODevice *dev, const QString &fileName, QString *errorMessage) bool MimeTypeParserBase::parse(QIODevice *dev, const QString &fileName, QString *errorMessage)
{ {
#if QT_CONFIG(xmlstreamreader) #if QT_CONFIG(xmlstreamreader)
MimeTypePrivate data; MimeTypeXMLData data;
data.loaded = true;
int priority = 50; int priority = 50;
QStack<MimeMagicRule *> currentRules; // stack for the nesting of rules QStack<MimeMagicRule *> currentRules; // stack for the nesting of rules
QList<MimeMagicRule> rules; // toplevel rules QList<MimeMagicRule> rules; // toplevel rules
@@ -271,7 +270,7 @@ bool MimeTypeParserBase::parse(QIODevice *dev, const QString &fileName, QString
{ {
const auto elementName = reader.name(); const auto elementName = reader.name();
if (elementName == QLatin1StringView(mimeTypeTagC)) { if (elementName == QLatin1StringView(mimeTypeTagC)) {
if (!process(MimeType(data), errorMessage)) if (!process(data, errorMessage))
return false; return false;
data.clear(); data.clear();
} else if (elementName == QLatin1StringView(matchTagC)) { } else if (elementName == QLatin1StringView(matchTagC)) {
@@ -312,4 +311,19 @@ bool MimeTypeParserBase::parse(QIODevice *dev, const QString &fileName, QString
#endif // feature xmlstreamreader #endif // feature xmlstreamreader
} }
void MimeTypeXMLData::clear()
{
hasGlobDeleteAll = false;
name.clear();
localeComments.clear();
genericIconName.clear();
iconName.clear();
globPatterns.clear();
}
void MimeTypeXMLData::addGlobPattern(const QString &pattern)
{
globPatterns.append(pattern);
}
} // namespace Utils } // namespace Utils

View File

@@ -14,7 +14,7 @@
// We mean it. // We mean it.
// //
#include "mimedatabase_p.h" #include <QtCore/qtconfigmacros.h>
#include "mimeprovider_p.h" #include "mimeprovider_p.h"
@@ -24,6 +24,21 @@ QT_END_NAMESPACE
namespace Utils { namespace Utils {
class MimeTypeXMLData
{
public:
void clear();
void addGlobPattern(const QString &pattern);
bool hasGlobDeleteAll = false; // true if the mimetype has a glob-deleteall tag
QString name;
MimeTypePrivate::LocaleHash localeComments;
QString genericIconName; // TODO move to a struct that's specific to the XML provider
QString iconName; // TODO move to a struct that's specific to the XML provider
QStringList globPatterns;
};
class MimeTypeParserBase class MimeTypeParserBase
{ {
Q_DISABLE_COPY_MOVE(MimeTypeParserBase) Q_DISABLE_COPY_MOVE(MimeTypeParserBase)
@@ -37,7 +52,7 @@ public:
static bool parseNumber(QStringView n, int *target, QString *errorMessage); static bool parseNumber(QStringView n, int *target, QString *errorMessage);
protected: protected:
virtual bool process(const MimeType &t, QString *errorMessage) = 0; virtual bool process(const MimeTypeXMLData &t, QString *errorMessage) = 0;
virtual bool process(const MimeGlobPattern &t, QString *errorMessage) = 0; virtual bool process(const MimeGlobPattern &t, QString *errorMessage) = 0;
virtual void processParent(const QString &child, const QString &parent) = 0; virtual void processParent(const QString &child, const QString &parent) = 0;
virtual void processAlias(const QString &alias, const QString &name) = 0; virtual void processAlias(const QString &alias, const QString &name) = 0;
@@ -71,7 +86,7 @@ public:
explicit MimeTypeParser(MimeXMLProvider &provider) : m_provider(provider) {} explicit MimeTypeParser(MimeXMLProvider &provider) : m_provider(provider) {}
protected: protected:
inline bool process(const MimeType &t, QString *) override inline bool process(const MimeTypeXMLData &t, QString *) override
{ m_provider.addMimeType(t); return true; } { m_provider.addMimeType(t); return true; }
inline bool process(const MimeGlobPattern &glob, QString *) override inline bool process(const MimeGlobPattern &glob, QString *) override