QMimeType::suffixForFileName shouldn't lowercase the file suffix

It was returning a lowercased suffix because it was extracting it from
the pattern (*.txt) rather than from the filename ("README.TXT").

This broke expectations on the application side, since this method is
documented to return a suffix from the given filename.

Ref: https://bugs.kde.org/show_bug.cgi?id=402388

Change-Id: I7dae13db31280249d3f592fa9592c4067804e22d
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
David Faure 2020-03-26 11:09:24 +02:00
parent b0294bb1c7
commit 4f1ebf666e
5 changed files with 33 additions and 16 deletions

View File

@ -638,7 +638,8 @@ QList<QMimeType> QMimeDatabase::mimeTypesForFileName(const QString &fileName) co
QString QMimeDatabase::suffixForFileName(const QString &fileName) const
{
QMutexLocker locker(&d->mutex);
return d->findByFileName(QFileInfo(fileName).fileName()).m_foundSuffix;
const int suffixLength = d->findByFileName(QFileInfo(fileName).fileName()).m_knownSuffixLength;
return fileName.right(suffixLength);
}
/*!

View File

@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE
Handles glob weights, and preferring longer matches over shorter matches.
*/
void QMimeGlobMatchResult::addMatch(const QString &mimeType, int weight, const QString &pattern)
void QMimeGlobMatchResult::addMatch(const QString &mimeType, int weight, const QString &pattern, int knownSuffixLength)
{
if (m_allMatchingMimeTypes.contains(mimeType))
return;
@ -84,8 +84,7 @@ void QMimeGlobMatchResult::addMatch(const QString &mimeType, int weight, const Q
if (!m_matchingMimeTypes.contains(mimeType)) {
m_matchingMimeTypes.append(mimeType);
m_allMatchingMimeTypes.append(mimeType);
if (pattern.startsWith(QLatin1String("*.")))
m_foundSuffix = pattern.mid(2);
m_knownSuffixLength = knownSuffixLength;
}
}
@ -152,6 +151,18 @@ bool QMimeGlobPattern::matchFileName(const QString &inputFilename) const
#endif
}
static bool isSimplePattern(const QString &pattern)
{
// starts with "*.", has no other '*'
return pattern.lastIndexOf(QLatin1Char('*')) == 0
&& pattern.length() > 1
&& pattern.at(1) == QLatin1Char('.') // (other dots are OK, like *.tar.bz2)
// and contains no other special character
&& !pattern.contains(QLatin1Char('?'))
&& !pattern.contains(QLatin1Char('['))
;
}
static bool isFastPattern(const QString &pattern)
{
// starts with "*.", has no other '*' and no other '.'
@ -205,8 +216,11 @@ void QMimeGlobPatternList::match(QMimeGlobMatchResult &result,
const QMimeGlobPatternList::const_iterator endIt = this->constEnd();
for (; it != endIt; ++it) {
const QMimeGlobPattern &glob = *it;
if (glob.matchFileName(fileName))
result.addMatch(glob.mimeType(), glob.weight(), glob.pattern());
if (glob.matchFileName(fileName)) {
const QString pattern = glob.pattern();
const int suffixLen = isSimplePattern(pattern) ? pattern.length() - 2 : 0;
result.addMatch(glob.mimeType(), glob.weight(), pattern, suffixLen);
}
}
}
@ -226,7 +240,7 @@ void QMimeAllGlobPatterns::matchingGlobs(const QString &fileName, QMimeGlobMatch
const QStringList matchingMimeTypes = m_fastPatterns.value(simpleExtension);
const QString simplePattern = QLatin1String("*.") + simpleExtension;
for (const QString &mime : matchingMimeTypes)
result.addMatch(mime, 50, simplePattern);
result.addMatch(mime, 50, simplePattern, simpleExtension.size());
// Can't return yet; *.tar.bz2 has to win over *.bz2, so we need the low-weight mimetypes anyway,
// at least those with weight 50.
}

View File

@ -62,17 +62,13 @@ QT_BEGIN_NAMESPACE
struct QMimeGlobMatchResult
{
QMimeGlobMatchResult()
: m_weight(0), m_matchingPatternLength(0)
{}
void addMatch(const QString &mimeType, int weight, const QString &pattern);
void addMatch(const QString &mimeType, int weight, const QString &pattern, int knownSuffixLength = 0);
QStringList m_matchingMimeTypes; // only those with highest weight
QStringList m_allMatchingMimeTypes;
int m_weight;
int m_matchingPatternLength;
QString m_foundSuffix;
int m_weight = 0;
int m_matchingPatternLength = 0;
int m_knownSuffixLength = 0;
};
class QMimeGlobPattern

View File

@ -306,7 +306,7 @@ bool QMimeBinaryProvider::matchSuffixTree(QMimeGlobMatchResult &result, QMimeBin
const bool caseSensitive = flagsAndWeight & 0x100;
if (caseSensitiveCheck || !caseSensitive) {
result.addMatch(QLatin1String(mimeType), weight,
QLatin1Char('*') + fileName.midRef(charPos + 1));
QLatin1Char('*') + fileName.midRef(charPos + 1), fileName.size() - charPos - 2);
success = true;
}
}

View File

@ -667,6 +667,9 @@ void tst_QMimeDatabase::knownSuffix()
QCOMPARE(db.suffixForFileName(QString::fromLatin1("foo.bz2")), QString::fromLatin1("bz2"));
QCOMPARE(db.suffixForFileName(QString::fromLatin1("foo.bar.bz2")), QString::fromLatin1("bz2"));
QCOMPARE(db.suffixForFileName(QString::fromLatin1("foo.tar.bz2")), QString::fromLatin1("tar.bz2"));
QCOMPARE(db.suffixForFileName(QString::fromLatin1("foo.TAR")), QString::fromLatin1("TAR")); // preserve case
QCOMPARE(db.suffixForFileName(QString::fromLatin1("foo.flatpakrepo")), QString::fromLatin1("flatpakrepo"));
QCOMPARE(db.suffixForFileName(QString::fromLatin1("foo.anim2")), QString()); // the glob is anim[0-9], no way to extract the extension without expensive regexp capturing
}
void tst_QMimeDatabase::symlinkToFifo() // QTBUG-48529
@ -784,6 +787,9 @@ void tst_QMimeDatabase::findByFileName()
// Test QFileInfo overload
const QMimeType mimeForFileInfo = database.mimeTypeForFile(QFileInfo(filePath), QMimeDatabase::MatchExtension);
QCOMPARE(mimeForFileInfo.name(), resultMimeTypeName);
const QString suffix = database.suffixForFileName(filePath);
QVERIFY2(filePath.endsWith(suffix), qPrintable(filePath + " does not end with " + suffix));
}
void tst_QMimeDatabase::findByData_data()