Update shared-mime-info to the 2.1 release, adjust implementation

The spec hasn't changed, but I made the same mistake in xdgmime
(the reference implementation) and in Qt: when multiple globs match,
and the result from magic sniffing is unrelated to any of those globs,
then I used the magic result, but that's wrong, globs have priority
and one of them should be picked up.

This is now fixed in xdgmime
(https://gitlab.freedesktop.org/xdg/xdgmime/-/merge_requests/3)
and in the expected results in shared-mime-info
(https://gitlab.freedesktop.org/xdg/shared-mime-info/-/merge_requests/99)
which this commit is also tested against.

This change also optimizes QMimeBinaryProvider::addFileNameMatches
to have the same logic as xdgmime for glob matching:
literals > extensions > other globs
As soon as one category matches, we can stop there.
This makes no difference in the overall results, in practice.

The user bug report (against the Qt implementation, actually)
is https://gitlab.freedesktop.org/xdg/shared-mime-info/-/issues/138
as well as https://bugs.kde.org/show_bug.cgi?id=411718

Change-Id: Ia0a34080427daff43c732609443ee6df8f41447c
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
(cherry picked from commit 0cbbba2aa5b472241d45b4be6959a792062fbc30)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
David Faure 2020-12-31 21:28:51 +01:00 committed by Qt Cherry-pick Bot
parent 51e940260a
commit 95c72df310
5 changed files with 8883 additions and 7056 deletions

File diff suppressed because it is too large Load Diff

View File

@ -388,20 +388,23 @@ QMimeType QMimeDatabasePrivate::mimeTypeForFileNameAndData(const QString &fileNa
// Disambiguate conflicting extensions (if magic matching found something)
if (candidateByData.isValid() && magicAccuracy > 0) {
const QString sniffedMime = candidateByData.name();
// If the sniffedMime matches a glob match, use it
// If the sniffedMime matches a highest-weight glob match, use it
if (candidatesByName.m_matchingMimeTypes.contains(sniffedMime)) {
*accuracyPtr = 100;
return candidateByData;
}
for (const QString &m : qAsConst(candidatesByName.m_matchingMimeTypes)) {
for (const QString &m : qAsConst(candidatesByName.m_allMatchingMimeTypes)) {
if (inherits(m, sniffedMime)) {
// We have magic + pattern pointing to this, so it's a pretty good match
*accuracyPtr = 100;
return mimeTypeForName(m);
}
}
*accuracyPtr = magicAccuracy;
return candidateByData;
if (candidatesByName.m_allMatchingMimeTypes.isEmpty()) {
// No glob, use magic
*accuracyPtr = magicAccuracy;
return candidateByData;
}
}
}

View File

@ -83,7 +83,10 @@ void QMimeGlobMatchResult::addMatch(const QString &mimeType, int weight, const Q
}
if (!m_matchingMimeTypes.contains(mimeType)) {
m_matchingMimeTypes.append(mimeType);
m_allMatchingMimeTypes.append(mimeType);
if (replace)
m_allMatchingMimeTypes.prepend(mimeType); // highest-weight first
else
m_allMatchingMimeTypes.append(mimeType);
m_knownSuffixLength = knownSuffixLength;
}
}

View File

@ -244,15 +244,18 @@ void QMimeBinaryProvider::addFileNameMatches(const QString &fileName, QMimeGlobM
const QString lowerFileName = fileName.toLower();
// Check literals (e.g. "Makefile")
matchGlobList(result, m_cacheFile, m_cacheFile->getUint32(PosLiteralListOffset), fileName);
// Check complex globs (e.g. "callgrind.out[0-9]*")
matchGlobList(result, m_cacheFile, m_cacheFile->getUint32(PosGlobListOffset), fileName);
// Check the very common *.txt cases with the suffix tree
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, numRoots, firstRootOffset, lowerFileName, lowerFileName.length() - 1, false);
if (result.m_matchingMimeTypes.isEmpty()) {
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, numRoots, firstRootOffset, lowerFileName, lowerFileName.length() - 1, false);
if (result.m_matchingMimeTypes.isEmpty())
matchSuffixTree(result, m_cacheFile, numRoots, firstRootOffset, fileName, fileName.length() - 1, true);
}
// Check complex globs (e.g. "callgrind.out[0-9]*" or "README*")
if (result.m_matchingMimeTypes.isEmpty())
matchSuffixTree(result, m_cacheFile, numRoots, firstRootOffset, fileName, fileName.length() - 1, true);
matchGlobList(result, m_cacheFile, m_cacheFile->getUint32(PosGlobListOffset), fileName);
}
void QMimeBinaryProvider::matchGlobList(QMimeGlobMatchResult &result, CacheFile *cacheFile, int off, const QString &fileName)

View File

@ -70,15 +70,15 @@ static inline QString testSuiteWarning()
QString result;
QTextStream str(&result);
str << "\nCannot find the shared-mime-info test suite\nstarting from: "
str << "\nCannot find the shared-mime-info test suite\nin the parent of: "
<< QDir::toNativeSeparators(QDir::currentPath()) << "\n"
"cd " << QDir::toNativeSeparators(QStringLiteral("tests/auto/corelib/mimetypes/qmimedatabase")) << "\n"
"wget https://gitlab.freedesktop.org/xdg/shared-mime-info/-/archive/Release-1-10/shared-mime-info-Release-1-10.zip\n"
"unzip shared-mime-info-Release-1-10.zip\n";
"wget https://gitlab.freedesktop.org/xdg/shared-mime-info/-/archive/2.1/shared-mime-info-2.1.zip\n"
"unzip shared-mime-info-2.1.zip\n";
#ifdef Q_OS_WIN
str << "mkdir testfiles\nxcopy /s shared-mime-info-Release-1-10 s-m-i\n";
str << "mkdir testfiles\nxcopy /s shared-mime-info-2.1 s-m-i\n";
#else
str << "ln -s shared-mime-info-Release-1-10 s-m-i\n";
str << "ln -s shared-mime-info-2.1 s-m-i\n";
#endif
return result;
}
@ -154,7 +154,7 @@ void tst_QMimeDatabase::initTestCase()
QVERIFY2(copyResourceFile(xmlFileName, xmlTargetFileName, &errorMessage), qPrintable(errorMessage));
#endif
m_testSuite = QFINDTESTDATA("s-m-i/tests");
m_testSuite = QFINDTESTDATA("../s-m-i/tests/mime-detection");
if (m_testSuite.isEmpty())
qWarning("%s", qPrintable(testSuiteWarning()));
@ -611,7 +611,7 @@ void tst_QMimeDatabase::allMimeTypes()
QVERIFY(!lst.isEmpty());
// Hardcoding this is the only way to check both providers find the same number of mimetypes.
QCOMPARE(lst.count(), 779);
QCOMPARE(lst.count(), 811);
foreach (const QMimeType &mime, lst) {
const QString name = mime.name();
@ -631,10 +631,9 @@ void tst_QMimeDatabase::suffixes_data()
QTest::newRow("mimetype with a single pattern") << "application/pdf" << "*.pdf" << "pdf";
QTest::newRow("mimetype with multiple patterns") << "application/x-kpresenter" << "*.kpr;*.kpt" << "kpr";
QTest::newRow("jpeg") << "image/jpeg" << "*.jpe;*.jpg;*.jpeg" << "jpeg";
//if (KMimeType::sharedMimeInfoVersion() > KDE_MAKE_VERSION(0, 60, 0)) {
QTest::newRow("mimetype with many patterns") << "application/vnd.wordperfect" << "*.wp;*.wp4;*.wp5;*.wp6;*.wpd;*.wpp" << "wp";
//}
// The preferred suffix for image/jpeg is *.jpg, as per https://bugs.kde.org/show_bug.cgi?id=176737
QTest::newRow("jpeg") << "image/jpeg" << "*.jpe;*.jpg;*.jpeg" << "jpg";
QTest::newRow("mimetype with many patterns") << "application/vnd.wordperfect" << "*.wp;*.wp4;*.wp5;*.wp6;*.wpd;*.wpp" << "wp";
QTest::newRow("oasis text mimetype") << "application/vnd.oasis.opendocument.text" << "*.odt" << "odt";
QTest::newRow("oasis presentation mimetype") << "application/vnd.oasis.opendocument.presentation" << "*.odp" << "odp";
QTest::newRow("mimetype with multiple patterns") << "text/plain" << "*.asc;*.txt;*,v" << "txt";