MimeDatabase: Remove bestMatch, which was broken beyond repair

The problem is that, if you check e.g. a .pro file against all C/C++ mime
types, and these define magic matchers, it would find that .pro doesn't
match C/C++ mime types by extension, so it would open the file to find a
magic match. Even though the extension .pro would identify it already as
a qmake .pro file when checking for the mime type globally.

Change-Id: I3341187e88e2263bf38169c3c99e5d2161e2a9ee
Reviewed-by: Daniel Teske <daniel.teske@theqtcompany.com>
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
This commit is contained in:
Eike Ziller
2015-02-27 16:02:25 +01:00
parent 6758b78ba6
commit 38b183fd90
7 changed files with 11 additions and 147 deletions

View File

@@ -352,79 +352,6 @@ QStringList MimeDatabase::allGlobPatterns()
return patterns; return patterns;
} }
static MimeType mimeForName(const QList<MimeType> &types, const QString &name)
{
foreach (const MimeType &mt, types)
if (mt.matchesName(name))
return mt;
return MimeType();
}
MimeType MimeDatabase::bestMatch(const QString &fileName, const QList<MimeType> &types)
{
// Copied together from mimeTypeForFile(QFileInfo) code path ...
// It would be better to be able to work on a list of mime types directly
// Check for directory. We just ignore the code path for special unix nodes.
if (fileName.endsWith(QLatin1Char('/')))
return mimeForName(types, QLatin1String("inode/directory"));
auto d = MimeDatabasePrivate::instance();
QMutexLocker locker(&d->mutex);
QStringList candidatesByName = d->provider()->bestMatchByFileName(QFileInfo(fileName).fileName(),
types);
if (candidatesByName.count() == 1) {
MimeType mt = mimeForName(types, candidatesByName.first());
if (mt.isValid())
return mt;
candidatesByName.clear();
}
// Extension is unknown, or matches multiple mimetypes.
// Pass 2) Match on content, if we can read the data
QFile file(QFileInfo(fileName).absoluteFilePath());
file.open(QIODevice::ReadOnly);
if (file.isOpen()) {
// Read 16K in one go (QIODEVICE_BUFFERSIZE in qiodevice_p.h).
// This is much faster than seeking back and forth into QIODevice.
const QByteArray data = file.peek(16384);
int magicAccuracy = 0;
MimeType candidateByData;
if (data.isEmpty()) {
magicAccuracy = 100;
candidateByData = mimeForName(types, QLatin1String("application/x-zerosize"));
} else {
candidateByData = d->provider()->bestMatchByMagic(data, types, &magicAccuracy);
if (!candidateByData.isValid()) {
if (isTextFile(data)) {
magicAccuracy = 5;
candidateByData = mimeForName(types, QLatin1String("text/plain"));
}
}
}
// Disambiguate conflicting extensions (if magic matching found something)
if (candidateByData.isValid() && magicAccuracy > 0) {
// "for glob_match in glob_matches:"
// "if glob_match is subclass or equal to sniffed_type, use glob_match"
const QString sniffedMime = candidateByData.name();
foreach (const QString &m, candidatesByName) {
if (d->inherits(m, sniffedMime)) {
// We have magic + pattern pointing to this, so it's a pretty good match
return mimeForName(types, m);
}
}
return candidateByData;
}
}
if (candidatesByName.count() > 1) {
candidatesByName.sort();
return mimeForName(types, candidatesByName.first());
}
return MimeType();
}
/*! /*!
\fn MimeType MimeDatabase::mimeTypeForName(const QString &nameOrAlias) const; \fn MimeType MimeDatabase::mimeTypeForName(const QString &nameOrAlias) const;
Returns a MIME type for \a nameOrAlias or an invalid one if none found. Returns a MIME type for \a nameOrAlias or an invalid one if none found.

View File

@@ -87,7 +87,6 @@ public:
static void addMimeTypes(const QString &fileName); static void addMimeTypes(const QString &fileName);
static QString allFiltersString(QString *allFilesFilter = 0); static QString allFiltersString(QString *allFilesFilter = 0);
static QStringList allGlobPatterns(); static QStringList allGlobPatterns();
static MimeType bestMatch(const QString &fileName, const QList<MimeType> &types);
static QMap<int, QList<Internal::MimeMagicRule> > magicRulesForMimeType(const MimeType &mimeType); // priority -> rules static QMap<int, QList<Internal::MimeMagicRule> > magicRulesForMimeType(const MimeType &mimeType); // priority -> rules
static void setGlobPatternsForMimeType(const MimeType &mimeType, const QStringList &patterns); static void setGlobPatternsForMimeType(const MimeType &mimeType, const QStringList &patterns);
static void setMagicRulesForMimeType(const MimeType &mimeType, static void setMagicRulesForMimeType(const MimeType &mimeType,

View File

@@ -719,38 +719,6 @@ QStringList MimeXMLProvider::findByFileName(const QString &fileName, QString *fo
return matchingMimeTypes; return matchingMimeTypes;
} }
QStringList MimeXMLProvider::bestMatchByFileName(const QString &fileName, const QList<MimeType> &types)
{
ensureLoaded();
// this is slow :(
// this would be much better if MimeType had references to their globs & magics
MimeAllGlobPatterns globs;
// fast patterns are fast (hash lookup), no need to reduce that set
globs.m_fastPatterns = m_mimeTypeGlobs.m_fastPatterns;
// fill highWeight and lowWeight glob lists
QSet<QString> names;
foreach (const MimeType &mt, types)
names.insert(mt.name());
foreach (const MimeGlobPattern &pattern, m_mimeTypeGlobs.m_highWeightGlobs) {
if (names.contains(pattern.mimeType()))
globs.m_highWeightGlobs.append(pattern);
}
foreach (const MimeGlobPattern &pattern, m_mimeTypeGlobs.m_lowWeightGlobs) {
if (names.contains(pattern.mimeType()))
globs.m_lowWeightGlobs.append(pattern);
}
QString foundSuffix;
const QStringList matchingMimeTypes = globs.matchingGlobs(fileName, &foundSuffix);
// result can still contain types that are not in our list, because of the fast patterns
QStringList result;
foreach (const QString &match, matchingMimeTypes) {
if (names.contains(match))
result.append(match);
}
return result;
}
MimeType MimeXMLProvider::findByMagic(const QByteArray &data, int *accuracyPtr) MimeType MimeXMLProvider::findByMagic(const QByteArray &data, int *accuracyPtr)
{ {
ensureLoaded(); ensureLoaded();
@@ -769,30 +737,6 @@ MimeType MimeXMLProvider::findByMagic(const QByteArray &data, int *accuracyPtr)
return mimeTypeForName(candidate); return mimeTypeForName(candidate);
} }
MimeType MimeXMLProvider::bestMatchByMagic(const QByteArray &data, const QList<MimeType> &types, int *accuracyPtr)
{
ensureLoaded();
QSet<QString> names;
foreach (const MimeType &mt, types)
names.insert(mt.name());
QString candidate;
foreach (const MimeMagicRuleMatcher &matcher, m_magicMatchers) {
if (!names.contains(matcher.mimetype()))
continue;
if (matcher.matches(data)) {
const int priority = matcher.priority();
if (priority > *accuracyPtr) {
*accuracyPtr = priority;
candidate = matcher.mimetype();
}
}
}
return mimeTypeForName(candidate);
}
QMap<int, QList<MimeMagicRule> > MimeXMLProvider::magicRulesForMimeType(const MimeType &mimeType) QMap<int, QList<MimeMagicRule> > MimeXMLProvider::magicRulesForMimeType(const MimeType &mimeType)
{ {
QMap<int, QList<MimeMagicRule> > result; QMap<int, QList<MimeMagicRule> > result;

View File

@@ -75,8 +75,6 @@ public:
virtual void loadGenericIcon(MimeTypePrivate &) {} virtual void loadGenericIcon(MimeTypePrivate &) {}
// Qt Creator additions // Qt Creator additions
virtual QStringList bestMatchByFileName(const QString &fileName, const QList<MimeType> &types) = 0;
virtual MimeType bestMatchByMagic(const QByteArray &data, const QList<MimeType> &types, int *accuracyPtr) = 0;
virtual QMap<int, QList<MimeMagicRule> > magicRulesForMimeType(const MimeType &mimeType) = 0; virtual QMap<int, QList<MimeMagicRule> > magicRulesForMimeType(const MimeType &mimeType) = 0;
virtual void setGlobPatternsForMimeType(const MimeType &mimeType, const QStringList &patterns) = 0; virtual void setGlobPatternsForMimeType(const MimeType &mimeType, const QStringList &patterns) = 0;
virtual void setMagicRulesForMimeType(const MimeType &mimeType, const QMap<int, QList<MimeMagicRule> > &rules) = 0; virtual void setMagicRulesForMimeType(const MimeType &mimeType, const QMap<int, QList<MimeMagicRule> > &rules) = 0;
@@ -158,8 +156,6 @@ public:
// Qt Creator additions // Qt Creator additions
void addFile(const QString &filePath); void addFile(const QString &filePath);
QStringList bestMatchByFileName(const QString &fileName, const QList<MimeType> &types);
MimeType bestMatchByMagic(const QByteArray &data, const QList<MimeType> &types, int *accuracyPtr);
QMap<int, QList<MimeMagicRule> > magicRulesForMimeType(const MimeType &mimeType); QMap<int, QList<MimeMagicRule> > magicRulesForMimeType(const MimeType &mimeType);
void setGlobPatternsForMimeType(const MimeType &mimeType, const QStringList &patterns); void setGlobPatternsForMimeType(const MimeType &mimeType, const QStringList &patterns);
void setMagicRulesForMimeType(const MimeType &mimeType, const QMap<int, QList<MimeMagicRule> > &rules); void setMagicRulesForMimeType(const MimeType &mimeType, const QMap<int, QList<MimeMagicRule> > &rules);

View File

@@ -142,8 +142,9 @@ ProjectFileAdder::~ProjectFileAdder()
bool ProjectFileAdder::maybeAdd(const QString &path) bool ProjectFileAdder::maybeAdd(const QString &path)
{ {
const Utils::MimeType mt = Utils::MimeDatabase::bestMatch(path, m_mimeTypes); Utils::MimeDatabase mdb;
if (mt.isValid()) { const Utils::MimeType mt = mdb.mimeTypeForFile(path);
if (m_mimeNameMapping.contains(mt.name())) {
m_files << ProjectFile(path, m_mimeNameMapping.value(mt.name())); m_files << ProjectFile(path, m_mimeNameMapping.value(mt.name()));
return true; return true;
} }
@@ -154,10 +155,8 @@ void ProjectFileAdder::addMapping(const char *mimeName, ProjectFile::Kind kind)
{ {
Utils::MimeDatabase mdb; Utils::MimeDatabase mdb;
Utils::MimeType mimeType = mdb.mimeTypeForName(QLatin1String(mimeName)); Utils::MimeType mimeType = mdb.mimeTypeForName(QLatin1String(mimeName));
if (mimeType.isValid()) { if (mimeType.isValid())
m_mimeNameMapping.insert(mimeType.name(), kind); m_mimeNameMapping.insert(mimeType.name(), kind);
m_mimeTypes.append(mimeType);
}
} }
} // namespace Internal } // namespace Internal

View File

@@ -88,7 +88,6 @@ private:
QList<ProjectFile> &m_files; QList<ProjectFile> &m_files;
QHash<QString, ProjectFile::Kind> m_mimeNameMapping; QHash<QString, ProjectFile::Kind> m_mimeNameMapping;
QList<Utils::MimeType> m_mimeTypes;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -81,14 +81,14 @@ ModelManagerInterface::ProjectInfo ModelManager::defaultProjectInfoForProject(
Target *activeTarget = 0; Target *activeTarget = 0;
if (project) { if (project) {
MimeDatabase mdb; MimeDatabase mdb;
QList<MimeType> qmlTypes; QSet<QString> qmlTypeNames;
foreach (const MimeType &mimeType, mdb.allMimeTypes()) { qmlTypeNames << QLatin1String(Constants::QML_MIMETYPE)
if (mimeType.matchesName(QLatin1String(Constants::QML_MIMETYPE)) << QLatin1String(Constants::QBS_MIMETYPE)
|| mimeType.allAncestors().contains(QLatin1String(Constants::QML_MIMETYPE))) << QLatin1String(Constants::QMLPROJECT_MIMETYPE)
qmlTypes.append(mimeType); << QLatin1String(Constants::QMLTYPES_MIMETYPE)
} << QLatin1String(Constants::QMLUI_MIMETYPE);
foreach (const QString &filePath, project->files(Project::ExcludeGeneratedFiles)) { foreach (const QString &filePath, project->files(Project::ExcludeGeneratedFiles)) {
if (mdb.bestMatch(filePath, qmlTypes).isValid()) if (qmlTypeNames.contains(mdb.mimeTypeForFile(filePath).name()))
projectInfo.sourceFiles << filePath; projectInfo.sourceFiles << filePath;
} }
activeTarget = project->activeTarget(); activeTarget = project->activeTarget();