QMimeDatabase: redesign to use both binary and XML providers
Previously, we would use mime.cache in all mime directories if at least one of them had such a file (other than the most-local one), otherwise the "source" XML would be used in all directories. Now it's possible to use mime.cache in those directories which have one, and XML in those directories that don't. Not only is this more correct, it will allow in a subsequent commit to bundle the binary cache in QtCore's qrc rather than the very big XML file. The design change to allow this is that now every provider only deals with a single directory, and QMimeDatabasePrivate takes care of creating multiple providers, one for each dir. This required to move most of the loops from the binary provider up to QMimeDatabasePrivate itself. Change-Id: Iac82d5f5836b80d45076e586b903d16fa2525b34 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
8835c0376b
commit
7a5644d648
src/corelib/mimetypes
mimetypes.qrcqmimedatabase.cppqmimedatabase_p.hqmimeglobpattern.cppqmimeglobpattern_p.hqmimeprovider.cppqmimeprovider_p.hqmimetype.cppqmimetype_p.hqmimetypeparser.cpp
tests/auto/corelib/mimetypes/qmimedatabase
@ -1,5 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/qt-project.org/qmime">
|
||||
<qresource prefix="/qt-project.org/qmime/packages">
|
||||
<file alias="freedesktop.org.xml">mime/packages/freedesktop.org.xml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QSet>
|
||||
#include <QtCore/QStandardPaths>
|
||||
#include <QtCore/QBuffer>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QDebug>
|
||||
@ -69,14 +70,13 @@ QMimeDatabasePrivate *QMimeDatabasePrivate::instance()
|
||||
}
|
||||
|
||||
QMimeDatabasePrivate::QMimeDatabasePrivate()
|
||||
: m_provider(0), m_defaultMimeType(QLatin1String("application/octet-stream"))
|
||||
: m_defaultMimeType(QLatin1String("application/octet-stream"))
|
||||
{
|
||||
}
|
||||
|
||||
QMimeDatabasePrivate::~QMimeDatabasePrivate()
|
||||
{
|
||||
delete m_provider;
|
||||
m_provider = 0;
|
||||
qDeleteAll(m_providers);
|
||||
}
|
||||
|
||||
Q_CORE_EXPORT int qmime_secondsBetweenChecks = 5; // exported for the unit test
|
||||
@ -89,24 +89,80 @@ bool QMimeDatabasePrivate::shouldCheck()
|
||||
return true;
|
||||
}
|
||||
|
||||
QMimeProviderBase *QMimeDatabasePrivate::provider()
|
||||
#if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY)
|
||||
#define QT_USE_MMAP
|
||||
#endif
|
||||
|
||||
void QMimeDatabasePrivate::loadProviders()
|
||||
{
|
||||
// We use QStandardPaths every time to check if new files appeared
|
||||
QStringList mimeDirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QLatin1String("mime"), QStandardPaths::LocateDirectory);
|
||||
const auto fdoIterator = std::find_if(mimeDirs.constBegin(), mimeDirs.constEnd(), [](const QString &mimeDir) -> bool {
|
||||
return QFileInfo::exists(mimeDir + QStringLiteral("/packages/freedesktop.org.xml")); }
|
||||
);
|
||||
if (fdoIterator == mimeDirs.constEnd())
|
||||
mimeDirs.prepend(QLatin1String(":/qt-project.org/qmime"));
|
||||
//qDebug() << "mime dirs:" << mimeDirs;
|
||||
|
||||
m_providers.reserve(mimeDirs.size());
|
||||
for (const QString &mimeDir : qAsConst(mimeDirs)) {
|
||||
const QString cacheFile = mimeDir + QStringLiteral("/mime.cache");
|
||||
QFileInfo fileInfo(cacheFile);
|
||||
// Check if we already have a provider for this dir
|
||||
// [This could be optimized by keeping a copy of mimeDirs and comparing the stringlists]
|
||||
const auto it = std::find_if(m_providers.begin(), m_providers.end(), [mimeDir](QMimeProviderBase *prov) { return prov->directory() == mimeDir; });
|
||||
if (it == m_providers.end()) {
|
||||
QMimeProviderBase *provider = nullptr;
|
||||
#if defined(QT_USE_MMAP)
|
||||
if (qEnvironmentVariableIsEmpty("QT_NO_MIME_CACHE") && fileInfo.exists()) {
|
||||
provider = new QMimeBinaryProvider(this, mimeDir);
|
||||
//qDebug() << "Created binary provider for" << mimeDir;
|
||||
if (!provider->isValid()) {
|
||||
delete provider;
|
||||
provider = nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!provider) {
|
||||
provider = new QMimeXMLProvider(this, mimeDir);
|
||||
//qDebug() << "Created XML provider for" << mimeDir;
|
||||
}
|
||||
m_providers.append(provider);
|
||||
} else {
|
||||
QMimeProviderBase *provider = *it;
|
||||
provider->ensureLoaded();
|
||||
if (!provider->isValid()) {
|
||||
delete provider;
|
||||
provider = new QMimeXMLProvider(this, mimeDir);
|
||||
//qDebug() << "Created XML provider to replace binary provider for" << mimeDir;
|
||||
*it = provider;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVector<QMimeProviderBase *> QMimeDatabasePrivate::providers()
|
||||
{
|
||||
Q_ASSERT(!mutex.tryLock()); // caller should have locked mutex
|
||||
if (!m_provider) {
|
||||
QMimeProviderBase *binaryProvider = new QMimeBinaryProvider(this);
|
||||
if (binaryProvider->isValid()) {
|
||||
m_provider = binaryProvider;
|
||||
} else {
|
||||
delete binaryProvider;
|
||||
m_provider = new QMimeXMLProvider(this);
|
||||
}
|
||||
m_provider->ensureLoaded();
|
||||
if (m_providers.isEmpty()) {
|
||||
loadProviders();
|
||||
m_lastCheck.start();
|
||||
} else {
|
||||
if (shouldCheck())
|
||||
m_provider->ensureLoaded();
|
||||
loadProviders();
|
||||
}
|
||||
return m_provider;
|
||||
return m_providers;
|
||||
}
|
||||
|
||||
QString QMimeDatabasePrivate::resolveAlias(const QString &nameOrAlias)
|
||||
{
|
||||
const auto allProviders = providers();
|
||||
for (QMimeProviderBase *provider : allProviders) {
|
||||
const QString ret = provider->resolveAlias(nameOrAlias);
|
||||
if (!ret.isEmpty())
|
||||
return ret;
|
||||
}
|
||||
return nameOrAlias;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -115,7 +171,14 @@ QMimeProviderBase *QMimeDatabasePrivate::provider()
|
||||
*/
|
||||
QMimeType QMimeDatabasePrivate::mimeTypeForName(const QString &nameOrAlias)
|
||||
{
|
||||
return provider()->mimeTypeForName(provider()->resolveAlias(nameOrAlias));
|
||||
const auto allProviders = providers();
|
||||
const QString mimeName = resolveAlias(nameOrAlias);
|
||||
for (QMimeProviderBase *provider : allProviders) {
|
||||
const QMimeType mime = provider->mimeTypeForName(mimeName);
|
||||
if (mime.isValid())
|
||||
return mime;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
QStringList QMimeDatabasePrivate::mimeTypeForFileName(const QString &fileName)
|
||||
@ -123,44 +186,105 @@ QStringList QMimeDatabasePrivate::mimeTypeForFileName(const QString &fileName)
|
||||
if (fileName.endsWith(QLatin1Char('/')))
|
||||
return QStringList() << QLatin1String("inode/directory");
|
||||
|
||||
QStringList matchingMimeTypes = provider()->findByFileName(QFileInfo(fileName).fileName()).m_matchingMimeTypes;
|
||||
const QString shortName = QFileInfo(fileName).fileName();
|
||||
const QMimeGlobMatchResult result = findByFileName(shortName);
|
||||
QStringList matchingMimeTypes = result.m_matchingMimeTypes;
|
||||
matchingMimeTypes.sort(); // make it deterministic
|
||||
return matchingMimeTypes;
|
||||
}
|
||||
|
||||
QMimeGlobMatchResult QMimeDatabasePrivate::findByFileName(const QString &fileName)
|
||||
{
|
||||
return provider()->findByFileName(fileName);
|
||||
QMimeGlobMatchResult result;
|
||||
// TODO this parses in the order (local, global). Check that it handles "NOGLOBS" correctly.
|
||||
const auto allProviders = providers();
|
||||
for (QMimeProviderBase *provider : allProviders)
|
||||
provider->addFileNameMatches(fileName, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void QMimeDatabasePrivate::loadMimeTypePrivate(QMimeTypePrivate &mimePrivate)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
provider()->loadMimeTypePrivate(mimePrivate);
|
||||
if (!mimePrivate.loaded) { // XML provider sets loaded=true, binary provider does this on demand
|
||||
Q_ASSERT(mimePrivate.fromCache);
|
||||
QMimeBinaryProvider::loadMimeTypePrivate(mimePrivate);
|
||||
}
|
||||
}
|
||||
|
||||
void QMimeDatabasePrivate::loadGenericIcon(QMimeTypePrivate &mimePrivate)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
provider()->loadGenericIcon(mimePrivate);
|
||||
if (mimePrivate.fromCache) {
|
||||
mimePrivate.genericIconName.clear();
|
||||
const auto allProviders = providers();
|
||||
for (QMimeProviderBase *provider : allProviders) {
|
||||
provider->loadGenericIcon(mimePrivate);
|
||||
if (!mimePrivate.genericIconName.isEmpty())
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QMimeDatabasePrivate::loadIcon(QMimeTypePrivate &mimePrivate)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
provider()->loadIcon(mimePrivate);
|
||||
if (mimePrivate.fromCache) {
|
||||
mimePrivate.iconName.clear();
|
||||
const auto allProviders = providers();
|
||||
for (QMimeProviderBase *provider : allProviders) {
|
||||
provider->loadIcon(mimePrivate);
|
||||
if (!mimePrivate.iconName.isEmpty())
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static QString fallbackParent(const QString &mimeTypeName)
|
||||
{
|
||||
const QStringRef myGroup = mimeTypeName.leftRef(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();
|
||||
}
|
||||
|
||||
QStringList QMimeDatabasePrivate::mimeParents(const QString &mimeName)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
return parents(mimeName);
|
||||
}
|
||||
|
||||
QStringList QMimeDatabasePrivate::parents(const QString &mimeName)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
return provider()->parents(mimeName);
|
||||
Q_ASSERT(!mutex.tryLock());
|
||||
QStringList result;
|
||||
const auto allProviders = providers();
|
||||
for (QMimeProviderBase *provider : allProviders)
|
||||
provider->addParents(mimeName, result);
|
||||
if (result.isEmpty()) {
|
||||
const QString parent = fallbackParent(mimeName);
|
||||
if (!parent.isEmpty())
|
||||
result.append(parent);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList QMimeDatabasePrivate::listAliases(const QString &mimeName)
|
||||
{
|
||||
QMutexLocker locker(&mutex);
|
||||
return provider()->listAliases(mimeName);
|
||||
QStringList result;
|
||||
const auto allProviders = providers();
|
||||
for (QMimeProviderBase *provider : allProviders)
|
||||
provider->addAliases(mimeName, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool QMimeDatabasePrivate::mimeInherits(const QString &mime, const QString &parent)
|
||||
@ -196,7 +320,10 @@ QMimeType QMimeDatabasePrivate::findByData(const QByteArray &data, int *accuracy
|
||||
}
|
||||
|
||||
*accuracyPtr = 0;
|
||||
QMimeType candidate = provider()->findByMagic(data, accuracyPtr);
|
||||
QMimeType candidate;
|
||||
const auto allProviders = providers();
|
||||
for (QMimeProviderBase *provider : allProviders)
|
||||
provider->findByMagic(data, accuracyPtr, candidate);
|
||||
|
||||
if (candidate.isValid())
|
||||
return candidate;
|
||||
@ -223,7 +350,7 @@ QMimeType QMimeDatabasePrivate::mimeTypeForFileNameAndData(const QString &fileNa
|
||||
if (fileName.endsWith(QLatin1Char('/')))
|
||||
candidatesByName.addMatch(QLatin1String("inode/directory"), 100, QString());
|
||||
else
|
||||
candidatesByName = provider()->findByFileName(QFileInfo(fileName).fileName());
|
||||
candidatesByName = findByFileName(QFileInfo(fileName).fileName());
|
||||
if (candidatesByName.m_allMatchingMimeTypes.count() == 1) {
|
||||
*accuracyPtr = 100;
|
||||
const QMimeType mime = mimeTypeForName(candidatesByName.m_matchingMimeTypes.at(0));
|
||||
@ -273,21 +400,25 @@ QMimeType QMimeDatabasePrivate::mimeTypeForFileNameAndData(const QString &fileNa
|
||||
|
||||
QList<QMimeType> QMimeDatabasePrivate::allMimeTypes()
|
||||
{
|
||||
return provider()->allMimeTypes();
|
||||
QList<QMimeType> result;
|
||||
const auto allProviders = providers();
|
||||
for (QMimeProviderBase *provider : allProviders)
|
||||
provider->addAllMimeTypes(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool QMimeDatabasePrivate::inherits(const QString &mime, const QString &parent)
|
||||
{
|
||||
const QString resolvedParent = provider()->resolveAlias(parent);
|
||||
//Q_ASSERT(provider()->resolveAlias(mime) == mime);
|
||||
const QString resolvedParent = resolveAlias(parent);
|
||||
std::stack<QString, QStringList> toCheck;
|
||||
toCheck.push(mime);
|
||||
while (!toCheck.empty()) {
|
||||
if (toCheck.top() == resolvedParent)
|
||||
return true;
|
||||
const auto parents = provider()->parents(toCheck.top());
|
||||
const QString mimeName = toCheck.top();
|
||||
toCheck.pop();
|
||||
for (const QString &par : parents)
|
||||
const auto parentList = parents(mimeName);
|
||||
for (const QString &par : parentList)
|
||||
toCheck.push(par);
|
||||
}
|
||||
return false;
|
||||
|
@ -59,8 +59,9 @@
|
||||
#include "qmimetype_p.h"
|
||||
#include "qmimeglobpattern_p.h"
|
||||
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qelapsedtimer.h>
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qvector.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -84,7 +85,8 @@ public:
|
||||
|
||||
QList<QMimeType> allMimeTypes();
|
||||
|
||||
|
||||
QString resolveAlias(const QString &nameOrAlias);
|
||||
QStringList parents(const QString &mimeName);
|
||||
QMimeType mimeTypeForName(const QString &nameOrAlias);
|
||||
QMimeType mimeTypeForFileNameAndData(const QString &fileName, QIODevice *device, int *priorityPtr);
|
||||
QMimeType findByData(const QByteArray &data, int *priorityPtr);
|
||||
@ -95,15 +97,16 @@ public:
|
||||
void loadMimeTypePrivate(QMimeTypePrivate &mimePrivate);
|
||||
void loadGenericIcon(QMimeTypePrivate &mimePrivate);
|
||||
void loadIcon(QMimeTypePrivate &mimePrivate);
|
||||
QStringList parents(const QString &mimeName);
|
||||
QStringList mimeParents(const QString &mimeName);
|
||||
QStringList listAliases(const QString &mimeName);
|
||||
bool mimeInherits(const QString &mime, const QString &parent);
|
||||
|
||||
private:
|
||||
QMimeProviderBase *provider();
|
||||
QVector<QMimeProviderBase *> providers();
|
||||
bool shouldCheck();
|
||||
void loadProviders();
|
||||
|
||||
mutable QMimeProviderBase *m_provider;
|
||||
mutable QVector<QMimeProviderBase *> m_providers;
|
||||
QElapsedTimer m_lastCheck;
|
||||
|
||||
public:
|
||||
|
@ -206,10 +206,9 @@ void QMimeGlobPatternList::match(QMimeGlobMatchResult &result,
|
||||
}
|
||||
}
|
||||
|
||||
QMimeGlobMatchResult QMimeAllGlobPatterns::matchingGlobs(const QString &fileName) const
|
||||
void QMimeAllGlobPatterns::matchingGlobs(const QString &fileName, QMimeGlobMatchResult &result) const
|
||||
{
|
||||
// First try the high weight matches (>50), if any.
|
||||
QMimeGlobMatchResult result;
|
||||
m_highWeightGlobs.match(result, fileName);
|
||||
|
||||
// Now use the "fast patterns" dict, for simple *.foo patterns with weight 50
|
||||
@ -230,8 +229,6 @@ QMimeGlobMatchResult QMimeAllGlobPatterns::matchingGlobs(const QString &fileName
|
||||
|
||||
// Finally, try the low weight matches (<=50)
|
||||
m_lowWeightGlobs.match(result, fileName);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void QMimeAllGlobPatterns::clear()
|
||||
|
@ -152,7 +152,7 @@ public:
|
||||
|
||||
void addGlob(const QMimeGlobPattern &glob);
|
||||
void removeMimeType(const QString &mimeType);
|
||||
QMimeGlobMatchResult matchingGlobs(const QString &fileName) const;
|
||||
void matchingGlobs(const QString &fileName, QMimeGlobMatchResult &result) const;
|
||||
void clear();
|
||||
|
||||
PatternsMap m_fastPatterns; // example: "doc" -> "application/msword", "text/plain"
|
||||
|
@ -61,37 +61,18 @@ static void initResources()
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
static QString fallbackParent(const QString &mimeTypeName)
|
||||
{
|
||||
const QStringRef myGroup = mimeTypeName.leftRef(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();
|
||||
}
|
||||
|
||||
QMimeProviderBase::QMimeProviderBase(QMimeDatabasePrivate *db)
|
||||
: m_db(db)
|
||||
QMimeProviderBase::QMimeProviderBase(QMimeDatabasePrivate *db, const QString &directory)
|
||||
: m_db(db), m_directory(directory)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
QMimeBinaryProvider::QMimeBinaryProvider(QMimeDatabasePrivate *db)
|
||||
: QMimeProviderBase(db), m_mimetypeListLoaded(false)
|
||||
QMimeBinaryProvider::QMimeBinaryProvider(QMimeDatabasePrivate *db, const QString &directory)
|
||||
: QMimeProviderBase(db, directory), m_mimetypeListLoaded(false)
|
||||
{
|
||||
ensureLoaded();
|
||||
}
|
||||
|
||||
#if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY)
|
||||
#define QT_USE_MMAP
|
||||
#endif
|
||||
|
||||
struct QMimeBinaryProvider::CacheFile
|
||||
{
|
||||
CacheFile(const QString &fileName);
|
||||
@ -145,7 +126,6 @@ bool QMimeBinaryProvider::CacheFile::load()
|
||||
|
||||
bool QMimeBinaryProvider::CacheFile::reload()
|
||||
{
|
||||
//qDebug() << "reload!" << file->fileName();
|
||||
m_valid = false;
|
||||
if (file.isOpen()) {
|
||||
file.close();
|
||||
@ -154,18 +134,14 @@ bool QMimeBinaryProvider::CacheFile::reload()
|
||||
return load();
|
||||
}
|
||||
|
||||
QMimeBinaryProvider::CacheFile *QMimeBinaryProvider::CacheFileList::findCacheFile(const QString &fileName) const
|
||||
{
|
||||
for (const_iterator it = begin(); it != end(); ++it) {
|
||||
if ((*it)->file.fileName() == fileName)
|
||||
return *it;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
QMimeBinaryProvider::~QMimeBinaryProvider()
|
||||
{
|
||||
qDeleteAll(m_cacheFiles);
|
||||
delete m_cacheFile;
|
||||
}
|
||||
|
||||
bool QMimeBinaryProvider::isValid()
|
||||
{
|
||||
return m_cacheFile != nullptr;
|
||||
}
|
||||
|
||||
// Position of the "list offsets" values, at the beginning of the mime.cache file
|
||||
@ -181,76 +157,33 @@ enum {
|
||||
PosGenericIconsListOffset = 36
|
||||
};
|
||||
|
||||
bool QMimeBinaryProvider::isValid()
|
||||
bool QMimeBinaryProvider::checkCacheChanged()
|
||||
{
|
||||
#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
|
||||
ensureLoaded();
|
||||
|
||||
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.constFirst()->file.fileName();
|
||||
const QString localCacheFile = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/mime/mime.cache");
|
||||
|
||||
return foundFile != localCacheFile;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool QMimeBinaryProvider::CacheFileList::checkCacheChanged()
|
||||
{
|
||||
bool somethingChanged = false;
|
||||
for (CacheFile *cacheFile : qAsConst(*this)) {
|
||||
QFileInfo fileInfo(cacheFile->file);
|
||||
if (!fileInfo.exists() || fileInfo.lastModified() > cacheFile->m_mtime) {
|
||||
QFileInfo fileInfo(m_cacheFile->file);
|
||||
if (fileInfo.lastModified() > m_cacheFile->m_mtime) {
|
||||
// Deletion can't happen by just running update-mime-database.
|
||||
// But the user could use rm -rf :-)
|
||||
cacheFile->reload(); // will mark itself as invalid on failure
|
||||
somethingChanged = true;
|
||||
m_cacheFile->reload(); // will mark itself as invalid on failure
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (somethingChanged) {
|
||||
auto deleteIfNoLongerValid = [](CacheFile *cacheFile) -> bool {
|
||||
const bool invalid = !cacheFile->isValid();
|
||||
if (invalid)
|
||||
delete cacheFile;
|
||||
return invalid;
|
||||
};
|
||||
erase(std::remove_if(begin(), end(), deleteIfNoLongerValid), end());
|
||||
}
|
||||
return somethingChanged;
|
||||
return false;
|
||||
}
|
||||
|
||||
void QMimeBinaryProvider::ensureLoaded()
|
||||
{
|
||||
// First iterate over existing known cache files and check for uptodate
|
||||
if (m_cacheFiles.checkCacheChanged())
|
||||
if (!m_cacheFile) {
|
||||
const QString cacheFileName = m_directory + QLatin1String("/mime.cache");
|
||||
m_cacheFile = new CacheFile(cacheFileName);
|
||||
m_mimetypeListLoaded = false;
|
||||
} else {
|
||||
if (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;
|
||||
return; // nothing to do
|
||||
}
|
||||
}
|
||||
m_cacheFileNames = cacheFileNames;
|
||||
m_mimetypeListLoaded = false;
|
||||
if (!m_cacheFile->isValid()) { // verify existence and version
|
||||
delete m_cacheFile;
|
||||
m_cacheFile = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,6 +191,7 @@ static QMimeType mimeTypeForNameUnchecked(const QString &name)
|
||||
{
|
||||
QMimeTypePrivate data;
|
||||
data.name = name;
|
||||
data.fromCache = true;
|
||||
// The rest is retrieved on demand.
|
||||
// comment and globPatterns: in loadMimeTypePrivate
|
||||
// iconName: in loadIcon
|
||||
@ -274,27 +208,23 @@ QMimeType QMimeBinaryProvider::mimeTypeForName(const QString &name)
|
||||
return mimeTypeForNameUnchecked(name);
|
||||
}
|
||||
|
||||
QMimeGlobMatchResult QMimeBinaryProvider::findByFileName(const QString &fileName)
|
||||
void QMimeBinaryProvider::addFileNameMatches(const QString &fileName, QMimeGlobMatchResult &result)
|
||||
{
|
||||
QMimeGlobMatchResult result;
|
||||
if (fileName.isEmpty())
|
||||
return result;
|
||||
return;
|
||||
Q_ASSERT(m_cacheFile);
|
||||
const QString lowerFileName = fileName.toLower();
|
||||
// TODO this parses in the order (local, global). Check that it handles "NOGLOBS" correctly.
|
||||
for (CacheFile *cacheFile : qAsConst(m_cacheFiles)) {
|
||||
// Check literals (e.g. "Makefile")
|
||||
matchGlobList(result, cacheFile, cacheFile->getUint32(PosLiteralListOffset), fileName);
|
||||
matchGlobList(result, m_cacheFile, m_cacheFile->getUint32(PosLiteralListOffset), fileName);
|
||||
// Check complex globs (e.g. "callgrind.out[0-9]*")
|
||||
matchGlobList(result, cacheFile, cacheFile->getUint32(PosGlobListOffset), fileName);
|
||||
matchGlobList(result, m_cacheFile, m_cacheFile->getUint32(PosGlobListOffset), fileName);
|
||||
// Check the very common *.txt cases with the suffix tree
|
||||
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, lowerFileName.length() - 1, false);
|
||||
const int reverseSuffixTreeOffset = m_cacheFile->getUint32(PosReverseSuffixTreeOffset);
|
||||
const int numRoots = m_cacheFile->getUint32(reverseSuffixTreeOffset);
|
||||
const int firstRootOffset = m_cacheFile->getUint32(reverseSuffixTreeOffset + 4);
|
||||
matchSuffixTree(result, m_cacheFile, numRoots, firstRootOffset, lowerFileName, lowerFileName.length() - 1, false);
|
||||
if (result.m_matchingMimeTypes.isEmpty())
|
||||
matchSuffixTree(result, cacheFile, numRoots, firstRootOffset, fileName, fileName.length() - 1, true);
|
||||
}
|
||||
return result;
|
||||
matchSuffixTree(result, m_cacheFile, numRoots, firstRootOffset, fileName, fileName.length() - 1, true);
|
||||
}
|
||||
|
||||
void QMimeBinaryProvider::matchGlobList(QMimeGlobMatchResult &result, CacheFile *cacheFile, int off, const QString &fileName)
|
||||
@ -392,120 +322,106 @@ bool QMimeBinaryProvider::matchMagicRule(QMimeBinaryProvider::CacheFile *cacheFi
|
||||
return false;
|
||||
}
|
||||
|
||||
QMimeType QMimeBinaryProvider::findByMagic(const QByteArray &data, int *accuracyPtr)
|
||||
void QMimeBinaryProvider::findByMagic(const QByteArray &data, int *accuracyPtr, QMimeType &candidate)
|
||||
{
|
||||
for (CacheFile *cacheFile : qAsConst(m_cacheFiles)) {
|
||||
const int magicListOffset = cacheFile->getUint32(PosMagicListOffset);
|
||||
const int numMatches = cacheFile->getUint32(magicListOffset);
|
||||
const int magicListOffset = m_cacheFile->getUint32(PosMagicListOffset);
|
||||
const int numMatches = m_cacheFile->getUint32(magicListOffset);
|
||||
//const int maxExtent = cacheFile->getUint32(magicListOffset + 4);
|
||||
const int firstMatchOffset = cacheFile->getUint32(magicListOffset + 8);
|
||||
const int firstMatchOffset = m_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);
|
||||
const int numMatchlets = m_cacheFile->getUint32(off + 8);
|
||||
const int firstMatchletOffset = m_cacheFile->getUint32(off + 12);
|
||||
if (matchMagicRule(m_cacheFile, numMatchlets, firstMatchletOffset, data)) {
|
||||
const int mimeTypeOffset = m_cacheFile->getUint32(off + 4);
|
||||
const char *mimeType = m_cacheFile->getCharStar(mimeTypeOffset);
|
||||
*accuracyPtr = m_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));
|
||||
candidate = mimeTypeForNameUnchecked(QLatin1String(mimeType));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
return QMimeType();
|
||||
}
|
||||
|
||||
QStringList QMimeBinaryProvider::parents(const QString &mime)
|
||||
void QMimeBinaryProvider::addParents(const QString &mime, QStringList &result)
|
||||
{
|
||||
const QByteArray mimeStr = mime.toLatin1();
|
||||
QStringList result;
|
||||
for (CacheFile *cacheFile : qAsConst(m_cacheFiles)) {
|
||||
const int parentListOffset = cacheFile->getUint32(PosParentListOffset);
|
||||
const int numEntries = cacheFile->getUint32(parentListOffset);
|
||||
const int parentListOffset = m_cacheFile->getUint32(PosParentListOffset);
|
||||
const int numEntries = m_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 mimeOffset = m_cacheFile->getUint32(off);
|
||||
const char *aMime = m_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);
|
||||
const int parentsOffset = m_cacheFile->getUint32(off + 4);
|
||||
const int numParents = m_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));
|
||||
const int parentOffset = m_cacheFile->getUint32(parentsOffset + 4 + 4 * i);
|
||||
const char *aParent = m_cacheFile->getCharStar(parentOffset);
|
||||
const QString strParent = QString::fromLatin1(aParent);
|
||||
if (!result.contains(strParent))
|
||||
result.append(strParent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result.isEmpty()) {
|
||||
const QString parent = fallbackParent(mime);
|
||||
if (!parent.isEmpty())
|
||||
result.append(parent);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QString QMimeBinaryProvider::resolveAlias(const QString &name)
|
||||
{
|
||||
const QByteArray input = name.toLatin1();
|
||||
for (CacheFile *cacheFile : qAsConst(m_cacheFiles)) {
|
||||
const int aliasListOffset = cacheFile->getUint32(PosAliasListOffset);
|
||||
const int numEntries = cacheFile->getUint32(aliasListOffset);
|
||||
const int aliasListOffset = m_cacheFile->getUint32(PosAliasListOffset);
|
||||
const int numEntries = m_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 aliasOffset = m_cacheFile->getUint32(off);
|
||||
const char *alias = m_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);
|
||||
const int mimeOffset = m_cacheFile->getUint32(off + 4);
|
||||
const char *mimeType = m_cacheFile->getCharStar(mimeOffset);
|
||||
return QLatin1String(mimeType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
QStringList QMimeBinaryProvider::listAliases(const QString &name)
|
||||
void QMimeBinaryProvider::addAliases(const QString &name, QStringList &result)
|
||||
{
|
||||
QStringList result;
|
||||
const QByteArray input = name.toLatin1();
|
||||
for (CacheFile *cacheFile : qAsConst(m_cacheFiles)) {
|
||||
const int aliasListOffset = cacheFile->getUint32(PosAliasListOffset);
|
||||
const int numEntries = cacheFile->getUint32(aliasListOffset);
|
||||
const int aliasListOffset = m_cacheFile->getUint32(PosAliasListOffset);
|
||||
const int numEntries = m_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);
|
||||
const int mimeOffset = m_cacheFile->getUint32(off + 4);
|
||||
const char *mimeType = m_cacheFile->getCharStar(mimeOffset);
|
||||
|
||||
if (input == mimeType) {
|
||||
const int aliasOffset = cacheFile->getUint32(off);
|
||||
const char *alias = cacheFile->getCharStar(aliasOffset);
|
||||
result.append(QString::fromLatin1(alias));
|
||||
const int aliasOffset = m_cacheFile->getUint32(off);
|
||||
const char *alias = m_cacheFile->getCharStar(aliasOffset);
|
||||
const QString strAlias = QString::fromLatin1(alias);
|
||||
if (!result.contains(strAlias))
|
||||
result.append(strAlias);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void QMimeBinaryProvider::loadMimeTypeList()
|
||||
@ -515,9 +431,7 @@ void QMimeBinaryProvider::loadMimeTypeList()
|
||||
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);
|
||||
QFile file(m_directory + QStringLiteral("/types"));
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
QTextStream stream(&file);
|
||||
stream.setCodec("ISO 8859-1");
|
||||
@ -526,20 +440,21 @@ void QMimeBinaryProvider::loadMimeTypeList()
|
||||
m_mimetypeNames.insert(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QList<QMimeType> QMimeBinaryProvider::allMimeTypes()
|
||||
void QMimeBinaryProvider::addAllMimeTypes(QList<QMimeType> &result)
|
||||
{
|
||||
QList<QMimeType> result;
|
||||
loadMimeTypeList();
|
||||
if (result.isEmpty()) {
|
||||
result.reserve(m_mimetypeNames.count());
|
||||
|
||||
for (QSet<QString>::const_iterator it = m_mimetypeNames.constBegin();
|
||||
it != m_mimetypeNames.constEnd(); ++it)
|
||||
result.append(mimeTypeForNameUnchecked(*it));
|
||||
|
||||
return result;
|
||||
for (const QString &name : m_mimetypeNames)
|
||||
result.append(mimeTypeForNameUnchecked(name));
|
||||
} else {
|
||||
for (const QString &name : m_mimetypeNames)
|
||||
if (std::find_if(result.constBegin(), result.constEnd(), [name](const QMimeType &mime) -> bool { return mime.name() == name; })
|
||||
== result.constEnd())
|
||||
result.append(mimeTypeForNameUnchecked(name));
|
||||
}
|
||||
}
|
||||
|
||||
void QMimeBinaryProvider::loadMimeTypePrivate(QMimeTypePrivate &data)
|
||||
@ -664,33 +579,28 @@ QLatin1String QMimeBinaryProvider::iconForMime(CacheFile *cacheFile, int posList
|
||||
void QMimeBinaryProvider::loadIcon(QMimeTypePrivate &data)
|
||||
{
|
||||
const QByteArray inputMime = data.name.toLatin1();
|
||||
for (CacheFile *cacheFile : qAsConst(m_cacheFiles)) {
|
||||
const QLatin1String icon = iconForMime(cacheFile, PosIconsListOffset, inputMime);
|
||||
const QLatin1String icon = iconForMime(m_cacheFile, PosIconsListOffset, inputMime);
|
||||
if (!icon.isEmpty()) {
|
||||
data.iconName = icon;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QMimeBinaryProvider::loadGenericIcon(QMimeTypePrivate &data)
|
||||
{
|
||||
const QByteArray inputMime = data.name.toLatin1();
|
||||
for (CacheFile *cacheFile : qAsConst(m_cacheFiles)) {
|
||||
const QLatin1String icon = iconForMime(cacheFile, PosGenericIconsListOffset, inputMime);
|
||||
const QLatin1String icon = iconForMime(m_cacheFile, PosGenericIconsListOffset, inputMime);
|
||||
if (!icon.isEmpty()) {
|
||||
data.genericIconName = icon;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
QMimeXMLProvider::QMimeXMLProvider(QMimeDatabasePrivate *db)
|
||||
: QMimeProviderBase(db)
|
||||
QMimeXMLProvider::QMimeXMLProvider(QMimeDatabasePrivate *db, const QString &directory)
|
||||
: QMimeProviderBase(db, directory)
|
||||
{
|
||||
initResources();
|
||||
ensureLoaded();
|
||||
}
|
||||
|
||||
QMimeXMLProvider::~QMimeXMLProvider()
|
||||
@ -699,6 +609,8 @@ QMimeXMLProvider::~QMimeXMLProvider()
|
||||
|
||||
bool QMimeXMLProvider::isValid()
|
||||
{
|
||||
// If you change this method, adjust the logic in QMimeDatabasePrivate::loadProviders,
|
||||
// which assumes isValid==false is only possible in QMimeBinaryProvider.
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -707,50 +619,38 @@ QMimeType QMimeXMLProvider::mimeTypeForName(const QString &name)
|
||||
return m_nameMimeTypeMap.value(name);
|
||||
}
|
||||
|
||||
QMimeGlobMatchResult QMimeXMLProvider::findByFileName(const QString &fileName)
|
||||
void QMimeXMLProvider::addFileNameMatches(const QString &fileName, QMimeGlobMatchResult &result)
|
||||
{
|
||||
return m_mimeTypeGlobs.matchingGlobs(fileName);
|
||||
m_mimeTypeGlobs.matchingGlobs(fileName, result);
|
||||
}
|
||||
|
||||
QMimeType QMimeXMLProvider::findByMagic(const QByteArray &data, int *accuracyPtr)
|
||||
void QMimeXMLProvider::findByMagic(const QByteArray &data, int *accuracyPtr, QMimeType &candidate)
|
||||
{
|
||||
QString candidate;
|
||||
|
||||
QString candidateName;
|
||||
bool foundOne = false;
|
||||
for (const QMimeMagicRuleMatcher &matcher : qAsConst(m_magicMatchers)) {
|
||||
if (matcher.matches(data)) {
|
||||
const int priority = matcher.priority();
|
||||
if (priority > *accuracyPtr) {
|
||||
*accuracyPtr = priority;
|
||||
candidate = matcher.mimetype();
|
||||
candidateName = matcher.mimetype();
|
||||
foundOne = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return mimeTypeForName(candidate);
|
||||
if (foundOne)
|
||||
candidate = mimeTypeForName(candidateName);
|
||||
}
|
||||
|
||||
void QMimeXMLProvider::ensureLoaded()
|
||||
{
|
||||
bool fdoXmlFound = false;
|
||||
QStringList allFiles;
|
||||
|
||||
const QStringList packageDirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QLatin1String("mime/packages"), QStandardPaths::LocateDirectory);
|
||||
//qDebug() << "packageDirs=" << packageDirs;
|
||||
for (const QString &packageDir : packageDirs) {
|
||||
const QString packageDir = m_directory + QStringLiteral("/packages");
|
||||
QDir dir(packageDir);
|
||||
const QStringList files = dir.entryList(QDir::Files | QDir::NoDotAndDotDot);
|
||||
//qDebug() << static_cast<const void *>(this) << packageDir << files;
|
||||
if (!fdoXmlFound)
|
||||
fdoXmlFound = files.contains(QLatin1String("freedesktop.org.xml"));
|
||||
QStringList::const_iterator endIt(files.constEnd());
|
||||
for (QStringList::const_iterator it(files.constBegin()); it != endIt; ++it) {
|
||||
allFiles.append(packageDir + QLatin1Char('/') + *it);
|
||||
}
|
||||
}
|
||||
|
||||
if (!fdoXmlFound) {
|
||||
// We could instead install the file as part of installing Qt?
|
||||
allFiles.prepend(QLatin1String(":/qt-project.org/qmime/freedesktop.org.xml"));
|
||||
}
|
||||
allFiles.reserve(files.count());
|
||||
for (const QString &xmlFile : files)
|
||||
allFiles.append(packageDir + QLatin1Char('/') + xmlFile);
|
||||
|
||||
if (m_allFiles == allFiles)
|
||||
return;
|
||||
@ -798,18 +698,16 @@ void QMimeXMLProvider::addGlobPattern(const QMimeGlobPattern &glob)
|
||||
|
||||
void QMimeXMLProvider::addMimeType(const QMimeType &mt)
|
||||
{
|
||||
Q_ASSERT(!mt.d.data()->fromCache);
|
||||
m_nameMimeTypeMap.insert(mt.name(), mt);
|
||||
}
|
||||
|
||||
QStringList QMimeXMLProvider::parents(const QString &mime)
|
||||
void QMimeXMLProvider::addParents(const QString &mime, QStringList &result)
|
||||
{
|
||||
QStringList result = m_parents.value(mime);
|
||||
if (result.isEmpty()) {
|
||||
const QString parent = fallbackParent(mime);
|
||||
if (!parent.isEmpty())
|
||||
for (const QString &parent : m_parents.value(mime)) {
|
||||
if (!result.contains(parent))
|
||||
result.append(parent);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void QMimeXMLProvider::addParent(const QString &child, const QString &parent)
|
||||
@ -817,10 +715,16 @@ void QMimeXMLProvider::addParent(const QString &child, const QString &parent)
|
||||
m_parents[child].append(parent);
|
||||
}
|
||||
|
||||
QStringList QMimeXMLProvider::listAliases(const QString &name)
|
||||
void QMimeXMLProvider::addAliases(const QString &name, QStringList &result)
|
||||
{
|
||||
// Iterate through the whole hash. This method is rarely used.
|
||||
return m_aliases.keys(name);
|
||||
for (auto it = m_aliases.constBegin(), end = m_aliases.constEnd() ; it != end ; ++it) {
|
||||
if (it.value() == name) {
|
||||
if (!result.contains(it.key()))
|
||||
result.append(it.key());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QString QMimeXMLProvider::resolveAlias(const QString &name)
|
||||
@ -833,9 +737,18 @@ void QMimeXMLProvider::addAlias(const QString &alias, const QString &name)
|
||||
m_aliases.insert(alias, name);
|
||||
}
|
||||
|
||||
QList<QMimeType> QMimeXMLProvider::allMimeTypes()
|
||||
void QMimeXMLProvider::addAllMimeTypes(QList<QMimeType> &result)
|
||||
{
|
||||
return m_nameMimeTypeMap.values();
|
||||
if (result.isEmpty()) { // fast path
|
||||
result = m_nameMimeTypeMap.values();
|
||||
} else {
|
||||
for (auto it = m_nameMimeTypeMap.constBegin(), end = m_nameMimeTypeMap.constEnd() ; it != end ; ++it) {
|
||||
const QString newMime = it.key();
|
||||
if (std::find_if(result.constBegin(), result.constEnd(), [newMime](const QMimeType &mime) -> bool { return mime.name() == newMime; })
|
||||
== result.constEnd())
|
||||
result.append(it.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QMimeXMLProvider::addMagicMatcher(const QMimeMagicRuleMatcher &matcher)
|
||||
|
@ -67,23 +67,25 @@ class QMimeMagicRuleMatcher;
|
||||
class QMimeProviderBase
|
||||
{
|
||||
public:
|
||||
QMimeProviderBase(QMimeDatabasePrivate *db);
|
||||
QMimeProviderBase(QMimeDatabasePrivate *db, const QString &directory);
|
||||
virtual ~QMimeProviderBase() {}
|
||||
|
||||
virtual bool isValid() = 0;
|
||||
virtual QMimeType mimeTypeForName(const QString &name) = 0;
|
||||
virtual QMimeGlobMatchResult findByFileName(const QString &fileName) = 0;
|
||||
virtual QStringList parents(const QString &mime) = 0;
|
||||
virtual void addFileNameMatches(const QString &fileName, QMimeGlobMatchResult &result) = 0;
|
||||
virtual void addParents(const QString &mime, QStringList &result) = 0;
|
||||
virtual QString resolveAlias(const QString &name) = 0;
|
||||
virtual QStringList listAliases(const QString &name) = 0;
|
||||
virtual QMimeType findByMagic(const QByteArray &data, int *accuracyPtr) = 0;
|
||||
virtual QList<QMimeType> allMimeTypes() = 0;
|
||||
virtual void loadMimeTypePrivate(QMimeTypePrivate &) {}
|
||||
virtual void addAliases(const QString &name, QStringList &result) = 0;
|
||||
virtual void findByMagic(const QByteArray &data, int *accuracyPtr, QMimeType &candidate) = 0;
|
||||
virtual void addAllMimeTypes(QList<QMimeType> &result) = 0;
|
||||
virtual void loadIcon(QMimeTypePrivate &) {}
|
||||
virtual void loadGenericIcon(QMimeTypePrivate &) {}
|
||||
virtual void ensureLoaded() {}
|
||||
|
||||
QString directory() const { return m_directory; }
|
||||
|
||||
QMimeDatabasePrivate *m_db;
|
||||
QString m_directory;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -92,18 +94,18 @@ public:
|
||||
class QMimeBinaryProvider : public QMimeProviderBase
|
||||
{
|
||||
public:
|
||||
QMimeBinaryProvider(QMimeDatabasePrivate *db);
|
||||
QMimeBinaryProvider(QMimeDatabasePrivate *db, const QString &directory);
|
||||
virtual ~QMimeBinaryProvider();
|
||||
|
||||
virtual bool isValid() override;
|
||||
virtual QMimeType mimeTypeForName(const QString &name) override;
|
||||
virtual QMimeGlobMatchResult findByFileName(const QString &fileName) override;
|
||||
virtual QStringList parents(const QString &mime) override;
|
||||
void addFileNameMatches(const QString &fileName, QMimeGlobMatchResult &result) override;
|
||||
void addParents(const QString &mime, QStringList &result) override;
|
||||
virtual QString resolveAlias(const QString &name) override;
|
||||
virtual QStringList listAliases(const QString &name) override;
|
||||
virtual QMimeType findByMagic(const QByteArray &data, int *accuracyPtr) override;
|
||||
virtual QList<QMimeType> allMimeTypes() override;
|
||||
virtual void loadMimeTypePrivate(QMimeTypePrivate &) override;
|
||||
void addAliases(const QString &name, QStringList &result) override;
|
||||
void findByMagic(const QByteArray &data, int *accuracyPtr, QMimeType &candidate) override;
|
||||
void addAllMimeTypes(QList<QMimeType> &result) override;
|
||||
static void loadMimeTypePrivate(QMimeTypePrivate &);
|
||||
virtual void loadIcon(QMimeTypePrivate &) override;
|
||||
virtual void loadGenericIcon(QMimeTypePrivate &) override;
|
||||
void ensureLoaded() override;
|
||||
@ -116,14 +118,9 @@ private:
|
||||
bool matchMagicRule(CacheFile *cacheFile, int numMatchlets, int firstOffset, const QByteArray &data);
|
||||
QLatin1String iconForMime(CacheFile *cacheFile, int posListOffset, const QByteArray &inputMime);
|
||||
void loadMimeTypeList();
|
||||
|
||||
class CacheFileList : public QList<CacheFile *>
|
||||
{
|
||||
public:
|
||||
CacheFile *findCacheFile(const QString &fileName) const;
|
||||
bool checkCacheChanged();
|
||||
};
|
||||
CacheFileList m_cacheFiles;
|
||||
|
||||
CacheFile *m_cacheFile = nullptr;
|
||||
QStringList m_cacheFileNames;
|
||||
QSet<QString> m_mimetypeNames;
|
||||
bool m_mimetypeListLoaded;
|
||||
@ -135,17 +132,17 @@ private:
|
||||
class QMimeXMLProvider : public QMimeProviderBase
|
||||
{
|
||||
public:
|
||||
QMimeXMLProvider(QMimeDatabasePrivate *db);
|
||||
QMimeXMLProvider(QMimeDatabasePrivate *db, const QString &directory);
|
||||
~QMimeXMLProvider();
|
||||
|
||||
virtual bool isValid() override;
|
||||
virtual QMimeType mimeTypeForName(const QString &name) override;
|
||||
virtual QMimeGlobMatchResult findByFileName(const QString &fileName) override;
|
||||
virtual QStringList parents(const QString &mime) override;
|
||||
void addFileNameMatches(const QString &fileName, QMimeGlobMatchResult &result) override;
|
||||
void addParents(const QString &mime, QStringList &result) override;
|
||||
virtual QString resolveAlias(const QString &name) override;
|
||||
virtual QStringList listAliases(const QString &name) override;
|
||||
virtual QMimeType findByMagic(const QByteArray &data, int *accuracyPtr) override;
|
||||
virtual QList<QMimeType> allMimeTypes() override;
|
||||
void addAliases(const QString &name, QStringList &result) override;
|
||||
void findByMagic(const QByteArray &data, int *accuracyPtr, QMimeType &candidate) override;
|
||||
void addAllMimeTypes(QList<QMimeType> &result) override;
|
||||
void ensureLoaded() override;
|
||||
|
||||
bool load(const QString &fileName, QString *errorMessage);
|
||||
|
@ -57,7 +57,7 @@
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QMimeTypePrivate::QMimeTypePrivate()
|
||||
: loaded(false)
|
||||
: loaded(false), fromCache(false)
|
||||
{}
|
||||
|
||||
QMimeTypePrivate::QMimeTypePrivate(const QMimeType &other)
|
||||
@ -76,7 +76,6 @@ void QMimeTypePrivate::clear()
|
||||
genericIconName.clear();
|
||||
iconName.clear();
|
||||
globPatterns.clear();
|
||||
loaded = false;
|
||||
}
|
||||
|
||||
void QMimeTypePrivate::addGlobPattern(const QString &pattern)
|
||||
@ -368,12 +367,12 @@ QStringList QMimeType::globPatterns() const
|
||||
*/
|
||||
QStringList QMimeType::parentMimeTypes() const
|
||||
{
|
||||
return QMimeDatabasePrivate::instance()->parents(d->name);
|
||||
return QMimeDatabasePrivate::instance()->mimeParents(d->name);
|
||||
}
|
||||
|
||||
static void collectParentMimeTypes(const QString &mime, QStringList &allParents)
|
||||
{
|
||||
const QStringList parents = QMimeDatabasePrivate::instance()->parents(mime);
|
||||
const QStringList parents = QMimeDatabasePrivate::instance()->mimeParents(mime);
|
||||
for (const QString &parent : parents) {
|
||||
// I would use QSet, but since order matters I better not
|
||||
if (!allParents.contains(parent))
|
||||
|
@ -74,6 +74,7 @@ public:
|
||||
void addGlobPattern(const QString &pattern);
|
||||
|
||||
bool loaded; // QSharedData leaves a 4 byte gap, so don't put 8 byte members first
|
||||
bool fromCache; // true if this comes from the binary provider
|
||||
QString name;
|
||||
LocaleHash localeComments;
|
||||
QString genericIconName;
|
||||
@ -94,6 +95,7 @@ QT_END_NAMESPACE
|
||||
{ \
|
||||
QMimeTypePrivate qMimeTypeData; \
|
||||
qMimeTypeData.name = name; \
|
||||
qMimeTypeData.loaded = true; \
|
||||
qMimeTypeData.genericIconName = genericIconName; \
|
||||
qMimeTypeData.iconName = iconName; \
|
||||
qMimeTypeData.globPatterns = globPatterns; \
|
||||
@ -112,6 +114,7 @@ QT_END_NAMESPACE
|
||||
) \
|
||||
{ \
|
||||
QMimeTypePrivate qMimeTypeData; \
|
||||
qMimeTypeData.loaded = true; \
|
||||
qMimeTypeData.name = std::move(name); \
|
||||
qMimeTypeData.genericIconName = std::move(genericIconName); \
|
||||
qMimeTypeData.iconName = std::move(iconName); \
|
||||
|
@ -201,6 +201,7 @@ bool QMimeTypeParserBase::parse(QIODevice *dev, const QString &fileName, QString
|
||||
return false;
|
||||
#else
|
||||
QMimeTypePrivate data;
|
||||
data.loaded = true;
|
||||
int priority = 50;
|
||||
QStack<QMimeMagicRule *> currentRules; // stack for the nesting of rules
|
||||
QList<QMimeMagicRule> rules; // toplevel rules
|
||||
|
@ -148,7 +148,7 @@ void tst_QMimeDatabase::initTestCase()
|
||||
qDebug() << "\nGlobal XDG_DATA_DIRS: " << m_globalXdgDir;
|
||||
|
||||
const QString freeDesktopXml = QStringLiteral("freedesktop.org.xml");
|
||||
const QString xmlFileName = QLatin1String(RESOURCE_PREFIX) + freeDesktopXml;
|
||||
const QString xmlFileName = QLatin1String(RESOURCE_PREFIX "packages/") + freeDesktopXml;
|
||||
const QString xmlTargetFileName = globalPackageDir + QLatin1Char('/') + freeDesktopXml;
|
||||
QVERIFY2(copyResourceFile(xmlFileName, xmlTargetFileName, &errorMessage), qPrintable(errorMessage));
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user