Utils: Remove old MIME database implementation

The new one has been in use for long enough now, that we
don't need the old one for regression testing anymore.

Change-Id: I20a4a1dae483b1fee345ea4ec8e31509f6877047
Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
This commit is contained in:
Eike Ziller
2023-01-03 11:55:43 +01:00
parent 0a3f66c790
commit 5a4092106e
20 changed files with 5 additions and 3854 deletions

View File

@@ -195,17 +195,9 @@ add_qtc_library(Utils
wizardpage.cpp wizardpage.h
)
option(QTC_USE_NEW_MIMEDATABASE "Use updated MIME database implementation" YES)
if(QTC_USE_NEW_MIMEDATABASE)
set(mime_prefix "mimetypes2")
else()
set(mime_prefix "mimetypes")
endif()
extend_qtc_library(Utils
SOURCES_PREFIX ${mime_prefix}
PUBLIC_INCLUDES ${mime_prefix}
SOURCES_PREFIX mimetypes2
PUBLIC_INCLUDES mimetypes2
SOURCES
mimedatabase.cpp
mimedatabase.h

View File

@@ -1,586 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR LGPL-3.0
#include <qplatformdefs.h> // always first
#include "mimedatabase.h"
#include "mimedatabase_p.h"
#include "mimemagicrule_p.h"
#include "mimeprovider_p.h"
#include "mimetype_p.h"
#include <utils/fileutils.h>
#include <QCoreApplication>
#include <QFile>
#include <QFileInfo>
#include <QSet>
#include <QBuffer>
#include <QUrl>
#include <QStack>
#include <QDebug>
#include <algorithm>
#include <functional>
using namespace Utils;
using namespace Utils::Internal;
Q_GLOBAL_STATIC(MimeDatabasePrivate, staticMimeDatabase)
MimeDatabasePrivate *MimeDatabasePrivate::instance()
{
return staticMimeDatabase();
}
MimeDatabasePrivate::MimeDatabasePrivate()
: m_provider(nullptr), m_defaultMimeType(QLatin1String("application/octet-stream"))
{
}
MimeDatabasePrivate::~MimeDatabasePrivate()
{
delete m_provider;
m_provider = nullptr;
}
MimeProviderBase *MimeDatabasePrivate::provider()
{
if (!m_provider) {
// MimeProviderBase *binaryProvider = new MimeBinaryProvider(this);
// if (binaryProvider->isValid()) {
// m_provider = binaryProvider;
// } else {
// delete binaryProvider;
m_provider = new MimeXMLProvider(this);
// }
}
return m_provider;
}
void MimeDatabasePrivate::setProvider(MimeProviderBase *theProvider)
{
delete m_provider;
m_provider = theProvider;
}
/*!
\internal
Returns a MIME type or an invalid one if none found
*/
MimeType MimeDatabasePrivate::mimeTypeForName(const QString &nameOrAlias)
{
return provider()->mimeTypeForName(provider()->resolveAlias(nameOrAlias));
}
QStringList MimeDatabasePrivate::mimeTypeForFileName(const QString &fileName, QString *foundSuffix)
{
if (fileName.endsWith(QLatin1Char('/')))
return QStringList("inode/directory");
const QStringList matchingMimeTypes = provider()->findByFileName(QFileInfo(fileName).fileName(), foundSuffix);
return matchingMimeTypes;
}
static inline bool isTextFile(const QByteArray &data)
{
// UTF16 byte order marks
static const char bigEndianBOM[] = "\xFE\xFF";
static const char littleEndianBOM[] = "\xFF\xFE";
if (data.startsWith(bigEndianBOM) || data.startsWith(littleEndianBOM))
return true;
// Check the first 32 bytes (see shared-mime spec)
const char *p = data.constData();
const char *e = p + qMin(32, data.size());
for ( ; p < e; ++p) {
if ((unsigned char)(*p) < 32 && *p != 9 && *p !=10 && *p != 13)
return false;
}
return true;
}
MimeType MimeDatabasePrivate::findByData(const QByteArray &data, int *accuracyPtr)
{
// if (data.isEmpty()) {
// *accuracyPtr = 100;
// return mimeTypeForName(QLatin1String("application/x-zerosize"));
// }
*accuracyPtr = 0;
MimeType candidate = provider()->findByMagic(data, accuracyPtr);
if (candidate.isValid())
return candidate;
if (isTextFile(data)) {
*accuracyPtr = 5;
return mimeTypeForName(QLatin1String("text/plain"));
}
return mimeTypeForName(defaultMimeType());
}
MimeType MimeDatabasePrivate::mimeTypeForFileNameAndData(const QString &fileName, QIODevice *device, int *accuracyPtr)
{
// First, glob patterns are evaluated. If there is a match with max weight,
// this one is selected and we are done. Otherwise, the file contents are
// evaluated and the match with the highest value (either a magic priority or
// a glob pattern weight) is selected. Matching starts from max level (most
// specific) in both cases, even when there is already a suffix matching candidate.
*accuracyPtr = 0;
// Pass 1) Try to match on the file name
QStringList candidatesByName = mimeTypeForFileName(fileName);
if (candidatesByName.count() == 1) {
*accuracyPtr = 100;
const MimeType mime = mimeTypeForName(candidatesByName.at(0));
if (mime.isValid())
return mime;
candidatesByName.clear();
}
// Extension is unknown, or matches multiple mimetypes.
// Pass 2) Match on content, if we can read the data
const bool openedByUs = !device->isOpen() && device->open(QIODevice::ReadOnly);
if (device->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 = device->peek(16384);
if (openedByUs)
device->close();
int magicAccuracy = 0;
MimeType candidateByData(findByData(data, &magicAccuracy));
// 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 (candidatesByName.contains(sniffedMime)) {
*accuracyPtr = 100;
return candidateByData;
}
// If there is a glob match that is a sub class of sniffedMime, use it
for (const QString &m : std::as_const(candidatesByName)) {
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.count() > 1) {
*accuracyPtr = 20;
candidatesByName.sort(); // to make it deterministic
const MimeType mime = mimeTypeForName(candidatesByName.at(0));
if (mime.isValid())
return mime;
}
return mimeTypeForName(defaultMimeType());
}
QList<MimeType> MimeDatabasePrivate::allMimeTypes()
{
return provider()->allMimeTypes();
}
bool MimeDatabasePrivate::inherits(const QString &mime, const QString &parent)
{
const QString resolvedParent = provider()->resolveAlias(parent);
//Q_ASSERT(provider()->resolveAlias(mime) == mime);
QStack<QString> toCheck;
QSet<QString> seen; // avoid endless loop on bogus mime data
toCheck.push(mime);
seen.insert(mime);
while (!toCheck.isEmpty()) {
const QString current = toCheck.pop();
if (current == resolvedParent)
return true;
const QStringList parents = provider()->parents(current);
for (const QString &par : parents) {
int seenSize = seen.size();
seen.insert(par);
if (seen.size() != seenSize) // haven't seen before, so add
toCheck.push(par);
}
}
return false;
}
/*!
\class MimeDatabase
\inmodule QtCore
\brief The MimeDatabase class maintains a database of MIME types.
\since 5.0
The MIME type database is provided by the freedesktop.org shared-mime-info
project. If the MIME type database cannot be found on the system, as is the case
on most Windows and Mac OS X systems, Qt will use its own copy of it.
Applications which want to define custom MIME types need to install an
XML file into the locations searched for MIME definitions.
These locations can be queried with
\code
QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QLatin1String("mime/packages"),
QStandardPaths::LocateDirectory);
\endcode
On a typical Unix system, this will be /usr/share/mime/packages/, but it is also
possible to extend the list of directories by setting the environment variable
\c XDG_DATA_DIRS. For instance adding /opt/myapp/share to \c XDG_DATA_DIRS will result
in /opt/myapp/share/mime/packages/ being searched for MIME definitions.
Here is an example of MIME XML:
\code
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="application/vnd.qt.qmakeprofile">
<comment xml:lang="en">Qt qmake Profile</comment>
<glob pattern="*.pro" weight="50"/>
</mime-type>
</mime-info>
\endcode
For more details about the syntax of XML MIME definitions, including defining
"magic" in order to detect MIME types based on data as well, read the
Shared Mime Info specification at
http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html
On Unix systems, a binary cache is used for more performance. This cache is generated
by the command "update-mime-database path", where path would be /opt/myapp/share/mime
in the above example. Make sure to run this command when installing the MIME type
definition file.
\threadsafe
\snippet code/src_corelib_mimetype_qmimedatabase.cpp 0
\sa MimeType
*/
/*!
\fn MimeDatabase::MimeDatabase();
Constructs a MimeDatabase object.
It is perfectly OK to create an instance of MimeDatabase every time you need to
perform a lookup.
The parsing of mimetypes is done on demand (when shared-mime-info is installed)
or when the very first instance is constructed (when parsing XML files directly).
*/
MimeDatabase::MimeDatabase() :
d(staticMimeDatabase())
{
}
/*!
\fn MimeDatabase::~MimeDatabase();
Destroys the MimeDatabase object.
*/
MimeDatabase::~MimeDatabase()
{
d = nullptr;
}
/*!
\fn MimeType MimeDatabase::mimeTypeForName(const QString &nameOrAlias) const;
Returns a MIME type for \a nameOrAlias or an invalid one if none found.
*/
MimeType MimeDatabase::mimeTypeForName(const QString &nameOrAlias) const
{
QMutexLocker locker(&d->mutex);
if (d->m_startupPhase <= MimeDatabase::PluginsInitializing)
qWarning("Accessing MimeDatabase for %s before plugins are initialized", qPrintable(nameOrAlias));
return d->mimeTypeForName(nameOrAlias);
}
/*!
Returns a MIME type for \a fileInfo.
A valid MIME type is always returned.
The default matching algorithm looks at both the file name and the file
contents, if necessary. The file extension has priority over the contents,
but the contents will be used if the file extension is unknown, or
matches multiple MIME types.
If \a fileInfo is a Unix symbolic link, the file that it refers to
will be used instead.
If the file doesn't match any known pattern or data, the default MIME type
(application/octet-stream) is returned.
When \a mode is set to MatchExtension, only the file name is used, not
the file contents. The file doesn't even have to exist. If the file name
doesn't match any known pattern, the default MIME type (application/octet-stream)
is returned.
If multiple MIME types match this file, the first one (alphabetically) is returned.
When \a mode is set to MatchContent, and the file is readable, only the
file contents are used to determine the MIME type. This is equivalent to
calling mimeTypeForData with a QFile as input device.
\a fileInfo may refer to an absolute or relative path.
\sa MimeType::isDefault(), mimeTypeForData()
*/
MimeType MimeDatabase::mimeTypeForFile(const QFileInfo &fileInfo, MatchMode mode) const
{
QMutexLocker locker(&d->mutex);
if (fileInfo.isDir())
return d->mimeTypeForName(QLatin1String("inode/directory"));
QFile file(fileInfo.absoluteFilePath());
#ifdef Q_OS_UNIX
// Cannot access statBuf.st_mode from the filesystem engine, so we have to stat again.
const QByteArray nativeFilePath = QFile::encodeName(file.fileName());
QT_STATBUF statBuffer;
if (QT_LSTAT(nativeFilePath.constData(), &statBuffer) == 0) {
if (S_ISCHR(statBuffer.st_mode))
return d->mimeTypeForName(QLatin1String("inode/chardevice"));
if (S_ISBLK(statBuffer.st_mode))
return d->mimeTypeForName(QLatin1String("inode/blockdevice"));
if (S_ISFIFO(statBuffer.st_mode))
return d->mimeTypeForName(QLatin1String("inode/fifo"));
if (S_ISSOCK(statBuffer.st_mode))
return d->mimeTypeForName(QLatin1String("inode/socket"));
}
#endif
int priority = 0;
switch (mode) {
case MatchDefault:
return d->mimeTypeForFileNameAndData(fileInfo.absoluteFilePath(), &file, &priority);
case MatchExtension:
locker.unlock();
return mimeTypeForFile(fileInfo.absoluteFilePath(), mode);
case MatchContent:
if (file.open(QIODevice::ReadOnly)) {
locker.unlock();
return mimeTypeForData(&file);
} else {
return d->mimeTypeForName(d->defaultMimeType());
}
default:
Q_ASSERT(false);
}
return d->mimeTypeForName(d->defaultMimeType());
}
/*!
Returns a MIME type for the file named \a fileName using \a mode.
\overload
*/
MimeType MimeDatabase::mimeTypeForFile(const QString &fileName, MatchMode mode) const
{
if (mode == MatchExtension) {
QMutexLocker locker(&d->mutex);
QStringList matches = d->mimeTypeForFileName(fileName);
const int matchCount = matches.count();
if (matchCount == 0) {
return d->mimeTypeForName(d->defaultMimeType());
} else if (matchCount == 1) {
return d->mimeTypeForName(matches.first());
} else {
// We have to pick one.
matches.sort(); // Make it deterministic
return d->mimeTypeForName(matches.first());
}
} else {
// Implemented as a wrapper around mimeTypeForFile(QFileInfo), so no mutex.
QFileInfo fileInfo(fileName);
return mimeTypeForFile(fileInfo, mode);
}
}
/*!
Returns the MIME types for the file name \a fileName.
If the file name doesn't match any known pattern, an empty list is returned.
If multiple MIME types match this file, they are all returned.
This function does not try to open the file. To also use the content
when determining the MIME type, use mimeTypeForFile() or
mimeTypeForFileNameAndData() instead.
\sa mimeTypeForFile()
*/
QList<MimeType> MimeDatabase::mimeTypesForFileName(const QString &fileName) const
{
QMutexLocker locker(&d->mutex);
QStringList matches = d->mimeTypeForFileName(fileName);
QList<MimeType> mimes;
matches.sort(); // Make it deterministic
for (const QString &mime : std::as_const(matches))
mimes.append(d->mimeTypeForName(mime));
return mimes;
}
/*!
Returns the suffix for the file \a fileName, as known by the MIME database.
This allows to pre-select "tar.bz2" for foo.tar.bz2, but still only
"txt" for my.file.with.dots.txt.
*/
QString MimeDatabase::suffixForFileName(const QString &fileName) const
{
QMutexLocker locker(&d->mutex);
QString foundSuffix;
d->mimeTypeForFileName(fileName, &foundSuffix);
return foundSuffix;
}
/*!
Returns a MIME type for \a data.
A valid MIME type is always returned. If \a data doesn't match any
known MIME type data, the default MIME type (application/octet-stream)
is returned.
*/
MimeType MimeDatabase::mimeTypeForData(const QByteArray &data) const
{
QMutexLocker locker(&d->mutex);
int accuracy = 0;
return d->findByData(data, &accuracy);
}
/*!
Returns a MIME type for the data in \a device.
A valid MIME type is always returned. If the data in \a device doesn't match any
known MIME type data, the default MIME type (application/octet-stream)
is returned.
*/
MimeType MimeDatabase::mimeTypeForData(QIODevice *device) const
{
QMutexLocker locker(&d->mutex);
int accuracy = 0;
const bool openedByUs = !device->isOpen() && device->open(QIODevice::ReadOnly);
if (device->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 = device->peek(16384);
const MimeType result = d->findByData(data, &accuracy);
if (openedByUs)
device->close();
return result;
}
return d->mimeTypeForName(d->defaultMimeType());
}
/*!
Returns a MIME type for \a url.
If the URL is a local file, this calls mimeTypeForFile.
Otherwise the matching is done based on the file name only,
except for schemes where file names don't mean much, like HTTP.
This method always returns the default mimetype for HTTP URLs,
use QNetworkAccessManager to handle HTTP URLs properly.
A valid MIME type is always returned. If \a url doesn't match any
known MIME type data, the default MIME type (application/octet-stream)
is returned.
*/
MimeType MimeDatabase::mimeTypeForUrl(const QUrl &url) const
{
if (url.isLocalFile())
return mimeTypeForFile(url.toLocalFile());
const QString scheme = url.scheme();
if (scheme.startsWith(QLatin1String("http")))
return mimeTypeForName(d->defaultMimeType());
return mimeTypeForFile(url.path());
}
/*!
Returns a MIME type for the given \a fileName and \a device data.
This overload can be useful when the file is remote, and we started to
download some of its data in a device. This allows to do full MIME type
matching for remote files as well.
If the device is not open, it will be opened by this function, and closed
after the MIME type detection is completed.
A valid MIME type is always returned. If \a device data doesn't match any
known MIME type data, the default MIME type (application/octet-stream)
is returned.
This method looks at both the file name and the file contents,
if necessary. The file extension has priority over the contents,
but the contents will be used if the file extension is unknown, or
matches multiple MIME types.
*/
MimeType MimeDatabase::mimeTypeForFileNameAndData(const QString &fileName, QIODevice *device) const
{
int accuracy = 0;
const MimeType result = d->mimeTypeForFileNameAndData(fileName, device, &accuracy);
return result;
}
/*!
Returns a MIME type for the given \a fileName and device \a data.
This overload can be useful when the file is remote, and we started to
download some of its data. This allows to do full MIME type matching for
remote files as well.
A valid MIME type is always returned. If \a data doesn't match any
known MIME type data, the default MIME type (application/octet-stream)
is returned.
This method looks at both the file name and the file contents,
if necessary. The file extension has priority over the contents,
but the contents will be used if the file extension is unknown, or
matches multiple MIME types.
*/
MimeType MimeDatabase::mimeTypeForFileNameAndData(const QString &fileName, const QByteArray &data) const
{
QBuffer buffer(const_cast<QByteArray *>(&data));
buffer.open(QIODevice::ReadOnly);
int accuracy = 0;
return d->mimeTypeForFileNameAndData(fileName, &buffer, &accuracy);
}
/*!
Returns the list of all available MIME types.
This can be useful for showing all MIME types to the user, for instance
in a MIME type editor. Do not use unless really necessary in other cases
though, prefer using the \l {mimeTypeForData()}{mimeTypeForXxx()} methods for performance reasons.
*/
QList<MimeType> MimeDatabase::allMimeTypes() const
{
QMutexLocker locker(&d->mutex);
return d->allMimeTypes();
}
/*!
\enum MimeDatabase::MatchMode
This enum specifies how matching a file to a MIME type is performed.
\value MatchDefault Both the file name and content are used to look for a match
\value MatchExtension Only the file name is used to look for a match
\value MatchContent The file content is used to look for a match
*/

View File

@@ -1,57 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR LGPL-3.0
#pragma once
#include "mimetype.h"
QT_BEGIN_NAMESPACE
class QFileInfo;
class QIODevice;
class QUrl;
QT_END_NAMESPACE
namespace Utils {
class MimeDatabase
{
Q_DISABLE_COPY(MimeDatabase)
public:
MimeDatabase();
~MimeDatabase();
MimeType mimeTypeForName(const QString &nameOrAlias) const;
enum MatchMode { MatchDefault = 0x0, MatchExtension = 0x1, MatchContent = 0x2 };
MimeType mimeTypeForFile(const QString &fileName, MatchMode mode = MatchDefault) const;
MimeType mimeTypeForFile(const QFileInfo &fileInfo, MatchMode mode = MatchDefault) const;
QList<MimeType> mimeTypesForFileName(const QString &fileName) const;
MimeType mimeTypeForData(const QByteArray &data) const;
MimeType mimeTypeForData(QIODevice *device) const;
MimeType mimeTypeForUrl(const QUrl &url) const;
MimeType mimeTypeForFileNameAndData(const QString &fileName, QIODevice *device) const;
MimeType mimeTypeForFileNameAndData(const QString &fileName, const QByteArray &data) const;
QString suffixForFileName(const QString &fileName) const;
QList<MimeType> allMimeTypes() const;
// For debugging purposes.
enum StartupPhase {
BeforeInitialize,
PluginsLoading,
PluginsInitializing, // Register up to here.
PluginsDelayedInitializing, // Use from here on.
UpAndRunning
};
static void setStartupPhase(StartupPhase);
private:
Internal::MimeDatabasePrivate *d;
};
} // Utils

View File

@@ -1,74 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR LGPL-3.0
#pragma once
//
// W A R N I N G
// -------------
//
// This file is mostly copied from Qt code and should not be touched
// unless really needed.
//
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/qhash.h>
#include <QtCore/qmutex.h>
QT_BEGIN_NAMESPACE
class QIODevice;
QT_END_NAMESPACE
#include "mimetype.h"
#include "mimetype_p.h"
#include "mimeglobpattern_p.h"
namespace Utils {
namespace Internal {
class MimeProviderBase;
class MimeDatabasePrivate
{
public:
Q_DISABLE_COPY(MimeDatabasePrivate)
MimeDatabasePrivate();
~MimeDatabasePrivate();
static MimeDatabasePrivate *instance();
MimeProviderBase *provider();
void setProvider(MimeProviderBase *theProvider);
inline QString defaultMimeType() const { return m_defaultMimeType; }
bool inherits(const QString &mime, const QString &parent);
QList<MimeType> allMimeTypes();
MimeType mimeTypeForName(const QString &nameOrAlias);
MimeType mimeTypeForFileNameAndData(const QString &fileName, QIODevice *device, int *priorityPtr);
MimeType findByData(const QByteArray &data, int *priorityPtr);
QStringList mimeTypeForFileName(const QString &fileName, QString *foundSuffix = nullptr);
mutable MimeProviderBase *m_provider;
const QString m_defaultMimeType;
QMutex mutex;
int m_startupPhase = 0;
};
} // Internal
} // Utils

View File

@@ -1,241 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR LGPL-3.0
#include "mimeglobpattern_p.h"
#include <QRegularExpression>
#include <QStringList>
#include <QDebug>
using namespace Utils;
using namespace Utils::Internal;
/*!
\internal
\class MimeGlobMatchResult
\inmodule QtCore
\brief The MimeGlobMatchResult class accumulates results from glob matching.
Handles glob weights, and preferring longer matches over shorter matches.
*/
void MimeGlobMatchResult::addMatch(const QString &mimeType, int weight, const QString &pattern)
{
// Is this a lower-weight pattern than the last match? Skip this match then.
if (weight < m_weight)
return;
bool replace = weight > m_weight;
if (!replace) {
// Compare the length of the match
if (pattern.length() < m_matchingPatternLength)
return; // too short, ignore
else if (pattern.length() > m_matchingPatternLength) {
// longer: clear any previous match (like *.bz2, when pattern is *.tar.bz2)
replace = true;
}
}
if (replace) {
m_matchingMimeTypes.clear();
// remember the new "longer" length
m_matchingPatternLength = pattern.length();
m_weight = weight;
}
if (!m_matchingMimeTypes.contains(mimeType)) {
m_matchingMimeTypes.append(mimeType);
if (pattern.startsWith(QLatin1String("*.")))
m_foundSuffix = pattern.mid(2);
}
}
MimeGlobPattern::PatternType MimeGlobPattern::detectPatternType(const QString &pattern) const
{
const int patternLength = pattern.length();
if (!patternLength)
return OtherPattern;
const bool starCount = pattern.count(QLatin1Char('*')) == 1;
const bool hasSquareBracket = pattern.indexOf(QLatin1Char('[')) != -1;
const bool hasQuestionMark = pattern.indexOf(QLatin1Char('?')) != -1;
if (!hasSquareBracket && !hasQuestionMark) {
if (starCount == 1) {
// Patterns like "*~", "*.extension"
if (pattern.at(0) == QLatin1Char('*'))
return SuffixPattern;
// Patterns like "README*" (well this is currently the only one like that...)
if (pattern.at(patternLength - 1) == QLatin1Char('*'))
return PrefixPattern;
}
// Names without any wildcards like "README"
if (starCount == 0)
return LiteralPattern;
}
if (pattern == QLatin1String("[0-9][0-9][0-9].vdr"))
return VdrPattern;
if (pattern == QLatin1String("*.anim[1-9j]"))
return AnimPattern;
return OtherPattern;
}
/*!
\internal
\class MimeGlobPattern
\inmodule QtCore
\brief The MimeGlobPattern class contains the glob pattern for file names for MIME type matching.
\sa MimeType, MimeDatabase, MimeMagicRuleMatcher, MimeMagicRule
*/
bool MimeGlobPattern::matchFileName(const QString &inputFileName) const
{
// "Applications MUST match globs case-insensitively, except when the case-sensitive
// attribute is set to true."
// The constructor takes care of putting case-insensitive patterns in lowercase.
const QString fileName = m_caseSensitivity == Qt::CaseInsensitive
? inputFileName.toLower() : inputFileName;
const int patternLength = m_pattern.length();
if (!patternLength)
return false;
const int fileNameLength = fileName.length();
switch (m_patternType) {
case SuffixPattern: {
if (fileNameLength + 1 < patternLength)
return false;
const QChar *c1 = m_pattern.unicode() + patternLength - 1;
const QChar *c2 = fileName.unicode() + fileNameLength - 1;
int cnt = 1;
while (cnt < patternLength && *c1-- == *c2--)
++cnt;
return cnt == patternLength;
}
case PrefixPattern: {
if (fileNameLength + 1 < patternLength)
return false;
const QChar *c1 = m_pattern.unicode();
const QChar *c2 = fileName.unicode();
int cnt = 1;
while (cnt < patternLength && *c1++ == *c2++)
++cnt;
return cnt == patternLength;
}
case LiteralPattern:
return (m_pattern == fileName);
case VdrPattern: // "[0-9][0-9][0-9].vdr" case
return fileNameLength == 7
&& fileName.at(0).isDigit() && fileName.at(1).isDigit() && fileName.at(2).isDigit()
&& QStringView{fileName}.mid(3, 4) == QLatin1String(".vdr");
case AnimPattern: { // "*.anim[1-9j]" case
if (fileNameLength < 6)
return false;
const QChar lastChar = fileName.at(fileNameLength - 1);
const bool lastCharOK = (lastChar.isDigit() && lastChar != QLatin1Char('0'))
|| lastChar == QLatin1Char('j');
return lastCharOK && QStringView{fileName}.mid(fileNameLength - 6, 5) == QLatin1String(".anim");
}
case OtherPattern:
// Other fallback patterns: slow but correct method
const QRegularExpression rx(QRegularExpression::anchoredPattern(
QRegularExpression::wildcardToRegularExpression(m_pattern)));
return rx.match(fileName).hasMatch();
}
return false;
}
static bool isFastPattern(const QString &pattern)
{
// starts with "*.", has no other '*' and no other '.'
return pattern.lastIndexOf(QLatin1Char('*')) == 0
&& pattern.lastIndexOf(QLatin1Char('.')) == 1
// and contains no other special character
&& !pattern.contains(QLatin1Char('?'))
&& !pattern.contains(QLatin1Char('['))
;
}
void MimeAllGlobPatterns::addGlob(const MimeGlobPattern &glob)
{
const QString &pattern = glob.pattern();
Q_ASSERT(!pattern.isEmpty());
// Store each patterns into either m_fastPatternDict (*.txt, *.html etc. with default weight 50)
// or for the rest, like core.*, *.tar.bz2, *~, into highWeightPatternOffset (>50)
// or lowWeightPatternOffset (<=50)
if (glob.weight() == 50 && isFastPattern(pattern) && !glob.isCaseSensitive()) {
// The bulk of the patterns is *.foo with weight 50 --> those go into the fast patterns hash.
const QString extension = pattern.mid(2).toLower();
QStringList &patterns = m_fastPatterns[extension]; // find or create
if (!patterns.contains(glob.mimeType()))
patterns.append(glob.mimeType());
} else {
if (glob.weight() > 50) {
if (!m_highWeightGlobs.hasPattern(glob.mimeType(), glob.pattern()))
m_highWeightGlobs.append(glob);
} else {
if (!m_lowWeightGlobs.hasPattern(glob.mimeType(), glob.pattern()))
m_lowWeightGlobs.append(glob);
}
}
}
void MimeAllGlobPatterns::removeMimeType(const QString &mimeType)
{
for (QStringList &x : m_fastPatterns)
x.removeAll(mimeType);
m_highWeightGlobs.removeMimeType(mimeType);
m_lowWeightGlobs.removeMimeType(mimeType);
}
void MimeGlobPatternList::match(MimeGlobMatchResult &result,
const QString &fileName) const
{
for (const MimeGlobPattern &glob : *this) {
if (glob.matchFileName(fileName))
result.addMatch(glob.mimeType(), glob.weight(), glob.pattern());
}
}
QStringList MimeAllGlobPatterns::matchingGlobs(const QString &fileName, QString *foundSuffix) const
{
// First try the high weight matches (>50), if any.
MimeGlobMatchResult result;
m_highWeightGlobs.match(result, fileName);
if (result.m_matchingMimeTypes.isEmpty()) {
// Now use the "fast patterns" dict, for simple *.foo patterns with weight 50
// (which is most of them, so this optimization is definitely worth it)
const int lastDot = fileName.lastIndexOf(QLatin1Char('.'));
if (lastDot != -1) { // if no '.', skip the extension lookup
const int ext_len = fileName.length() - lastDot - 1;
const QString simpleExtension = fileName.right(ext_len).toLower();
// (toLower because fast patterns are always case-insensitive and saved as lowercase)
const QStringList matchingMimeTypes = m_fastPatterns.value(simpleExtension);
for (const QString &mime : matchingMimeTypes)
result.addMatch(mime, 50, QLatin1String("*.") + simpleExtension);
// 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.
}
// Finally, try the low weight matches (<=50)
m_lowWeightGlobs.match(result, fileName);
}
if (foundSuffix)
*foundSuffix = result.m_foundSuffix;
return result.m_matchingMimeTypes;
}
void MimeAllGlobPatterns::clear()
{
m_fastPatterns.clear();
m_highWeightGlobs.clear();
m_lowWeightGlobs.clear();
}

View File

@@ -1,135 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR LGPL-3.0
#pragma once
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/qstringlist.h>
#include <QtCore/qhash.h>
namespace Utils {
namespace Internal {
struct MimeGlobMatchResult
{
void addMatch(const QString &mimeType, int weight, const QString &pattern);
QStringList m_matchingMimeTypes;
int m_weight = 0;
int m_matchingPatternLength = 0;
QString m_foundSuffix;
};
class MimeGlobPattern
{
public:
static const unsigned MaxWeight = 100;
static const unsigned DefaultWeight = 50;
static const unsigned MinWeight = 1;
explicit MimeGlobPattern(const QString &thePattern, const QString &theMimeType,
unsigned theWeight = DefaultWeight,
Qt::CaseSensitivity s = Qt::CaseInsensitive) :
m_pattern(s == Qt::CaseInsensitive ? thePattern.toLower() : thePattern),
m_mimeType(theMimeType),
m_weight(theWeight),
m_caseSensitivity(s),
m_patternType(detectPatternType(m_pattern))
{
}
void swap(MimeGlobPattern &other) noexcept
{
qSwap(m_pattern, other.m_pattern);
qSwap(m_mimeType, other.m_mimeType);
qSwap(m_weight, other.m_weight);
qSwap(m_caseSensitivity, other.m_caseSensitivity);
qSwap(m_patternType, other.m_patternType);
}
bool matchFileName(const QString &inputFileName) const;
inline const QString &pattern() const { return m_pattern; }
inline unsigned weight() const { return m_weight; }
inline const QString &mimeType() const { return m_mimeType; }
inline bool isCaseSensitive() const { return m_caseSensitivity == Qt::CaseSensitive; }
private:
enum PatternType {
SuffixPattern,
PrefixPattern,
LiteralPattern,
VdrPattern, // special handling for "[0-9][0-9][0-9].vdr" pattern
AnimPattern, // special handling for "*.anim[1-9j]" pattern
OtherPattern
};
PatternType detectPatternType(const QString &pattern) const;
QString m_pattern;
QString m_mimeType;
int m_weight;
Qt::CaseSensitivity m_caseSensitivity;
PatternType m_patternType;
};
class MimeGlobPatternList : public QList<MimeGlobPattern>
{
public:
bool hasPattern(const QString &mimeType, const QString &pattern) const
{
const_iterator it = begin();
const const_iterator myend = end();
for (; it != myend; ++it)
if ((*it).pattern() == pattern && (*it).mimeType() == mimeType)
return true;
return false;
}
/*!
"noglobs" is very rare occurrence, so it's ok if it's slow
*/
void removeMimeType(const QString &mimeType)
{
auto isMimeTypeEqual = [&mimeType](const MimeGlobPattern &pattern) {
return pattern.mimeType() == mimeType;
};
erase(std::remove_if(begin(), end(), isMimeTypeEqual), end());
}
void match(MimeGlobMatchResult &result, const QString &fileName) const;
};
/*!
Result of the globs parsing, as data structures ready for efficient MIME type matching.
This contains:
1) a map of fast regular patterns (e.g. *.txt is stored as "txt" in a qhash's key)
2) a linear list of high-weight globs
3) a linear list of low-weight globs
*/
class MimeAllGlobPatterns
{
public:
typedef QHash<QString, QStringList> PatternsMap; // MIME type -> patterns
void addGlob(const MimeGlobPattern &glob);
void removeMimeType(const QString &mimeType);
QStringList matchingGlobs(const QString &fileName, QString *foundSuffix) const;
void clear();
PatternsMap m_fastPatterns; // example: "doc" -> "application/msword", "text/plain"
MimeGlobPatternList m_highWeightGlobs;
MimeGlobPatternList m_lowWeightGlobs; // <= 50, including the non-fast 50 patterns
};
} // Internal
} // Utils

View File

@@ -1,403 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR LGPL-3.0
#include "mimemagicrule_p.h"
#include <QtCore/QList>
#include <QtCore/QRegularExpression>
#include <QtCore/QDebug>
#include <qendian.h>
using namespace Utils;
using namespace Utils::Internal;
// in the same order as Type!
static const char magicRuleTypes_string[] =
"invalid\0"
"string\0"
"regexp\0"
"host16\0"
"host32\0"
"big16\0"
"big32\0"
"little16\0"
"little32\0"
"byte\0"
"\0";
static const int magicRuleTypes_indices[] = {
0, 8, 15, 22, 29, 36, 42, 48, 57, 66, 71, 0
};
MimeMagicRule::Type MimeMagicRule::type(const QByteArray &theTypeName)
{
for (int i = String; i <= Byte; ++i) {
if (theTypeName == magicRuleTypes_string + magicRuleTypes_indices[i])
return Type(i);
}
return Invalid;
}
QByteArray MimeMagicRule::typeName(MimeMagicRule::Type theType)
{
return magicRuleTypes_string + magicRuleTypes_indices[theType];
}
namespace Utils {
namespace Internal {
class MimeMagicRulePrivate
{
public:
bool operator==(const MimeMagicRulePrivate &other) const;
MimeMagicRule::Type type;
QByteArray value;
int startPos;
int endPos;
QByteArray mask;
QRegularExpression regexp;
QByteArray pattern;
quint32 number;
quint32 numberMask;
using MatchFunction = bool (*)(const MimeMagicRulePrivate*, const QByteArray&);
MatchFunction matchFunction;
};
bool MimeMagicRulePrivate::operator==(const MimeMagicRulePrivate &other) const
{
return type == other.type &&
value == other.value &&
startPos == other.startPos &&
endPos == other.endPos &&
mask == other.mask &&
pattern == other.pattern &&
number == other.number &&
numberMask == other.numberMask &&
matchFunction == other.matchFunction;
}
} // Internal
} // Utils
// Used by both providers
bool MimeMagicRule::matchSubstring(const char *dataPtr, int dataSize, int rangeStart, int rangeLength,
int valueLength, const char *valueData, const char *mask)
{
// Size of searched data.
// Example: value="ABC", rangeLength=3 -> we need 3+3-1=5 bytes (ABCxx,xABCx,xxABC would match)
const int dataNeeded = qMin(rangeLength + valueLength - 1, dataSize - rangeStart);
if (!mask) {
// callgrind says QByteArray::indexOf is much slower, since our strings are typically too
// short for be worth Boyer-Moore matching (1 to 71 bytes, 11 bytes on average).
bool found = false;
for (int i = rangeStart; i < rangeStart + rangeLength; ++i) {
if (i + valueLength > dataSize)
break;
if (memcmp(valueData, dataPtr + i, valueLength) == 0) {
found = true;
break;
}
}
if (!found)
return false;
} else {
bool found = false;
const char *readDataBase = dataPtr + rangeStart;
// Example (continued from above):
// deviceSize is 4, so dataNeeded was max'ed to 4.
// maxStartPos = 4 - 3 + 1 = 2, and indeed
// we need to check for a match a positions 0 and 1 (ABCx and xABC).
const int maxStartPos = dataNeeded - valueLength + 1;
for (int i = 0; i < maxStartPos; ++i) {
const char *d = readDataBase + i;
bool valid = true;
for (int idx = 0; idx < valueLength; ++idx) {
if (((*d++) & mask[idx]) != (valueData[idx] & mask[idx])) {
valid = false;
break;
}
}
if (valid)
found = true;
}
if (!found)
return false;
}
//qDebug() << "Found" << value << "in" << searchedData;
return true;
}
static bool matchString(const MimeMagicRulePrivate *d, const QByteArray &data)
{
const int rangeLength = d->endPos - d->startPos + 1;
return MimeMagicRule::matchSubstring(data.constData(), data.size(), d->startPos, rangeLength, d->pattern.size(), d->pattern.constData(), d->mask.constData());
}
static bool matchRegExp(const MimeMagicRulePrivate *d, const QByteArray &data)
{
const QString str = QString::fromUtf8(data);
int length = d->endPos;
if (length == d->startPos)
length = -1; // from startPos to end of string
const QString subStr = str.left(length);
return d->regexp.match(subStr, d->startPos).hasMatch();
}
template <typename T>
static bool matchNumber(const MimeMagicRulePrivate *d, const QByteArray &data)
{
const T value(d->number);
const T mask(d->numberMask);
//qDebug() << "matchNumber" << "0x" << QString::number(d->number, 16) << "size" << sizeof(T);
//qDebug() << "mask" << QString::number(d->numberMask, 16);
const char *p = data.constData() + d->startPos;
const char *e = data.constData() + qMin(data.size() - int(sizeof(T)), d->endPos + 1);
for ( ; p <= e; ++p) {
if ((*reinterpret_cast<const T*>(p) & mask) == (value & mask))
return true;
}
return false;
}
static inline QByteArray makePattern(const QByteArray &value)
{
QByteArray pattern(value.size(), Qt::Uninitialized);
char *data = pattern.data();
const char *p = value.constData();
const char *e = p + value.size();
for ( ; p < e; ++p) {
if (*p == '\\' && ++p < e) {
if (*p == 'x') { // hex (\\xff)
char c = 0;
for (int i = 0; i < 2 && p + 1 < e; ++i) {
++p;
if (*p >= '0' && *p <= '9')
c = (c << 4) + *p - '0';
else if (*p >= 'a' && *p <= 'f')
c = (c << 4) + *p - 'a' + 10;
else if (*p >= 'A' && *p <= 'F')
c = (c << 4) + *p - 'A' + 10;
else
continue;
}
*data++ = c;
} else if (*p >= '0' && *p <= '7') { // oct (\\7, or \\77, or \\377)
char c = *p - '0';
if (p + 1 < e && p[1] >= '0' && p[1] <= '7') {
c = (c << 3) + *(++p) - '0';
if (p + 1 < e && p[1] >= '0' && p[1] <= '7' && p[-1] <= '3')
c = (c << 3) + *(++p) - '0';
}
*data++ = c;
} else if (*p == 'n') {
*data++ = '\n';
} else if (*p == 'r') {
*data++ = '\r';
} else { // escaped
*data++ = *p;
}
} else {
*data++ = *p;
}
}
pattern.truncate(data - pattern.data());
return pattern;
}
MimeMagicRule::MimeMagicRule(MimeMagicRule::Type theType,
const QByteArray &theValue,
int theStartPos,
int theEndPos,
const QByteArray &theMask,
QString *errorString) :
d(new MimeMagicRulePrivate)
{
d->type = theType;
d->value = theValue;
d->startPos = theStartPos;
d->endPos = theEndPos;
d->mask = theMask;
d->matchFunction = nullptr;
if (d->value.isEmpty()) {
d->type = Invalid;
if (errorString)
*errorString = QLatin1String("Invalid empty magic rule value");
return;
}
if (d->type >= Host16 && d->type <= Byte) {
bool ok;
d->number = d->value.toUInt(&ok, 0); // autodetect
if (!ok) {
d->type = Invalid;
if (errorString)
*errorString = QString::fromLatin1("Invalid magic rule value \"%1\"").arg(
QString::fromLatin1(d->value));
return;
}
d->numberMask = !d->mask.isEmpty() ? d->mask.toUInt(&ok, 0) : 0; // autodetect
}
switch (d->type) {
case String:
d->pattern = makePattern(d->value);
d->pattern.squeeze();
if (!d->mask.isEmpty()) {
if (d->mask.size() < 4 || !d->mask.startsWith("0x")) {
d->type = Invalid;
if (errorString)
*errorString = QString::fromLatin1("Invalid magic rule mask \"%1\"").arg(
QString::fromLatin1(d->mask));
return;
}
const QByteArray &tempMask = QByteArray::fromHex(QByteArray::fromRawData(
d->mask.constData() + 2, d->mask.size() - 2));
if (tempMask.size() != d->pattern.size()) {
d->type = Invalid;
if (errorString)
*errorString = QString::fromLatin1("Invalid magic rule mask size \"%1\"").arg(
QString::fromLatin1(d->mask));
return;
}
d->mask = tempMask;
} else {
d->mask.fill(char(-1), d->pattern.size());
}
d->mask.squeeze();
d->matchFunction = matchString;
break;
case RegExp:
d->regexp.setPatternOptions(QRegularExpression::MultilineOption
| QRegularExpression::DotMatchesEverythingOption
);
d->regexp.setPattern(QString::fromUtf8(d->value));
if (!d->regexp.isValid()) {
d->type = Invalid;
if (errorString)
*errorString = QString::fromLatin1("Invalid magic rule regexp value \"%1\"").arg(
QString::fromLatin1(d->value));
return;
}
d->matchFunction = matchRegExp;
break;
case Byte:
if (d->number <= quint8(-1)) {
if (d->numberMask == 0)
d->numberMask = quint8(-1);
d->matchFunction = matchNumber<quint8>;
}
break;
case Big16:
case Host16:
case Little16:
if (d->number <= quint16(-1)) {
d->number = d->type == Little16 ? qFromLittleEndian<quint16>(d->number) : qFromBigEndian<quint16>(d->number);
if (d->numberMask == 0)
d->numberMask = quint16(-1);
d->matchFunction = matchNumber<quint16>;
}
break;
case Big32:
case Host32:
case Little32:
if (d->number <= quint32(-1)) {
d->number = d->type == Little32 ? qFromLittleEndian<quint32>(d->number) : qFromBigEndian<quint32>(d->number);
if (d->numberMask == 0)
d->numberMask = quint32(-1);
d->matchFunction = matchNumber<quint32>;
}
break;
default:
break;
}
}
MimeMagicRule::MimeMagicRule(const MimeMagicRule &other)
: m_subMatches(other.m_subMatches)
, d(new MimeMagicRulePrivate(*other.d))
{
}
MimeMagicRule::~MimeMagicRule() = default;
MimeMagicRule &MimeMagicRule::operator=(const MimeMagicRule &other)
{
*d = *other.d;
m_subMatches = other.m_subMatches;
return *this;
}
bool MimeMagicRule::operator==(const MimeMagicRule &other) const
{
return (d == other.d || *d == *other.d) && m_subMatches == other.m_subMatches;
}
MimeMagicRule::Type MimeMagicRule::type() const
{
return d->type;
}
QByteArray MimeMagicRule::value() const
{
return d->value;
}
int MimeMagicRule::startPos() const
{
return d->startPos;
}
int MimeMagicRule::endPos() const
{
return d->endPos;
}
QByteArray MimeMagicRule::mask() const
{
QByteArray result = d->mask;
if (d->type == String) {
// restore '0x'
result = "0x" + result.toHex();
}
return result;
}
bool MimeMagicRule::isValid() const
{
return d->matchFunction;
}
bool MimeMagicRule::matches(const QByteArray &data) const
{
const bool ok = d->matchFunction && d->matchFunction(d.data(), data);
if (!ok)
return false;
// No submatch? Then we are done.
if (m_subMatches.isEmpty())
return true;
//qDebug() << "Checking" << m_subMatches.count() << "sub-rules";
// Check that one of the submatches matches too
for ( QList<MimeMagicRule>::const_iterator it = m_subMatches.begin(), end = m_subMatches.end() ;
it != end ; ++it ) {
if ((*it).matches(data)) {
// One of the hierarchies matched -> mimetype recognized.
return true;
}
}
return false;
}

View File

@@ -1,71 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR LGPL-3.0
#pragma once
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <utils/utils_global.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qscopedpointer.h>
#include <QtCore/qlist.h>
#include <QtCore/qmap.h>
namespace Utils {
class MimeType;
namespace Internal {
class MimeMagicRulePrivate;
}
class QTCREATOR_UTILS_EXPORT MimeMagicRule
{
public:
enum Type { Invalid = 0, String, RegExp, Host16, Host32, Big16, Big32, Little16, Little32, Byte };
MimeMagicRule(Type type, const QByteArray &value, int startPos, int endPos,
const QByteArray &mask = QByteArray(), QString *errorString = nullptr);
MimeMagicRule(const MimeMagicRule &other);
~MimeMagicRule();
MimeMagicRule &operator=(const MimeMagicRule &other);
bool operator==(const MimeMagicRule &other) const;
Type type() const;
QByteArray value() const;
int startPos() const;
int endPos() const;
QByteArray mask() const;
bool isValid() const;
bool matches(const QByteArray &data) const;
QList<MimeMagicRule> m_subMatches;
static Type type(const QByteArray &type);
static QByteArray typeName(Type type);
static bool matchSubstring(const char *dataPtr, int dataSize, int rangeStart, int rangeLength, int valueLength, const char *valueData, const char *mask);
private:
const QScopedPointer<Internal::MimeMagicRulePrivate> d;
};
} // Utils
QT_BEGIN_NAMESPACE
Q_DECLARE_TYPEINFO(Utils::MimeMagicRule, Q_MOVABLE_TYPE);
QT_END_NAMESPACE

View File

@@ -1,67 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR LGPL-3.0
#include "mimemagicrulematcher_p.h"
#include "mimetype_p.h"
using namespace Utils;
using namespace Utils::Internal;
/*!
\internal
\class MimeMagicRuleMatcher
\inmodule QtCore
\brief The MimeMagicRuleMatcher class checks a number of rules based on operator "or".
It is used for rules parsed from XML files.
\sa MimeType, MimeDatabase, MagicRule, MagicStringRule, MagicByteRule, GlobPattern
\sa MimeTypeParserBase, MimeTypeParser
*/
MimeMagicRuleMatcher::MimeMagicRuleMatcher(const QString &mime, unsigned thePriority) :
m_list(),
m_priority(thePriority),
m_mimetype(mime)
{
}
bool MimeMagicRuleMatcher::operator==(const MimeMagicRuleMatcher &other) const
{
return m_list == other.m_list &&
m_priority == other.m_priority;
}
void MimeMagicRuleMatcher::addRule(const MimeMagicRule &rule)
{
m_list.append(rule);
}
void MimeMagicRuleMatcher::addRules(const QList<MimeMagicRule> &rules)
{
m_list.append(rules);
}
QList<MimeMagicRule> MimeMagicRuleMatcher::magicRules() const
{
return m_list;
}
// Check for a match on contents of a file
bool MimeMagicRuleMatcher::matches(const QByteArray &data) const
{
for (const MimeMagicRule &magicRule : m_list) {
if (magicRule.matches(data))
return true;
}
return false;
}
// Return a priority value from 1..100
unsigned MimeMagicRuleMatcher::priority() const
{
return m_priority;
}

View File

@@ -1,51 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR LGPL-3.0
#pragma once
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "mimemagicrule_p.h"
#include <QtCore/qbytearray.h>
#include <QtCore/qlist.h>
#include <QtCore/qstring.h>
namespace Utils {
namespace Internal {
class MimeMagicRuleMatcher
{
public:
explicit MimeMagicRuleMatcher(const QString &mime, unsigned priority = 65535);
bool operator==(const MimeMagicRuleMatcher &other) const;
void addRule(const MimeMagicRule &rule);
void addRules(const QList<MimeMagicRule> &rules);
QList<MimeMagicRule> magicRules() const;
bool matches(const QByteArray &data) const;
unsigned priority() const;
QString mimetype() const { return m_mimetype; }
private:
QList<MimeMagicRule> m_list;
unsigned m_priority;
QString m_mimetype;
};
} // Internal
} // Utils

View File

@@ -1,871 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR LGPL-3.0
#include "mimeprovider_p.h"
#include "mimetypeparser_p.h"
#include <qstandardpaths.h>
#include "mimemagicrulematcher_p.h"
#include <QXmlStreamReader>
#include <QDir>
#include <QFile>
#include <QByteArrayMatcher>
#include <QDebug>
#include <QDateTime>
#include <QtEndian>
#include <QtGlobal>
using namespace Utils;
using namespace Utils::Internal;
static QString fallbackParent(const QString &mimeTypeName)
{
const QString myGroup = mimeTypeName.left(mimeTypeName.indexOf(QLatin1Char('/')));
// All text/* types are subclasses of text/plain.
if (myGroup == QLatin1String("text") && mimeTypeName != QLatin1String("text/plain"))
return QLatin1String("text/plain");
// All real-file mimetypes implicitly derive from application/octet-stream
if (myGroup != QLatin1String("inode") &&
// ignore non-file extensions
myGroup != QLatin1String("all") && myGroup != QLatin1String("fonts") && myGroup != QLatin1String("print") && myGroup != QLatin1String("uri")
&& mimeTypeName != QLatin1String("application/octet-stream")) {
return QLatin1String("application/octet-stream");
}
return QString();
}
MimeProviderBase::MimeProviderBase(MimeDatabasePrivate *db)
: m_db(db)
{
}
static int mime_secondsBetweenChecks = 5;
bool MimeProviderBase::shouldCheck()
{
const QDateTime now = QDateTime::currentDateTime();
if (m_lastCheck.isValid() && m_lastCheck.secsTo(now) < mime_secondsBetweenChecks)
return false;
m_lastCheck = now;
return true;
}
//MimeBinaryProvider::MimeBinaryProvider(MimeDatabasePrivate *db)
// : MimeProviderBase(db), m_mimetypeListLoaded(false)
//{
//}
//#if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY)
//#define QT_USE_MMAP
//#endif
//struct MimeBinaryProvider::CacheFile
//{
// CacheFile(const QString &fileName);
// ~CacheFile();
// bool isValid() const { return m_valid; }
// inline quint16 getUint16(int offset) const
// {
// return qFromBigEndian(*reinterpret_cast<quint16 *>(data + offset));
// }
// inline quint32 getUint32(int offset) const
// {
// return qFromBigEndian(*reinterpret_cast<quint32 *>(data + offset));
// }
// inline const char *getCharStar(int offset) const
// {
// return reinterpret_cast<const char *>(data + offset);
// }
// bool load();
// bool reload();
// QFile file;
// uchar *data;
// QDateTime m_mtime;
// bool m_valid;
//};
//MimeBinaryProvider::CacheFile::CacheFile(const QString &fileName)
// : file(fileName), m_valid(false)
//{
// load();
//}
//MimeBinaryProvider::CacheFile::~CacheFile()
//{
//}
//bool MimeBinaryProvider::CacheFile::load()
//{
// if (!file.open(QIODevice::ReadOnly))
// return false;
// data = file.map(0, file.size());
// if (data) {
// const int major = getUint16(0);
// const int minor = getUint16(2);
// m_valid = (major == 1 && minor >= 1 && minor <= 2);
// }
// m_mtime = QFileInfo(file).lastModified();
// return m_valid;
//}
//bool MimeBinaryProvider::CacheFile::reload()
//{
// //qDebug() << "reload!" << file->fileName();
// m_valid = false;
// if (file.isOpen()) {
// file.close();
// }
// data = 0;
// return load();
//}
//MimeBinaryProvider::CacheFile *MimeBinaryProvider::CacheFileList::findCacheFile(const QString &fileName) const
//{
// for (const_iterator it = begin(); it != end(); ++it) {
// if ((*it)->file.fileName() == fileName)
// return *it;
// }
// return 0;
//}
//MimeBinaryProvider::~MimeBinaryProvider()
//{
// qDeleteAll(m_cacheFiles);
//}
//// Position of the "list offsets" values, at the beginning of the mime.cache file
//enum {
// PosAliasListOffset = 4,
// PosParentListOffset = 8,
// PosLiteralListOffset = 12,
// PosReverseSuffixTreeOffset = 16,
// PosGlobListOffset = 20,
// PosMagicListOffset = 24,
// // PosNamespaceListOffset = 28,
// PosIconsListOffset = 32,
// PosGenericIconsListOffset = 36
//};
//bool MimeBinaryProvider::isValid()
//{
//#if defined(QT_USE_MMAP)
// if (!qEnvironmentVariableIsEmpty("QT_NO_MIME_CACHE"))
// return false;
// Q_ASSERT(m_cacheFiles.isEmpty()); // this method is only ever called once
// checkCache();
// if (m_cacheFiles.count() > 1)
// return true;
// if (m_cacheFiles.isEmpty())
// return false;
// // We found exactly one file; is it the user-modified mimes, or a system file?
// const QString foundFile = m_cacheFiles.first()->file.fileName();
// const QString localCacheFile = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/mime/mime.cache");
// return foundFile != localCacheFile;
//#else
// return false;
//#endif
//}
//bool MimeBinaryProvider::CacheFileList::checkCacheChanged()
//{
// bool somethingChanged = false;
// QMutableListIterator<CacheFile *> it(*this);
// while (it.hasNext()) {
// CacheFile *cacheFile = it.next();
// QFileInfo fileInfo(cacheFile->file);
// if (!fileInfo.exists()) { // This can't happen by just running update-mime-database. But the user could use rm -rf :-)
// delete cacheFile;
// it.remove();
// somethingChanged = true;
// } else if (fileInfo.lastModified() > cacheFile->m_mtime) {
// if (!cacheFile->reload()) {
// delete cacheFile;
// it.remove();
// }
// somethingChanged = true;
// }
// }
// return somethingChanged;
//}
//void MimeBinaryProvider::checkCache()
//{
// if (!shouldCheck())
// return;
// // First iterate over existing known cache files and check for uptodate
// if (m_cacheFiles.checkCacheChanged())
// m_mimetypeListLoaded = false;
// // Then check if new cache files appeared
// const QStringList cacheFileNames = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QLatin1String("mime/mime.cache"));
// if (cacheFileNames != m_cacheFileNames) {
// for (const QString &cacheFileName : cacheFileNames) {
// CacheFile *cacheFile = m_cacheFiles.findCacheFile(cacheFileName);
// if (!cacheFile) {
// //qDebug() << "new file:" << cacheFileName;
// cacheFile = new CacheFile(cacheFileName);
// if (cacheFile->isValid()) // verify version
// m_cacheFiles.append(cacheFile);
// else
// delete cacheFile;
// }
// }
// m_cacheFileNames = cacheFileNames;
// m_mimetypeListLoaded = false;
// }
//}
//static MimeType mimeTypeForNameUnchecked(const QString &name)
//{
// MimeTypePrivate data;
// data.name = name;
// // 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)
//{
// checkCache();
// if (!m_mimetypeListLoaded)
// loadMimeTypeList();
// if (!m_mimetypeNames.contains(name))
// return MimeType(); // unknown mimetype
// return mimeTypeForNameUnchecked(name);
//}
//QStringList MimeBinaryProvider::findByFileName(const QString &fileName, QString *foundSuffix)
//{
// checkCache();
// if (fileName.isEmpty())
// return QStringList();
// const QString lowerFileName = fileName.toLower();
// MimeGlobMatchResult result;
// // TODO this parses in the order (local, global). Check that it handles "NOGLOBS" correctly.
// for (CacheFile *cacheFile : std::as_const(m_cacheFiles)) {
// matchGlobList(result, cacheFile, cacheFile->getUint32(PosLiteralListOffset), fileName);
// matchGlobList(result, cacheFile, cacheFile->getUint32(PosGlobListOffset), fileName);
// const int reverseSuffixTreeOffset = cacheFile->getUint32(PosReverseSuffixTreeOffset);
// const int numRoots = cacheFile->getUint32(reverseSuffixTreeOffset);
// const int firstRootOffset = cacheFile->getUint32(reverseSuffixTreeOffset + 4);
// matchSuffixTree(result, cacheFile, numRoots, firstRootOffset, lowerFileName, fileName.length() - 1, false);
// if (result.m_matchingMimeTypes.isEmpty())
// matchSuffixTree(result, cacheFile, numRoots, firstRootOffset, fileName, fileName.length() - 1, true);
// }
// if (foundSuffix)
// *foundSuffix = result.m_foundSuffix;
// return result.m_matchingMimeTypes;
//}
//void MimeBinaryProvider::matchGlobList(MimeGlobMatchResult &result, CacheFile *cacheFile, int off, const QString &fileName)
//{
// const int numGlobs = cacheFile->getUint32(off);
// //qDebug() << "Loading" << numGlobs << "globs from" << cacheFile->file.fileName() << "at offset" << cacheFile->globListOffset;
// for (int i = 0; i < numGlobs; ++i) {
// const int globOffset = cacheFile->getUint32(off + 4 + 12 * i);
// const int mimeTypeOffset = cacheFile->getUint32(off + 4 + 12 * i + 4);
// const int flagsAndWeight = cacheFile->getUint32(off + 4 + 12 * i + 8);
// const int weight = flagsAndWeight & 0xff;
// const bool caseSensitive = flagsAndWeight & 0x100;
// const Qt::CaseSensitivity qtCaseSensitive = caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
// const QString pattern = QLatin1String(cacheFile->getCharStar(globOffset));
// const char *mimeType = cacheFile->getCharStar(mimeTypeOffset);
// //qDebug() << pattern << mimeType << weight << caseSensitive;
// MimeGlobPattern glob(pattern, QString() /*unused*/, weight, qtCaseSensitive);
// // TODO: this could be done faster for literals where a simple == would do.
// if (glob.matchFileName(fileName))
// result.addMatch(QLatin1String(mimeType), weight, pattern);
// }
//}
//bool MimeBinaryProvider::matchSuffixTree(MimeGlobMatchResult &result, MimeBinaryProvider::CacheFile *cacheFile, int numEntries, int firstOffset, const QString &fileName, int charPos, bool caseSensitiveCheck)
//{
// QChar fileChar = fileName[charPos];
// int min = 0;
// int max = numEntries - 1;
// while (min <= max) {
// const int mid = (min + max) / 2;
// const int off = firstOffset + 12 * mid;
// const QChar ch = cacheFile->getUint32(off);
// if (ch < fileChar)
// min = mid + 1;
// else if (ch > fileChar)
// max = mid - 1;
// else {
// --charPos;
// int numChildren = cacheFile->getUint32(off + 4);
// int childrenOffset = cacheFile->getUint32(off + 8);
// bool success = false;
// if (charPos > 0)
// success = matchSuffixTree(result, cacheFile, numChildren, childrenOffset, fileName, charPos, caseSensitiveCheck);
// if (!success) {
// for (int i = 0; i < numChildren; ++i) {
// const int childOff = childrenOffset + 12 * i;
// const int mch = cacheFile->getUint32(childOff);
// if (mch != 0)
// break;
// const int mimeTypeOffset = cacheFile->getUint32(childOff + 4);
// const char *mimeType = cacheFile->getCharStar(mimeTypeOffset);
// const int flagsAndWeight = cacheFile->getUint32(childOff + 8);
// const int weight = flagsAndWeight & 0xff;
// const bool caseSensitive = flagsAndWeight & 0x100;
// if (caseSensitiveCheck || !caseSensitive) {
// result.addMatch(QLatin1String(mimeType), weight, QLatin1Char('*') + fileName.mid(charPos+1));
// success = true;
// }
// }
// }
// return success;
// }
// }
// return false;
//}
//bool MimeBinaryProvider::matchMagicRule(MimeBinaryProvider::CacheFile *cacheFile, int numMatchlets, int firstOffset, const QByteArray &data)
//{
// const char *dataPtr = data.constData();
// const int dataSize = data.size();
// for (int matchlet = 0; matchlet < numMatchlets; ++matchlet) {
// const int off = firstOffset + matchlet * 32;
// const int rangeStart = cacheFile->getUint32(off);
// const int rangeLength = cacheFile->getUint32(off + 4);
// //const int wordSize = cacheFile->getUint32(off + 8);
// const int valueLength = cacheFile->getUint32(off + 12);
// const int valueOffset = cacheFile->getUint32(off + 16);
// const int maskOffset = cacheFile->getUint32(off + 20);
// const char *mask = maskOffset ? cacheFile->getCharStar(maskOffset) : NULL;
// if (!MimeMagicRule::matchSubstring(dataPtr, dataSize, rangeStart, rangeLength, valueLength, cacheFile->getCharStar(valueOffset), mask))
// continue;
// const int numChildren = cacheFile->getUint32(off + 24);
// const int firstChildOffset = cacheFile->getUint32(off + 28);
// if (numChildren == 0) // No submatch? Then we are done.
// return true;
// // Check that one of the submatches matches too
// if (matchMagicRule(cacheFile, numChildren, firstChildOffset, data))
// return true;
// }
// return false;
//}
//MimeType MimeBinaryProvider::findByMagic(const QByteArray &data, int *accuracyPtr)
//{
// checkCache();
// for (CacheFile *cacheFile : std::as_const(m_cacheFiles)) {
// const int magicListOffset = cacheFile->getUint32(PosMagicListOffset);
// const int numMatches = cacheFile->getUint32(magicListOffset);
// //const int maxExtent = cacheFile->getUint32(magicListOffset + 4);
// const int firstMatchOffset = cacheFile->getUint32(magicListOffset + 8);
// for (int i = 0; i < numMatches; ++i) {
// const int off = firstMatchOffset + i * 16;
// const int numMatchlets = cacheFile->getUint32(off + 8);
// const int firstMatchletOffset = cacheFile->getUint32(off + 12);
// if (matchMagicRule(cacheFile, numMatchlets, firstMatchletOffset, data)) {
// const int mimeTypeOffset = cacheFile->getUint32(off + 4);
// const char *mimeType = cacheFile->getCharStar(mimeTypeOffset);
// *accuracyPtr = cacheFile->getUint32(off);
// // 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?)
// return mimeTypeForNameUnchecked(QLatin1String(mimeType));
// }
// }
// }
// return MimeType();
//}
//QStringList MimeBinaryProvider::parents(const QString &mime)
//{
// checkCache();
// const QByteArray mimeStr = mime.toLatin1();
// QStringList result;
// for (CacheFile *cacheFile : std::as_const(m_cacheFiles)) {
// const int parentListOffset = cacheFile->getUint32(PosParentListOffset);
// const int numEntries = cacheFile->getUint32(parentListOffset);
// int begin = 0;
// int end = numEntries - 1;
// while (begin <= end) {
// const int medium = (begin + end) / 2;
// const int off = parentListOffset + 4 + 8 * medium;
// const int mimeOffset = cacheFile->getUint32(off);
// const char *aMime = cacheFile->getCharStar(mimeOffset);
// const int cmp = qstrcmp(aMime, mimeStr);
// if (cmp < 0) {
// begin = medium + 1;
// } else if (cmp > 0) {
// end = medium - 1;
// } else {
// const int parentsOffset = cacheFile->getUint32(off + 4);
// const int numParents = cacheFile->getUint32(parentsOffset);
// for (int i = 0; i < numParents; ++i) {
// const int parentOffset = cacheFile->getUint32(parentsOffset + 4 + 4 * i);
// const char *aParent = cacheFile->getCharStar(parentOffset);
// result.append(QString::fromLatin1(aParent));
// }
// break;
// }
// }
// }
// if (result.isEmpty()) {
// const QString parent = fallbackParent(mime);
// if (!parent.isEmpty())
// result.append(parent);
// }
// return result;
//}
//QString MimeBinaryProvider::resolveAlias(const QString &name)
//{
// checkCache();
// const QByteArray input = name.toLatin1();
// for (CacheFile *cacheFile : std::as_const(m_cacheFiles)) {
// const int aliasListOffset = cacheFile->getUint32(PosAliasListOffset);
// const int numEntries = cacheFile->getUint32(aliasListOffset);
// int begin = 0;
// int end = numEntries - 1;
// while (begin <= end) {
// const int medium = (begin + end) / 2;
// const int off = aliasListOffset + 4 + 8 * medium;
// const int aliasOffset = cacheFile->getUint32(off);
// const char *alias = cacheFile->getCharStar(aliasOffset);
// const int cmp = qstrcmp(alias, input);
// if (cmp < 0) {
// begin = medium + 1;
// } else if (cmp > 0) {
// end = medium - 1;
// } else {
// const int mimeOffset = cacheFile->getUint32(off + 4);
// const char *mimeType = cacheFile->getCharStar(mimeOffset);
// return QLatin1String(mimeType);
// }
// }
// }
// return name;
//}
//QStringList MimeBinaryProvider::listAliases(const QString &name)
//{
// checkCache();
// QStringList result;
// const QByteArray input = name.toLatin1();
// for (CacheFile *cacheFile : std::as_const(m_cacheFiles)) {
// const int aliasListOffset = cacheFile->getUint32(PosAliasListOffset);
// const int numEntries = cacheFile->getUint32(aliasListOffset);
// for (int pos = 0; pos < numEntries; ++pos) {
// const int off = aliasListOffset + 4 + 8 * pos;
// const int mimeOffset = cacheFile->getUint32(off + 4);
// const char *mimeType = cacheFile->getCharStar(mimeOffset);
// if (input == mimeType) {
// const int aliasOffset = cacheFile->getUint32(off);
// const char *alias = cacheFile->getCharStar(aliasOffset);
// result.append(QString::fromLatin1(alias));
// }
// }
// }
// return result;
//}
//void MimeBinaryProvider::loadMimeTypeList()
//{
// if (!m_mimetypeListLoaded) {
// m_mimetypeListLoaded = true;
// m_mimetypeNames.clear();
// // Unfortunately mime.cache doesn't have a full list of all mimetypes.
// // So we have to parse the plain-text files called "types".
// const QStringList typesFilenames = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QLatin1String("mime/types"));
// for (const QString &typeFilename : typesFilenames) {
// QFile file(typeFilename);
// if (file.open(QIODevice::ReadOnly)) {
// while (!file.atEnd()) {
// QByteArray line = file.readLine();
// line.chop(1);
// m_mimetypeNames.insert(QString::fromLatin1(line.constData(), line.size()));
// }
// }
// }
// }
//}
//QList<MimeType> MimeBinaryProvider::allMimeTypes()
//{
// QList<MimeType> result;
// loadMimeTypeList();
// for (QSet<QString>::const_iterator it = m_mimetypeNames.constBegin();
// it != m_mimetypeNames.constEnd(); ++it)
// result.append(mimeTypeForNameUnchecked(*it));
// return result;
//}
//void MimeBinaryProvider::loadMimeTypePrivate(MimeTypePrivate &data)
//{
//#ifdef QT_NO_XMLSTREAMREADER
// qWarning() << "Cannot load mime type since QXmlStreamReader is not available.";
// return;
//#else
// if (data.loaded)
// return;
// data.loaded = true;
// // load comment and globPatterns
// const QString file = data.name + QLatin1String(".xml");
// const QStringList mimeFiles = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QString::fromLatin1("mime/") + file);
// if (mimeFiles.isEmpty()) {
// // TODO: ask Thiago about this
// qWarning() << "No file found for" << file << ", even though the file appeared in a directory listing.";
// qWarning() << "Either it was just removed, or the directory doesn't have executable permission...";
// qWarning() << QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QLatin1String("mime"), QStandardPaths::LocateDirectory);
// return;
// }
// QString comment;
// QString mainPattern;
// const QString preferredLanguage = QLocale::system().name();
// QListIterator<QString> mimeFilesIter(mimeFiles);
// mimeFilesIter.toBack();
// while (mimeFilesIter.hasPrevious()) { // global first, then local.
// const QString fullPath = mimeFilesIter.previous();
// QFile qfile(fullPath);
// if (!qfile.open(QFile::ReadOnly))
// continue;
// QXmlStreamReader xml(&qfile);
// if (xml.readNextStartElement()) {
// if (xml.name() != QLatin1String("mime-type")) {
// continue;
// }
// const QString name = xml.attributes().value(QLatin1String("type")).toString();
// if (name.isEmpty())
// continue;
// if (name != data.name) {
// qWarning() << "Got name" << name << "in file" << file << "expected" << data.name;
// }
// while (xml.readNextStartElement()) {
// const QStringRef tag = xml.name();
// if (tag == QLatin1String("comment")) {
// QString lang = xml.attributes().value(QLatin1String("xml:lang")).toString();
// const QString text = xml.readElementText();
// if (lang.isEmpty()) {
// lang = QLatin1String("en_US");
// }
// data.localeComments.insert(lang, text);
// continue; // we called readElementText, so we're at the EndElement already.
// } else if (tag == QLatin1String("icon")) { // as written out by shared-mime-info >= 0.40
// data.iconName = xml.attributes().value(QLatin1String("name")).toString();
// } else if (tag == QLatin1String("glob-deleteall")) { // as written out by shared-mime-info >= 0.70
// data.globPatterns.clear();
// } else if (tag == QLatin1String("glob")) { // as written out by shared-mime-info >= 0.70
// const QString pattern = xml.attributes().value(QLatin1String("pattern")).toString();
// if (mainPattern.isEmpty() && pattern.startsWith(QLatin1Char('*'))) {
// mainPattern = pattern;
// }
// if (!data.globPatterns.contains(pattern))
// data.globPatterns.append(pattern);
// }
// xml.skipCurrentElement();
// }
// Q_ASSERT(xml.name() == QLatin1String("mime-type"));
// }
// }
// // Let's assume that shared-mime-info is at least version 0.70
// // Otherwise we would need 1) a version check, and 2) code for parsing patterns from the globs file.
//#if 1
// if (!mainPattern.isEmpty() && data.globPatterns.first() != mainPattern) {
// // ensure it's first in the list of patterns
// data.globPatterns.removeAll(mainPattern);
// data.globPatterns.prepend(mainPattern);
// }
//#else
// const bool globsInXml = sharedMimeInfoVersion() >= QT_VERSION_CHECK(0, 70, 0);
// if (globsInXml) {
// if (!mainPattern.isEmpty() && data.globPatterns.first() != mainPattern) {
// // ensure it's first in the list of patterns
// data.globPatterns.removeAll(mainPattern);
// data.globPatterns.prepend(mainPattern);
// }
// } else {
// // Fallback: get the patterns from the globs file
// // TODO: This would be the only way to support shared-mime-info < 0.70
// // But is this really worth the effort?
// }
//#endif
//#endif //QT_NO_XMLSTREAMREADER
//}
//// Binary search in the icons or generic-icons list
//QString MimeBinaryProvider::iconForMime(CacheFile *cacheFile, int posListOffset, const QByteArray &inputMime)
//{
// const int iconsListOffset = cacheFile->getUint32(posListOffset);
// const int numIcons = cacheFile->getUint32(iconsListOffset);
// int begin = 0;
// int end = numIcons - 1;
// while (begin <= end) {
// const int medium = (begin + end) / 2;
// const int off = iconsListOffset + 4 + 8 * medium;
// const int mimeOffset = cacheFile->getUint32(off);
// const char *mime = cacheFile->getCharStar(mimeOffset);
// const int cmp = qstrcmp(mime, inputMime);
// if (cmp < 0)
// begin = medium + 1;
// else if (cmp > 0)
// end = medium - 1;
// else {
// const int iconOffset = cacheFile->getUint32(off + 4);
// return QLatin1String(cacheFile->getCharStar(iconOffset));
// }
// }
// return QString();
//}
//void MimeBinaryProvider::loadIcon(MimeTypePrivate &data)
//{
// checkCache();
// const QByteArray inputMime = data.name.toLatin1();
// for (CacheFile *cacheFile : std::as_const(m_cacheFiles)) {
// const QString icon = iconForMime(cacheFile, PosIconsListOffset, inputMime);
// if (!icon.isEmpty()) {
// data.iconName = icon;
// return;
// }
// }
//}
//void MimeBinaryProvider::loadGenericIcon(MimeTypePrivate &data)
//{
// checkCache();
// const QByteArray inputMime = data.name.toLatin1();
// for (CacheFile *cacheFile : std::as_const(m_cacheFiles)) {
// const QString icon = iconForMime(cacheFile, PosGenericIconsListOffset, inputMime);
// if (!icon.isEmpty()) {
// data.genericIconName = icon;
// return;
// }
// }
//}
////
MimeXMLProvider::MimeXMLProvider(MimeDatabasePrivate *db)
: MimeProviderBase(db), m_loaded(false)
{
}
bool MimeXMLProvider::isValid()
{
return true;
}
MimeType MimeXMLProvider::mimeTypeForName(const QString &name)
{
ensureLoaded();
return m_nameMimeTypeMap.value(name);
}
QStringList MimeXMLProvider::findByFileName(const QString &fileName, QString *foundSuffix)
{
ensureLoaded();
const QStringList matchingMimeTypes = m_mimeTypeGlobs.matchingGlobs(fileName, foundSuffix);
return matchingMimeTypes;
}
MimeType MimeXMLProvider::findByMagic(const QByteArray &data, int *accuracyPtr)
{
ensureLoaded();
QString candidate;
for (const MimeMagicRuleMatcher &matcher : std::as_const(m_magicMatchers)) {
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> > result;
for (const MimeMagicRuleMatcher &matcher : std::as_const(m_magicMatchers)) {
if (mimeType.matchesName(matcher.mimetype()))
result[matcher.priority()].append(matcher.magicRules());
}
return result;
}
void MimeXMLProvider::setGlobPatternsForMimeType(const MimeType &mimeType, const QStringList &patterns)
{
// remove all previous globs
m_mimeTypeGlobs.removeMimeType(mimeType.name());
// add new patterns as case-insensitive default-weight patterns
for (const QString &pattern : patterns)
addGlobPattern(MimeGlobPattern(pattern, mimeType.name()));
mimeType.d->globPatterns = patterns;
}
void MimeXMLProvider::setMagicRulesForMimeType(const MimeType &mimeType, const QMap<int, QList<MimeMagicRule> > &rules)
{
// remove all previous rules
for (int i = 0; i < m_magicMatchers.size(); ++i) {
if (m_magicMatchers.at(i).mimetype() == mimeType.name())
m_magicMatchers.removeAt(i--);
}
// add new rules
for (auto it = rules.cbegin(); it != rules.cend(); ++it) {
MimeMagicRuleMatcher matcher(mimeType.name(), it.key()/*priority*/);
matcher.addRules(it.value());
addMagicMatcher(matcher);
}
}
void MimeXMLProvider::ensureLoaded()
{
if (!m_loaded /*|| shouldCheck()*/) {
m_loaded = true;
QStringList allFiles = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation,
QStringLiteral("mime/packages/freedesktop.org.xml"),
QStandardPaths::LocateFile);
if (allFiles.isEmpty()) {
// System freedsktop.org.xml file not found, use our bundled copy
const char freedesktopOrgXml[] = ":/utils/mimetypes/freedesktop.org.xml";
allFiles.prepend(QLatin1String(freedesktopOrgXml));
}
m_nameMimeTypeMap.clear();
m_aliases.clear();
m_parents.clear();
m_mimeTypeGlobs.clear();
m_magicMatchers.clear();
//qDebug() << "Loading" << m_allFiles;
// add custom mime types first, which override any default from freedesktop.org.xml
MimeTypeParser parser(*this);
for (auto it = m_additionalData.constBegin(), end = m_additionalData.constEnd(); it != end; ++it) {
QString errorMessage;
if (!parser.parse(it.value(), it.key(), &errorMessage)) {
qWarning("MimeDatabase: Error loading %s\n%s", qPrintable(it.key()),
qPrintable(errorMessage));
}
}
for (const QString &file : std::as_const(allFiles))
load(file);
}
}
void MimeXMLProvider::load(const QString &fileName)
{
QString errorMessage;
if (!load(fileName, &errorMessage))
qWarning("MimeDatabase: Error loading %s\n%s", qPrintable(fileName), qPrintable(errorMessage));
}
bool MimeXMLProvider::load(const QString &fileName, QString *errorMessage)
{
m_loaded = true;
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
if (errorMessage)
*errorMessage = QString::fromLatin1("Cannot open %1: %2").arg(fileName, file.errorString());
return false;
}
if (errorMessage)
errorMessage->clear();
const QByteArray content = file.readAll();
MimeTypeParser parser(*this);
return parser.parse(content, fileName, errorMessage);
}
void MimeXMLProvider::addGlobPattern(const MimeGlobPattern &glob)
{
m_mimeTypeGlobs.addGlob(glob);
}
void MimeXMLProvider::addMimeType(const MimeType &mt)
{
m_nameMimeTypeMap.insert(mt.name(), mt);
}
QStringList MimeXMLProvider::parents(const QString &mime)
{
ensureLoaded();
QStringList result = m_parents.value(mime);
if (result.isEmpty()) {
const QString parent = fallbackParent(mime);
if (!parent.isEmpty())
result.append(parent);
}
return result;
}
void MimeXMLProvider::addParent(const QString &child, const QString &parent)
{
m_parents[child].append(parent);
}
QStringList MimeXMLProvider::listAliases(const QString &name)
{
ensureLoaded();
// Iterate through the whole hash. This method is rarely used.
return m_aliases.keys(name);
}
QString MimeXMLProvider::resolveAlias(const QString &name)
{
ensureLoaded();
return m_aliases.value(name, name);
}
void MimeXMLProvider::addAlias(const QString &alias, const QString &name)
{
m_aliases.insert(alias, name);
}
QList<MimeType> MimeXMLProvider::allMimeTypes()
{
ensureLoaded();
return m_nameMimeTypeMap.values();
}
void MimeXMLProvider::addMagicMatcher(const MimeMagicRuleMatcher &matcher)
{
m_magicMatchers.append(matcher);
}
void MimeXMLProvider::addData(const QString &id, const QByteArray &data)
{
if (m_additionalData.contains(id))
qWarning("Overwriting data in mime database, id '%s'", qPrintable(id));
m_additionalData.insert(id, data);
m_loaded = false; // force reload to ensure correct load order for overridden mime types
}

View File

@@ -1,155 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR LGPL-3.0
#pragma once
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "mimedatabase_p.h"
#include "mimemagicrule_p.h"
#include <QtCore/qdatetime.h>
#include <QtCore/qset.h>
namespace Utils {
namespace Internal {
class MimeMagicRuleMatcher;
class MimeProviderBase
{
public:
MimeProviderBase(MimeDatabasePrivate *db);
virtual ~MimeProviderBase() {}
virtual bool isValid() = 0;
virtual MimeType mimeTypeForName(const QString &name) = 0;
virtual QStringList findByFileName(const QString &fileName, QString *foundSuffix) = 0;
virtual QStringList parents(const QString &mime) = 0;
virtual QString resolveAlias(const QString &name) = 0;
virtual QStringList listAliases(const QString &name) = 0;
virtual MimeType findByMagic(const QByteArray &data, int *accuracyPtr) = 0;
virtual QList<MimeType> allMimeTypes() = 0;
virtual void loadMimeTypePrivate(MimeTypePrivate &) {}
virtual void loadIcon(MimeTypePrivate &) {}
virtual void loadGenericIcon(MimeTypePrivate &) {}
// Qt Creator additions
virtual QMap<int, QList<MimeMagicRule> > magicRulesForMimeType(const MimeType &mimeType) = 0;
virtual void setGlobPatternsForMimeType(const MimeType &mimeType, const QStringList &patterns) = 0;
virtual void setMagicRulesForMimeType(const MimeType &mimeType, const QMap<int, QList<MimeMagicRule> > &rules) = 0;
MimeDatabasePrivate *m_db;
protected:
bool shouldCheck();
QDateTime m_lastCheck;
};
///*
// Parses the files 'mime.cache' and 'types' on demand
// */
//class MimeBinaryProvider : public MimeProviderBase
//{
//public:
// MimeBinaryProvider(MimeDatabasePrivate *db);
// virtual ~MimeBinaryProvider();
// virtual bool isValid();
// virtual MimeType mimeTypeForName(const QString &name);
// virtual QStringList findByFileName(const QString &fileName, QString *foundSuffix);
// virtual QStringList parents(const QString &mime);
// virtual QString resolveAlias(const QString &name);
// virtual QStringList listAliases(const QString &name);
// virtual MimeType findByMagic(const QByteArray &data, int *accuracyPtr);
// virtual QList<MimeType> allMimeTypes();
// virtual void loadMimeTypePrivate(MimeTypePrivate &);
// virtual void loadIcon(MimeTypePrivate &);
// virtual void loadGenericIcon(MimeTypePrivate &);
//private:
// struct CacheFile;
// void matchGlobList(MimeGlobMatchResult &result, CacheFile *cacheFile, int offset, const QString &fileName);
// bool matchSuffixTree(MimeGlobMatchResult &result, CacheFile *cacheFile, int numEntries, int firstOffset, const QString &fileName, int charPos, bool caseSensitiveCheck);
// bool matchMagicRule(CacheFile *cacheFile, int numMatchlets, int firstOffset, const QByteArray &data);
// QString iconForMime(CacheFile *cacheFile, int posListOffset, const QByteArray &inputMime);
// void loadMimeTypeList();
// void checkCache();
// class CacheFileList : public QList<CacheFile *>
// {
// public:
// CacheFile *findCacheFile(const QString &fileName) const;
// bool checkCacheChanged();
// };
// CacheFileList m_cacheFiles;
// QStringList m_cacheFileNames;
// QSet<QString> m_mimetypeNames;
// bool m_mimetypeListLoaded;
//};
/*
Parses the raw XML files (slower)
*/
class MimeXMLProvider : public MimeProviderBase
{
public:
MimeXMLProvider(MimeDatabasePrivate *db);
bool isValid() override;
MimeType mimeTypeForName(const QString &name) override;
QStringList findByFileName(const QString &fileName, QString *foundSuffix) override;
QStringList parents(const QString &mime) override;
QString resolveAlias(const QString &name) override;
QStringList listAliases(const QString &name) override;
MimeType findByMagic(const QByteArray &data, int *accuracyPtr) override;
QList<MimeType> allMimeTypes() override;
bool load(const QString &fileName, QString *errorMessage);
// Called by the mimetype xml parser
void addMimeType(const MimeType &mt);
void addGlobPattern(const MimeGlobPattern &glob);
void addParent(const QString &child, const QString &parent);
void addAlias(const QString &alias, const QString &name);
void addMagicMatcher(const MimeMagicRuleMatcher &matcher);
// Qt Creator additions
void addData(const QString &id, const QByteArray &data);
QMap<int, QList<MimeMagicRule> > magicRulesForMimeType(const MimeType &mimeType) override;
void setGlobPatternsForMimeType(const MimeType &mimeType, const QStringList &patterns) override;
void setMagicRulesForMimeType(const MimeType &mimeType, const QMap<int, QList<MimeMagicRule> > &rules) override;
private:
void ensureLoaded();
void load(const QString &fileName);
bool m_loaded;
typedef QHash<QString, MimeType> NameMimeTypeMap;
NameMimeTypeMap m_nameMimeTypeMap;
typedef QHash<QString, QString> AliasHash;
AliasHash m_aliases;
typedef QHash<QString, QStringList> ParentsHash;
ParentsHash m_parents;
MimeAllGlobPatterns m_mimeTypeGlobs;
QList<MimeMagicRuleMatcher> m_magicMatchers;
// Qt Creator additions
QHash<QString, QByteArray> m_additionalData; // id -> data
};
} // Internal
} // Utils

View File

@@ -1,423 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR LGPL-3.0
#include "mimetype.h"
#include "mimetype_p.h"
#include "mimedatabase_p.h"
#include "mimeprovider_p.h"
#include "mimeglobpattern_p.h"
#include <QtCore/QDebug>
#include <QtCore/QLocale>
#include <memory>
using namespace Utils;
using namespace Utils::Internal;
static QString suffixFromPattern(const QString &pattern)
{
// Not a simple suffix if it looks like: README or *. or *.* or *.JP*G or *.JP?
if (pattern.startsWith(QLatin1String("*.")) &&
pattern.length() > 2 &&
pattern.indexOf(QLatin1Char('*'), 2) < 0 && pattern.indexOf(QLatin1Char('?'), 2) < 0) {
return pattern.mid(2);
}
return QString();
}
MimeTypePrivate::MimeTypePrivate()
: loaded(false)
{}
MimeTypePrivate::MimeTypePrivate(const MimeType &other)
: name(other.d->name),
localeComments(other.d->localeComments),
genericIconName(other.d->genericIconName),
iconName(other.d->iconName),
globPatterns(other.d->globPatterns),
loaded(other.d->loaded)
{}
void MimeTypePrivate::clear()
{
name.clear();
localeComments.clear();
genericIconName.clear();
iconName.clear();
globPatterns.clear();
loaded = false;
}
void MimeTypePrivate::addGlobPattern(const QString &pattern)
{
globPatterns.append(pattern);
}
/*!
\class MimeType
\inmodule QtCreator
\ingroup shared
\brief The MimeType class describes types of file or data, represented by a MIME type string.
\since 5.0
For instance, a file named \c readme.txt has the MIME type \c text/plain.
The MIME type can be determined from the file name, or from the file
contents, or from both. MIME type determination can also be done on
buffers of data not coming from files.
Determining the MIME type of a file can be useful to make sure your
application supports it. It is also useful in file-manager-like applications
or widgets, in order to display an appropriate \l {MimeType::iconName}{icon} for the file, or even
the descriptive \l {MimeType::comment()}{comment} in detailed views.
To check if a file has the expected MIME type, you should use inherits()
rather than a simple string comparison based on the name(). This is because
MIME types can inherit from each other: for instance a C source file is
a specific type of plain text file, so \c text/x-csrc inherits \c text/plain.
*/
/*!
Constructs this MimeType object initialized with default property values that indicate an invalid MIME type.
*/
MimeType::MimeType() :
d(new MimeTypePrivate())
{
}
/*!
Constructs this MimeType object as a copy of \a other.
*/
MimeType::MimeType(const MimeType &other) = default;
/*!
Assigns the data of \a other to this MimeType object, and returns a reference to this object.
*/
MimeType &MimeType::operator=(const MimeType &other)
{
if (d != other.d)
d = other.d;
return *this;
}
/*!
\fn MimeType::MimeType(const Internal::MimeTypePrivate &dd)
\internal
*/
MimeType::MimeType(const MimeTypePrivate &dd) :
d(new MimeTypePrivate(dd))
{
}
/*!
Destroys the MimeType object, and releases the d pointer.
*/
MimeType::~MimeType() = default;
/*!
Returns \c true if \a other equals this MimeType object, otherwise returns \c false.
The name is the unique identifier for a MIME type, so two MIME types with
the same name are equal.
*/
bool MimeType::operator==(const MimeType &other) const
{
return d == other.d || d->name == other.d->name;
}
/*!
\fn bool MimeType::operator!=(const MimeType &other) const;
Returns \c true if \a other does not equal this MimeType object, otherwise returns \c false.
*/
/*!
\fn inline uint Utils::qHash(const MimeType &mime)
\internal
*/
/*!
Returns \c true if the MimeType object contains valid data, otherwise returns \c false.
A valid MIME type has a non-empty name().
The invalid MIME type is the default-constructed MimeType.
*/
bool MimeType::isValid() const
{
return !d->name.isEmpty();
}
/*!
Returns \c true if this MIME type is the default MIME type which
applies to all files: \c application/octet-stream.
*/
bool MimeType::isDefault() const
{
return d->name == MimeDatabasePrivate::instance()->defaultMimeType();
}
/*!
Returns the name of the MIME type.
*/
QString MimeType::name() const
{
return d->name;
}
/*!
Returns the description of the MIME type to be displayed on user interfaces.
The system language (QLocale::system().name()) is used to select the appropriate translation.
*/
QString MimeType::comment() const
{
MimeDatabasePrivate::instance()->provider()->loadMimeTypePrivate(*d);
QStringList languageList;
languageList << QLocale::system().name();
languageList << QLocale::system().uiLanguages();
for (const QString &language : std::as_const(languageList)) {
const QString lang = language == QLatin1String("C") ? QLatin1String("en_US") : language;
const QString comm = d->localeComments.value(lang);
if (!comm.isEmpty())
return comm;
const int pos = lang.indexOf(QLatin1Char('_'));
if (pos != -1) {
// "pt_BR" not found? try just "pt"
const QString shortLang = lang.left(pos);
const QString commShort = d->localeComments.value(shortLang);
if (!commShort.isEmpty())
return commShort;
}
}
// Use the mimetype name as fallback
return d->name;
}
/*!
Returns the file name of a generic icon that represents the MIME type.
This should be used if the icon returned by iconName() cannot be found on
the system. It is used for categories of similar types (like spreadsheets
or archives) that can use a common icon.
The freedesktop.org Icon Naming Specification lists a set of such icon names.
The icon name can be given to QIcon::fromTheme() in order to load the icon.
*/
QString MimeType::genericIconName() const
{
MimeDatabasePrivate::instance()->provider()->loadGenericIcon(*d);
if (d->genericIconName.isEmpty()) {
// From the spec:
// 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
// media type (e.g. "video" in "video/ogg") and appending "-x-generic"
// (i.e. "video-x-generic" in the previous example).
QString group = name();
const int slashindex = group.indexOf(QLatin1Char('/'));
if (slashindex != -1)
group = group.left(slashindex);
return group + QLatin1String("-x-generic");
}
return d->genericIconName;
}
/*!
Returns the file name of an icon image that represents the MIME type.
The icon name can be given to QIcon::fromTheme() in order to load the icon.
*/
QString MimeType::iconName() const
{
MimeDatabasePrivate::instance()->provider()->loadIcon(*d);
if (d->iconName.isEmpty()) {
// Make default icon name from the mimetype name
d->iconName = name();
const int slashindex = d->iconName.indexOf(QLatin1Char('/'));
if (slashindex != -1)
d->iconName[slashindex] = QLatin1Char('-');
}
return d->iconName;
}
/*!
Returns the list of glob matching patterns.
*/
QStringList MimeType::globPatterns() const
{
MimeDatabasePrivate::instance()->provider()->loadMimeTypePrivate(*d);
return d->globPatterns;
}
/*!
A type is a subclass of another type if any instance of the first type is
also an instance of the second. For example, all \c image/svg+xml files are
also \c text/xml, \c text/plain and \c application/octet-stream files.
Subclassing is about the format, rather than the category of the data.
For example, there is no \e {generic spreadsheet} class that all
spreadsheets inherit from.
Conversely, the parent MIME type of \c image/svg+xml is \c text/xml.
A MIME type can have multiple parents. For instance, \c application/x-perl
has two parents: \c application/x-executable and \c text/plain. This makes
it possible to both execute perl scripts, and to open them in text editors.
*/
QStringList MimeType::parentMimeTypes() const
{
return MimeDatabasePrivate::instance()->provider()->parents(d->name);
}
static void collectParentMimeTypes(const QString &mime, QStringList &allParents)
{
const QStringList parents = MimeDatabasePrivate::instance()->provider()->parents(mime);
for (const QString &parent : parents) {
// I would use QSet, but since order matters I better not
if (!allParents.contains(parent))
allParents.append(parent);
}
// We want a breadth-first search, so that the least-specific parent (octet-stream) is last
// This means iterating twice, unfortunately.
for (const QString &parent : parents)
collectParentMimeTypes(parent, allParents);
}
/*!
Returns all the parent MIME types of this type, direct and indirect.
This includes grandparents, and so on.
For instance, for \c image/svg+xml the list would be:
\c application/xml, \c text/plain, \c application/octet-stream.
\note The \c application/octet-stream type is the ultimate parent for all types
of files (but not directories).
*/
QStringList MimeType::allAncestors() const
{
QStringList allParents;
collectParentMimeTypes(d->name, allParents);
return allParents;
}
/*!
Returns the list of aliases of this MIME type.
For instance, for \c text/csv, the returned list would be:
\c text/x-csv, \c text/x-comma-separated-values.
\note All MimeType instances refer to proper MIME types,
never to aliases directly.
The order of the aliases in the list is undefined.
*/
QStringList MimeType::aliases() const
{
return MimeDatabasePrivate::instance()->provider()->listAliases(d->name);
}
/*!
Returns the known suffixes for the MIME type.
No leading dot is included, so for instance this would return
\c {"jpg", "jpeg"} for \c image/jpeg.
*/
QStringList MimeType::suffixes() const
{
MimeDatabasePrivate::instance()->provider()->loadMimeTypePrivate(*d);
QStringList result;
for (const QString &pattern : std::as_const(d->globPatterns)) {
const QString suffix = suffixFromPattern(pattern);
if (!suffix.isEmpty())
result.append(suffix);
}
return result;
}
/*!
Returns the preferred suffix for the MIME type.
No leading dot is included, so for instance this would return \c "pdf" for
\c application/pdf. The return value can be empty, for MIME types which do
not have any suffixes associated.
*/
QString MimeType::preferredSuffix() const
{
const QStringList suffixList = suffixes();
return suffixList.isEmpty() ? QString() : suffixList.at(0);
}
/*!
Returns a filter string usable for a file dialog.
*/
QString MimeType::filterString() const
{
MimeDatabasePrivate::instance()->provider()->loadMimeTypePrivate(*d);
QString filter;
if (!d->globPatterns.empty()) {
filter += comment() + QLatin1String(" (");
for (int i = 0; i < d->globPatterns.size(); ++i) {
if (i != 0)
filter += QLatin1Char(' ');
filter += d->globPatterns.at(i);
}
filter += QLatin1Char(')');
}
return filter;
}
/*!
Returns \c true if the name or alias of the MIME type matches
\a nameOrAlias.
*/
bool MimeType::matchesName(const QString &nameOrAlias) const
{
if (d->name == nameOrAlias)
return true;
return MimeDatabasePrivate::instance()->provider()->resolveAlias(nameOrAlias) == d->name;
}
/*!
Sets the preferred filename suffix for the MIME type to \a suffix.
*/
void MimeType::setPreferredSuffix(const QString &suffix)
{
MimeDatabasePrivate::instance()->provider()->loadMimeTypePrivate(*d);
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);
}
/*!
Returns \c true if this MIME type is \a mimeTypeName or inherits it,
or if \a mimeTypeName is an alias for this mimetype.
\sa parentMimeTypes()
*/
bool MimeType::inherits(const QString &mimeTypeName) const
{
if (d->name == mimeTypeName)
return true;
return MimeDatabasePrivate::instance()->inherits(d->name, mimeTypeName);
}
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug debug, const MimeType &mime)
{
QDebugStateSaver saver(debug);
if (!mime.isValid()) {
debug.nospace() << "MimeType(invalid)";
} else {
debug.nospace() << "MimeType(" << mime.name() << ")";
}
return debug;
}
#endif

View File

@@ -1,99 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR LGPL-3.0
#pragma once
#include <utils/utils_global.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
class QFileinfo;
QT_END_NAMESPACE
namespace Utils {
namespace Internal {
class MimeTypeParserBase;
class MimeTypeMapEntry;
class MimeDatabasePrivate;
class MimeXMLProvider;
class MimeBinaryProvider;
class MimeTypePrivate;
}
class QTCREATOR_UTILS_EXPORT MimeType
{
public:
MimeType();
MimeType(const MimeType &other);
MimeType &operator=(const MimeType &other);
//#ifdef Q_COMPILER_RVALUE_REFS
// MimeType &operator=(MimeType &&other)
// {
// qSwap(d, other.d);
// return *this;
// }
//#endif
// void swap(MimeType &other)
// {
// qSwap(d, other.d);
// }
explicit MimeType(const Internal::MimeTypePrivate &dd);
~MimeType();
bool operator==(const MimeType &other) const;
inline bool operator!=(const MimeType &other) const
{
return !operator==(other);
}
bool isValid() const;
bool isDefault() const;
QString name() const;
QString comment() const;
QString genericIconName() const;
QString iconName() const;
QStringList globPatterns() const;
QStringList parentMimeTypes() const;
QStringList allAncestors() const;
QStringList aliases() const;
QStringList suffixes() const;
QString preferredSuffix() const;
bool inherits(const QString &mimeTypeName) const;
QString filterString() const;
// Qt Creator additions
bool matchesName(const QString &nameOrAlias) const;
void setPreferredSuffix(const QString &suffix);
friend auto qHash(const MimeType &mime) { return qHash(mime.name()); }
protected:
friend class Internal::MimeTypeParserBase;
friend class Internal::MimeTypeMapEntry;
friend class Internal::MimeDatabasePrivate;
friend class Internal::MimeXMLProvider;
friend class Internal::MimeBinaryProvider;
friend class Internal::MimeTypePrivate;
QExplicitlySharedDataPointer<Internal::MimeTypePrivate> d;
};
} // Utils
//Q_DECLARE_SHARED(Utils::MimeType)
#ifndef QT_NO_DEBUG_STREAM
QT_BEGIN_NAMESPACE
class QDebug;
QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug debug, const Utils::MimeType &mime);
QT_END_NAMESPACE
#endif

View File

@@ -1,84 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR LGPL-3.0
#pragma once
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "mimetype.h"
#include <QtCore/qhash.h>
#include <QtCore/qstringlist.h>
namespace Utils {
namespace Internal {
class MimeTypePrivate : public QSharedData
{
public:
typedef QHash<QString, QString> LocaleHash;
MimeTypePrivate();
explicit MimeTypePrivate(const MimeType &other);
void clear();
void addGlobPattern(const QString &pattern);
QString name;
LocaleHash localeComments;
QString genericIconName;
QString iconName;
QStringList globPatterns;
bool loaded;
};
} // Internal
} // Utils
#define MIMETYPE_BUILDER \
QT_BEGIN_NAMESPACE \
static MimeType buildMimeType ( \
const QString &name, \
const QString &genericIconName, \
const QString &iconName, \
const QStringList &globPatterns \
) \
{ \
MimeTypePrivate qMimeTypeData; \
qMimeTypeData.name = name; \
qMimeTypeData.genericIconName = genericIconName; \
qMimeTypeData.iconName = iconName; \
qMimeTypeData.globPatterns = globPatterns; \
return MimeType(qMimeTypeData); \
} \
QT_END_NAMESPACE
#ifdef Q_COMPILER_RVALUE_REFS
#define MIMETYPE_BUILDER_FROM_RVALUE_REFS \
QT_BEGIN_NAMESPACE \
static MimeType buildMimeType ( \
QString &&name, \
QString &&genericIconName, \
QString &&iconName, \
QStringList &&globPatterns \
) \
{ \
MimeTypePrivate qMimeTypeData; \
qMimeTypeData.name = std::move(name); \
qMimeTypeData.genericIconName = std::move(genericIconName); \
qMimeTypeData.iconName = std::move(iconName); \
qMimeTypeData.globPatterns = std::move(globPatterns); \
return MimeType(qMimeTypeData); \
} \
QT_END_NAMESPACE
#endif

View File

@@ -1,325 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR LGPL-3.0
#include "mimetypeparser_p.h"
#include "mimetype_p.h"
#include "mimemagicrulematcher_p.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QPair>
#include <QtCore/QXmlStreamReader>
#include <QtCore/QXmlStreamWriter>
#include <QtCore/QStack>
using namespace Utils;
using namespace Utils::Internal;
// XML tags in MIME files
static const char mimeInfoTagC[] = "mime-info";
static const char mimeTypeTagC[] = "mime-type";
static const char mimeTypeAttributeC[] = "type";
static const char subClassTagC[] = "sub-class-of";
static const char commentTagC[] = "comment";
static const char genericIconTagC[] = "generic-icon";
static const char iconTagC[] = "icon";
static const char nameAttributeC[] = "name";
static const char globTagC[] = "glob";
static const char aliasTagC[] = "alias";
static const char patternAttributeC[] = "pattern";
static const char weightAttributeC[] = "weight";
static const char caseSensitiveAttributeC[] = "case-sensitive";
static const char localeAttributeC[] = "xml:lang";
static const char magicTagC[] = "magic";
static const char priorityAttributeC[] = "priority";
static const char matchTagC[] = "match";
static const char matchValueAttributeC[] = "value";
static const char matchTypeAttributeC[] = "type";
static const char matchOffsetAttributeC[] = "offset";
static const char matchMaskAttributeC[] = "mask";
/*!
\class MimeTypeParser
\inmodule QtCore
\internal
\brief The MimeTypeParser class parses MIME types, and builds a MIME database hierarchy by adding to MimeDatabasePrivate.
Populates MimeDataBase
\sa MimeDatabase, MimeMagicRuleMatcher, MagicRule, MagicStringRule, MagicByteRule, GlobPattern
\sa MimeTypeParser
*/
/*!
\class MimeTypeParserBase
\inmodule QtCore
\internal
\brief The MimeTypeParserBase class parses for a sequence of <mime-type> in a generic way.
Calls abstract handler function process for MimeType it finds.
\sa MimeDatabase, MimeMagicRuleMatcher, MagicRule, MagicStringRule, MagicByteRule, GlobPattern
\sa MimeTypeParser
*/
/*!
\fn virtual bool MimeTypeParserBase::process(const MimeType &t, QString *errorMessage) = 0;
Overwrite to process the sequence of parsed data
*/
MimeTypeParserBase::ParseState MimeTypeParserBase::nextState(ParseState currentState,
QStringView startElement)
{
switch (currentState) {
case ParseBeginning:
if (startElement == QLatin1String(mimeInfoTagC))
return ParseMimeInfo;
if (startElement == QLatin1String(mimeTypeTagC))
return ParseMimeType;
return ParseError;
case ParseMimeInfo:
return startElement == QLatin1String(mimeTypeTagC) ? ParseMimeType : ParseError;
case ParseMimeType:
case ParseComment:
case ParseGenericIcon:
case ParseIcon:
case ParseGlobPattern:
case ParseSubClass:
case ParseAlias:
case ParseOtherMimeTypeSubTag:
case ParseMagicMatchRule:
if (startElement == QLatin1String(mimeTypeTagC)) // Sequence of <mime-type>
return ParseMimeType;
if (startElement == QLatin1String(commentTagC ))
return ParseComment;
if (startElement == QLatin1String(genericIconTagC))
return ParseGenericIcon;
if (startElement == QLatin1String(iconTagC))
return ParseIcon;
if (startElement == QLatin1String(globTagC))
return ParseGlobPattern;
if (startElement == QLatin1String(subClassTagC))
return ParseSubClass;
if (startElement == QLatin1String(aliasTagC))
return ParseAlias;
if (startElement == QLatin1String(magicTagC))
return ParseMagic;
if (startElement == QLatin1String(matchTagC))
return ParseMagicMatchRule;
return ParseOtherMimeTypeSubTag;
case ParseMagic:
if (startElement == QLatin1String(matchTagC))
return ParseMagicMatchRule;
break;
case ParseError:
break;
}
return ParseError;
}
// Parse int number from an (attribute) string)
static bool parseNumber(const QString &n, int *target, QString *errorMessage)
{
bool ok;
*target = n.toInt(&ok);
if (!ok) {
if (errorMessage)
*errorMessage = QString::fromLatin1("Not a number '%1'.").arg(n);
return false;
}
return true;
}
// Evaluate a magic match rule like
// <match value="must be converted with BinHex" type="string" offset="11"/>
// <match value="0x9501" type="big16" offset="0:64"/>
#ifndef QT_NO_XMLSTREAMREADER
static bool createMagicMatchRule(const QXmlStreamAttributes &atts,
QString *errorMessage, MimeMagicRule *&rule)
{
const QString type = atts.value(QLatin1String(matchTypeAttributeC)).toString();
MimeMagicRule::Type magicType = MimeMagicRule::type(type.toLatin1());
if (magicType == MimeMagicRule::Invalid) {
qWarning("%s: match type %s is not supported.", Q_FUNC_INFO, type.toUtf8().constData());
return true;
}
const QString value = atts.value(QLatin1String(matchValueAttributeC)).toString();
// Parse for offset as "1" or "1:10"
int startPos, endPos;
const QString offsetS = atts.value(QLatin1String(matchOffsetAttributeC)).toString();
const int colonIndex = offsetS.indexOf(QLatin1Char(':'));
const QString startPosS = colonIndex == -1 ? offsetS : offsetS.mid(0, colonIndex);
const QString endPosS = colonIndex == -1 ? offsetS : offsetS.mid(colonIndex + 1);
if (!parseNumber(startPosS, &startPos, errorMessage) || !parseNumber(endPosS, &endPos, errorMessage))
return false;
const QString mask = atts.value(QLatin1String(matchMaskAttributeC)).toString();
MimeMagicRule *tempRule = new MimeMagicRule(magicType, value.toUtf8(), startPos, endPos,
mask.toLatin1(), errorMessage);
if (!tempRule->isValid()) {
delete tempRule;
return false;
}
rule = tempRule;
return true;
}
#endif
bool MimeTypeParserBase::parse(const QByteArray &content, const QString &fileName, QString *errorMessage)
{
#ifdef QT_NO_XMLSTREAMREADER
if (errorMessage)
*errorMessage = QString::fromLatin1("QXmlStreamReader is not available, cannot parse.");
return false;
#else
MimeTypePrivate data;
int priority = 50;
QStack<MimeMagicRule *> currentRules; // stack for the nesting of rules
QList<MimeMagicRule> rules; // toplevel rules
QXmlStreamReader reader(content);
ParseState ps = ParseBeginning;
QXmlStreamAttributes atts;
bool ignoreCurrentMimeType = false;
while (!reader.atEnd()) {
switch (reader.readNext()) {
case QXmlStreamReader::StartElement:
if (ignoreCurrentMimeType)
continue;
ps = nextState(ps, reader.name());
atts = reader.attributes();
switch (ps) {
case ParseMimeType: { // start parsing a MIME type name
const QString name = atts.value(QLatin1String(mimeTypeAttributeC)).toString();
if (name.isEmpty()) {
reader.raiseError(QString::fromLatin1("Missing '%1'-attribute").arg(QString::fromLatin1(mimeTypeAttributeC)));
} else {
if (mimeTypeExists(name))
ignoreCurrentMimeType = true;
else
data.name = name;
}
}
break;
case ParseGenericIcon:
data.genericIconName = atts.value(QLatin1String(nameAttributeC)).toString();
break;
case ParseIcon:
data.iconName = atts.value(QLatin1String(nameAttributeC)).toString();
break;
case ParseGlobPattern: {
const QString pattern = atts.value(QLatin1String(patternAttributeC)).toString();
unsigned weight = atts.value(QLatin1String(weightAttributeC)).toString().toInt();
const bool caseSensitive = atts.value(QLatin1String(caseSensitiveAttributeC)).toString() == QLatin1String("true");
if (weight == 0)
weight = MimeGlobPattern::DefaultWeight;
Q_ASSERT(!data.name.isEmpty());
const MimeGlobPattern glob(pattern, data.name, weight, caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
if (!process(glob, errorMessage)) // for actual glob matching
return false;
data.addGlobPattern(pattern); // just for MimeType::globPatterns()
}
break;
case ParseSubClass: {
const QString inheritsFrom = atts.value(QLatin1String(mimeTypeAttributeC)).toString();
if (!inheritsFrom.isEmpty())
processParent(data.name, inheritsFrom);
}
break;
case ParseComment: {
// comments have locale attributes. We want the default, English one
QString locale = atts.value(QLatin1String(localeAttributeC)).toString();
const QString comment = reader.readElementText();
if (locale.isEmpty())
locale = QString::fromLatin1("en_US");
data.localeComments.insert(locale, comment);
}
break;
case ParseAlias: {
const QString alias = atts.value(QLatin1String(mimeTypeAttributeC)).toString();
if (!alias.isEmpty())
processAlias(alias, data.name);
}
break;
case ParseMagic: {
priority = 50;
const QString priorityS = atts.value(QLatin1String(priorityAttributeC)).toString();
if (!priorityS.isEmpty()) {
if (!parseNumber(priorityS, &priority, errorMessage))
return false;
}
currentRules.clear();
//qDebug() << "MAGIC start for mimetype" << data.name;
}
break;
case ParseMagicMatchRule: {
MimeMagicRule *rule = nullptr;
if (!createMagicMatchRule(atts, errorMessage, rule))
return false;
QList<MimeMagicRule> *ruleList;
if (currentRules.isEmpty())
ruleList = &rules;
else // nest this rule into the proper parent
ruleList = &currentRules.top()->m_subMatches;
ruleList->append(*rule);
//qDebug() << " MATCH added. Stack size was" << currentRules.size();
currentRules.push(&ruleList->last());
delete rule;
break;
}
case ParseError:
reader.raiseError(QString::fromLatin1("Unexpected element <%1>").
arg(reader.name().toString()));
break;
default:
break;
}
break;
// continue switch QXmlStreamReader::Token...
case QXmlStreamReader::EndElement: // Finished element
{
const QStringView elementName = reader.name();
if (elementName == QLatin1String(mimeTypeTagC)) {
if (!ignoreCurrentMimeType) {
if (!process(MimeType(data), errorMessage))
return false;
}
ignoreCurrentMimeType = false;
data.clear();
} else if (!ignoreCurrentMimeType) {
if (elementName == QLatin1String(matchTagC)) {
// Closing a <match> tag, pop stack
currentRules.pop();
//qDebug() << " MATCH closed. Stack size is now" << currentRules.size();
} else if (elementName == QLatin1String(magicTagC)) {
//qDebug() << "MAGIC ended, we got" << rules.count() << "rules, with prio" << priority;
// Finished a <magic> sequence
MimeMagicRuleMatcher ruleMatcher(data.name, priority);
ruleMatcher.addRules(rules);
processMagicMatcher(ruleMatcher);
rules.clear();
}
}
break;
}
default:
break;
}
}
if (reader.hasError()) {
if (errorMessage)
*errorMessage = QString::fromLatin1("An error has been encountered at line %1 of %2: %3:").arg(reader.lineNumber()).arg(fileName, reader.errorString());
return false;
}
return true;
#endif //QT_NO_XMLSTREAMREADER
}

View File

@@ -1,91 +0,0 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR LGPL-3.0
#pragma once
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "mimedatabase_p.h"
#include "mimeprovider_p.h"
namespace Utils {
namespace Internal {
class MimeTypeParserBase
{
Q_DISABLE_COPY(MimeTypeParserBase)
public:
MimeTypeParserBase() {}
virtual ~MimeTypeParserBase() {}
bool parse(const QByteArray &content, const QString &fileName, QString *errorMessage);
protected:
virtual bool mimeTypeExists(const QString &mimeTypeName) = 0;
virtual bool process(const MimeType &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 processAlias(const QString &alias, const QString &name) = 0;
virtual void processMagicMatcher(const MimeMagicRuleMatcher &matcher) = 0;
private:
enum ParseState {
ParseBeginning,
ParseMimeInfo,
ParseMimeType,
ParseComment,
ParseGenericIcon,
ParseIcon,
ParseGlobPattern,
ParseSubClass,
ParseAlias,
ParseMagic,
ParseMagicMatchRule,
ParseOtherMimeTypeSubTag,
ParseError
};
static ParseState nextState(ParseState currentState, QStringView startElement);
};
class MimeTypeParser : public MimeTypeParserBase
{
public:
explicit MimeTypeParser(MimeXMLProvider &provider) : m_provider(provider) {}
protected:
inline bool mimeTypeExists(const QString &mimeTypeName) override
{ return m_provider.mimeTypeForName(mimeTypeName).isValid(); }
inline bool process(const MimeType &t, QString *) override
{ m_provider.addMimeType(t); return true; }
inline bool process(const MimeGlobPattern &glob, QString *) override
{ m_provider.addGlobPattern(glob); return true; }
inline void processParent(const QString &child, const QString &parent) override
{ m_provider.addParent(child, parent); }
inline void processAlias(const QString &alias, const QString &name) override
{ m_provider.addAlias(alias, name); }
inline void processMagicMatcher(const MimeMagicRuleMatcher &matcher) override
{ m_provider.addMagicMatcher(matcher); }
private:
MimeXMLProvider &m_provider;
};
} // Internal
} // Utils

View File

@@ -1,104 +0,0 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR LGPL-3.0
#include "mimeutils.h"
#include "mimedatabase.h"
#include "mimedatabase_p.h"
#include "mimemagicrule_p.h"
#include "mimeprovider_p.h"
#include "filepath.h"
using namespace Utils;
using namespace Utils::Internal;
void Utils::addMimeTypes(const QString &fileName, const QByteArray &data)
{
auto d = MimeDatabasePrivate::instance();
QMutexLocker locker(&d->mutex);
if (d->m_startupPhase >= MimeDatabase::PluginsDelayedInitializing)
qWarning("Adding items from %s to MimeDatabase after initialization time",
qPrintable(fileName));
auto xmlProvider = static_cast<MimeXMLProvider *>(d->provider());
xmlProvider->addData(fileName, data);
}
QMap<int, QList<MimeMagicRule>> Utils::magicRulesForMimeType(const MimeType &mimeType)
{
auto d = MimeDatabasePrivate::instance();
QMutexLocker locker(&d->mutex);
return d->provider()->magicRulesForMimeType(mimeType);
}
void Utils::setGlobPatternsForMimeType(const MimeType &mimeType, const QStringList &patterns)
{
auto d = MimeDatabasePrivate::instance();
QMutexLocker locker(&d->mutex);
d->provider()->setGlobPatternsForMimeType(mimeType, patterns);
}
void Utils::setMagicRulesForMimeType(const MimeType &mimeType,
const QMap<int, QList<MimeMagicRule>> &rules)
{
auto d = MimeDatabasePrivate::instance();
QMutexLocker locker(&d->mutex);
d->provider()->setMagicRulesForMimeType(mimeType, rules);
}
void Utils::setMimeStartupPhase(MimeStartupPhase phase)
{
auto d = MimeDatabasePrivate::instance();
QMutexLocker locker(&d->mutex);
if (int(phase) != d->m_startupPhase + 1)
qWarning("Unexpected jump in MimedDatabase lifetime from %d to %d",
d->m_startupPhase,
int(phase));
d->m_startupPhase = int(phase);
}
MimeType Utils::mimeTypeForName(const QString &nameOrAlias)
{
MimeDatabase mdb;
return mdb.mimeTypeForName(nameOrAlias);
}
MimeType Utils::mimeTypeForFile(const QString &fileName, MimeMatchMode mode)
{
MimeDatabase mdb;
return mdb.mimeTypeForFile(fileName, MimeDatabase::MatchMode(mode));
}
MimeType Utils::mimeTypeForFile(const QFileInfo &fileInfo, MimeMatchMode mode)
{
MimeDatabase mdb;
return mdb.mimeTypeForFile(fileInfo, MimeDatabase::MatchMode(mode));
}
MimeType Utils::mimeTypeForFile(const FilePath &filePath, MimeMatchMode mode)
{
MimeDatabase mdb;
if (filePath.needsDevice())
return mdb.mimeTypeForUrl(filePath.toUrl());
return mdb.mimeTypeForFile(filePath.toString(), MimeDatabase::MatchMode(mode));
}
QList<MimeType> Utils::mimeTypesForFileName(const QString &fileName)
{
MimeDatabase mdb;
return mdb.mimeTypesForFileName(fileName);
}
MimeType Utils::mimeTypeForData(const QByteArray &data)
{
MimeDatabase mdb;
return mdb.mimeTypeForData(data);
}
QList<MimeType> Utils::allMimeTypes()
{
MimeDatabase mdb;
return mdb.allMimeTypes();
}

View File

@@ -5,9 +5,7 @@ Project {
name: "Utils"
QtcLibrary {
property bool useNewMimeDatabase: true
cpp.includePaths: base.concat((useNewMimeDatabase ? "mimetypes2" : "mimetypes"), ".")
cpp.includePaths: base.concat("mimetypes2", ".")
cpp.defines: base.concat([
"UTILS_LIBRARY"
])
@@ -416,7 +414,7 @@ Project {
Group {
name: "MimeTypes"
prefix: useNewMimeDatabase ? "mimetypes2/" : "mimetypes/"
prefix: "mimetypes2/"
files: [
"mimedatabase.cpp",
"mimedatabase.h",
@@ -461,8 +459,7 @@ Project {
Export {
Depends { name: "Qt"; submodules: ["concurrent", "widgets" ] }
cpp.includePaths: base.concat(exportingProduct.useNewMimeDatabase ? "mimetypes2"
: "mimetypes")
cpp.includePaths: base.concat("mimetypes2")
}
}
}

View File

@@ -23,7 +23,6 @@
#include <projectexplorer/jsonwizard/jsonwizardfactory.h>
#include <utils/algorithm.h>
#include <utils/mimetypes/mimedatabase.h>
#include <utils/qtcassert.h>
#include <QMenu>