QMimeDatabase: Fix MIME detection issues with magics in MIME hierarchies

Assume two MIME types A and B are registered, both with the same glob
pattern, A being parent of B, A with some magic rule, and B with another
magic rule. Given a file that matches the glob pattern and the magic rule
of A, the resulting MIME type depended on the order of registration of A
and B, because it would just check if some glob matching MIME type was
also a subclass of the magic matching MIME type.

The patch prefers the the MIME type that matches by magic if that
matches by glob pattern as well (i.e. A in our example).

The "recommended checking order" of the spec does handle that case.

Task-number: QTBUG-44846
Change-Id: I2af43f6199faf9a42cd9c35d3a045441afbd6217
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
Reviewed-by: David Faure <david.faure@kdab.com>
This commit is contained in:
Eike Ziller 2018-08-18 13:08:50 +02:00
parent fe9a37ac48
commit 67984b265a
6 changed files with 42 additions and 2 deletions

View File

@ -382,9 +382,12 @@ QMimeType QMimeDatabasePrivate::mimeTypeForFileNameAndData(const QString &fileNa
// 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();
// If the sniffedMime matches a glob match, use it
if (candidatesByName.m_matchingMimeTypes.contains(sniffedMime)) {
*accuracyPtr = 100;
return candidateByData;
}
for (const QString &m : qAsConst(candidatesByName.m_matchingMimeTypes)) {
if (inherits(m, sniffedMime)) {
// We have magic + pattern pointing to this, so it's a pretty good match

View File

@ -0,0 +1,3 @@
<?foo>
<blah>
</blah>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
<!-- The real life example would be that this mime type is a sub class of application/xml
which has a magic that matches &lt;?xml .
XML files with an early appearing qnx tag are detected as
application/vnd.qnx.bar-descriptor. We want that XML files without the qnx tag to be
identified as application/xml, independent of the order in which the two are registered. -->
<mime-type type="application/vnd.qnx.bar-descriptor">
<sub-class-of type="application/foo"/>
<glob pattern="*.foo"/>
<magic><!-- higher priority than the parent magic -->
<match value="&lt;qnx&gt;" type="string" offset="0:200"/>
</magic>
</mime-type>
<mime-type type="application/foo">
<glob pattern="*.foo"/>
<magic priority="40">
<match value="&lt;?foo" type="string" offset="0"/>
</magic>
</mime-type>
</mime-info>

View File

@ -0,0 +1,3 @@
<?foo>
<qnx>
</qnx>

View File

@ -7,5 +7,8 @@
<file>invalid-magic1.xml</file>
<file>invalid-magic2.xml</file>
<file>invalid-magic3.xml</file>
<file>magic-and-hierarchy.xml</file>
<file>magic-and-hierarchy.foo</file>
<file>magic-and-hierarchy2.foo</file>
</qresource>
</RCC>

View File

@ -52,6 +52,7 @@ static const char *const additionalMimeFiles[] = {
"invalid-magic1.xml",
"invalid-magic2.xml",
"invalid-magic3.xml",
"magic-and-hierarchy.xml",
0
};
@ -985,6 +986,12 @@ void tst_QMimeDatabase::installNewGlobalMimeType()
qDebug() << objcsrc.globPatterns();
}
const QString fooTestFile = QLatin1String(RESOURCE_PREFIX "magic-and-hierarchy.foo");
QCOMPARE(db.mimeTypeForFile(fooTestFile).name(), QString::fromLatin1("application/foo"));
const QString fooTestFile2 = QLatin1String(RESOURCE_PREFIX "magic-and-hierarchy2.foo");
QCOMPARE(db.mimeTypeForFile(fooTestFile2).name(), QString::fromLatin1("application/vnd.qnx.bar-descriptor"));
// Now test removing the mimetype definitions again
for (int i = 0; i < m_additionalMimeFileNames.size(); ++i)
QFile::remove(destDir + m_additionalMimeFileNames.at(i));