kdelibs/kdecore/services/kmimeglobsfileparser.cpp

180 lines
6.7 KiB
C++
Raw Normal View History

2014-11-13 01:04:59 +02:00
/* This file is part of the KDE libraries
* Copyright 2007, 2010 David Faure <faure@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "kmimeglobsfileparser_p.h"
#include <kglobal.h>
#include <kdeversion.h>
#include <kmimetype.h>
#include <kstandarddirs.h>
#include "kmimetyperepository_p.h"
#include <kdebug.h>
#include <QtCore/QTextStream>
#include <QtCore/QFile>
KMimeGlobsFileParser::AllGlobs KMimeGlobsFileParser::parseGlobs()
{
const QStringList globFiles = KGlobal::dirs()->findAllResources("xdgdata-mime", QString::fromLatin1("globs2"));
2014-11-13 01:04:59 +02:00
//kDebug() << globFiles;
return parseGlobs(globFiles);
}
KMimeGlobsFileParser::AllGlobs KMimeGlobsFileParser::parseGlobs(const QStringList &globFiles)
2014-11-13 01:04:59 +02:00
{
KMimeGlobsFileParser::AllGlobs allGlobs;
QListIterator<QString> globIter(globFiles);
globIter.toBack();
// At each level, we must be able to override (not just add to) the information that we read at higher levels
// (if glob-deleteall is used).
while (globIter.hasPrevious()) { // global first, then local
QString fileName = globIter.previous();
QFile globFile(fileName);
//kDebug() << "Now parsing" << fileName;
parseGlobFile(&globFile, allGlobs);
2014-11-13 01:04:59 +02:00
}
return allGlobs;
}
static void filterEmptyFromList(QList<QByteArray>* bytelist)
{
QList<QByteArray>::iterator fieldsit = bytelist->begin();
while (fieldsit != bytelist->end()) {
if (fieldsit->isEmpty()) {
fieldsit = bytelist->erase(fieldsit);
} else {
fieldsit++;
}
}
}
2014-11-13 01:04:59 +02:00
// uses a QIODevice to make unit tests possible
bool KMimeGlobsFileParser::parseGlobFile(QIODevice* file, AllGlobs& globs)
2014-11-13 01:04:59 +02:00
{
Q_ASSERT(file);
if (!file->open(QIODevice::ReadOnly)) {
2014-11-13 01:04:59 +02:00
return false;
}
2014-11-13 01:04:59 +02:00
// for reference:
// https://specifications.freedesktop.org/shared-mime-info-spec/latest/ar01s02.html
// NOTE: the file is supposed to be in UTF-8 encoding however in practise no mime-type entry
// contains non-latin1 characters
QByteArray lastMime, lastPattern;
QByteArray line;
while (!file->atEnd()) {
line = file->readLine().trimmed();
if (line.isEmpty() || line.startsWith('#'))
2014-11-13 01:04:59 +02:00
continue;
// kDebug() << "line=" << line;
QList<QByteArray> fields = line.split(':');
filterEmptyFromList(&fields);
2014-11-13 01:04:59 +02:00
if (fields.count() < 3) // syntax error
continue;
const int weight = fields.at(0).toInt();
const QByteArray mimeTypeName = fields.at(1);
const QByteArray pattern = fields.at(2);
const QByteArray flagsStr = fields.value(3); // could be empty
QList<QByteArray> flagList = flagsStr.split(',');
filterEmptyFromList(&flagList);
2014-11-13 01:04:59 +02:00
Q_ASSERT(!pattern.isEmpty());
Q_ASSERT(!pattern.contains(':'));
2014-11-13 01:04:59 +02:00
// kDebug() << " got:" << mimeTypeName << pattern;
2014-11-13 01:04:59 +02:00
if (lastMime == mimeTypeName && lastPattern == pattern) {
// Ignore duplicates, especially important for those with no flags after a line with flags:
// 50:text/x-csrc:*.c:cs
// 50:text/x-csrc:*.c
continue;
}
bool caseSensitive = flagList.contains(QByteArray("cs"));
2014-11-13 01:04:59 +02:00
const QString mimeTypeNameStr = QString::fromLatin1(mimeTypeName.constData(), mimeTypeName.size());
if (pattern == "__NOGLOBS__") {
// kDebug() << "removing" << mimeTypeName;
globs.removeMime(mimeTypeNameStr);
2014-11-13 01:04:59 +02:00
lastMime.clear();
} else {
//if (mimeTypeName == "text/plain")
// kDebug() << "Adding pattern" << pattern << "to mimetype" << mimeTypeName << "from globs file, with weight" << weight;
//if (pattern.toLower() == "*.c")
// kDebug() << " Adding pattern" << pattern << "to mimetype" << mimeTypeName << "from globs file, with weight" << weight << "flags" << flags;
const QString patternStr = QString::fromLatin1(pattern.constData(), pattern.size());
globs.addGlob(Glob(mimeTypeNameStr, weight, patternStr, caseSensitive));
2014-11-13 01:04:59 +02:00
lastMime = mimeTypeName;
lastPattern = pattern;
}
}
return true;
}
void KMimeGlobsFileParser::AllGlobs::addGlob(const Glob& glob)
{
// Note that in each case, we check for duplicates to avoid inserting duplicated patterns.
// This can happen when installing kde.xml and freedesktop.org.xml
// in the same prefix, and they both have text/plain:*.txt
const QString &pattern = glob.pattern;
Q_ASSERT(!pattern.isEmpty());
Q_UNUSED(pattern);
2014-11-13 01:04:59 +02:00
//kDebug() << "pattern" << pattern << "glob.weight=" << glob.weight << glob.flags;
2014-11-13 01:04:59 +02:00
// 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)
Glob adjustedGlob(glob);
if (!adjustedGlob.casesensitive)
adjustedGlob.pattern = adjustedGlob.pattern.toLower();
if (adjustedGlob.weight >= 50) {
if (!m_highWeightGlobs.hasPattern(adjustedGlob.mimeType, adjustedGlob.pattern))
m_highWeightGlobs.append(adjustedGlob);
2014-11-13 01:04:59 +02:00
} else {
if (!m_lowWeightGlobs.hasPattern(adjustedGlob.mimeType, adjustedGlob.pattern))
m_lowWeightGlobs.append(adjustedGlob);
2014-11-13 01:04:59 +02:00
}
}
KMimeGlobsFileParser::PatternsMap KMimeGlobsFileParser::AllGlobs::patternsMap() const
{
PatternsMap patMap;
patMap.reserve(m_highWeightGlobs.size() + m_lowWeightGlobs.size());
2014-11-13 01:04:59 +02:00
// This is just to fill in KMimeType::patterns. This has no real effect
// on the actual mimetype matching.
Q_FOREACH(const Glob& glob, m_highWeightGlobs)
patMap[glob.mimeType].append(glob.pattern);
Q_FOREACH(const Glob& glob, m_lowWeightGlobs)
patMap[glob.mimeType].append(glob.pattern);
return patMap;
}
void KMimeGlobsFileParser::AllGlobs::removeMime(const QString& mime)
{
m_highWeightGlobs.removeMime(mime);
m_lowWeightGlobs.removeMime(mime);
}