File indexing completed on 2024-03-24 15:27:25

0001 /*  This file is part of the KDE libraries
0002  *  Copyright (C) 2006-2007, 2010 David Faure <faure@kde.org>
0003  *
0004  *  This library is free software; you can redistribute it and/or
0005  *  modify it under the terms of the GNU Library General Public
0006  *  License as published by the Free Software Foundation; either
0007  *  version 2 of the License, or (at your option) any later version.
0008  *
0009  *  This library is distributed in the hope that it will be useful,
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012  *  Library General Public License for more details.
0013  *
0014  *  You should have received a copy of the GNU Library General Public License
0015  *  along with this library; see the file COPYING.LIB.  If not, write to
0016  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  *  Boston, MA 02110-1301, USA.
0018  */
0019 
0020 #include "kmimetyperepository_p.h"
0021 #include <kdebug.h>
0022 #include <ksharedconfig.h>
0023 #include <kconfiggroup.h>
0024 #include "kmimetype.h"
0025 #include <kdeversion.h> // KDE_MAKE_VERSION
0026 #include <qstandardpaths.h>
0027 #include <QFile>
0028 #include <QProcess>
0029 
0030 extern int servicesDebugArea();
0031 
0032 class KMimeTypeRepositorySingleton
0033 {
0034 public:
0035     KMimeTypeRepository instance;
0036 };
0037 
0038 Q_GLOBAL_STATIC(KMimeTypeRepositorySingleton, s_self)
0039 
0040 KMimeTypeRepository *KMimeTypeRepository::self()
0041 {
0042     return &s_self()->instance;
0043 }
0044 
0045 KMimeTypeRepository::KMimeTypeRepository()
0046     : m_useFavIcons(true),
0047       m_useFavIconsChecked(false),
0048       m_sharedMimeInfoVersion(0),
0049       m_mutex(QReadWriteLock::Recursive)
0050 {
0051 }
0052 
0053 KMimeTypeRepository::~KMimeTypeRepository()
0054 {
0055 }
0056 
0057 bool KMimeTypeRepository::matchFileName(const QString &filename, const QString &pattern)
0058 {
0059     const int pattern_len = pattern.length();
0060     if (!pattern_len) {
0061         return false;
0062     }
0063     const int len = filename.length();
0064 
0065     const int starCount = pattern.count(QLatin1Char('*'));
0066 
0067     // Patterns like "*~", "*.extension"
0068     if (pattern[0] == QLatin1Char('*')  && pattern.indexOf(QLatin1Char('[')) == -1 && starCount == 1) {
0069         if (len + 1 < pattern_len) {
0070             return false;
0071         }
0072 
0073         const QChar *c1 = pattern.unicode() + pattern_len - 1;
0074         const QChar *c2 = filename.unicode() + len - 1;
0075         int cnt = 1;
0076         while (cnt < pattern_len && *c1-- == *c2--) {
0077             ++cnt;
0078         }
0079         return cnt == pattern_len;
0080     }
0081 
0082     // Patterns like "README*" (well this is currently the only one like that...)
0083     if (starCount == 1 && pattern[pattern_len - 1] == QLatin1Char('*')) {
0084         if (len + 1 < pattern_len) {
0085             return false;
0086         }
0087         if (pattern[0] == QLatin1Char('*')) {
0088             return filename.indexOf(pattern.mid(1, pattern_len - 2)) != -1;
0089         }
0090 
0091         const QChar *c1 = pattern.unicode();
0092         const QChar *c2 = filename.unicode();
0093         int cnt = 1;
0094         while (cnt < pattern_len && *c1++ == *c2++) {
0095             ++cnt;
0096         }
0097         return cnt == pattern_len;
0098     }
0099 
0100     // Names without any wildcards like "README"
0101     if (pattern.indexOf(QLatin1Char('[')) == -1 && starCount == 0 && pattern.indexOf(QLatin1Char('?'))) {
0102         return (pattern == filename);
0103     }
0104 
0105     // Other (quite rare) patterns, like "*.anim[1-9j]": use slow but correct method
0106     QRegExp rx(pattern);
0107     rx.setPatternSyntax(QRegExp::Wildcard);
0108     return rx.exactMatch(filename);
0109 }
0110 
0111 QStringList KMimeTypeRepository::patternsForMimetype(const QString &mimeType)
0112 {
0113     //QWriteLocker lock(&m_mutex);
0114     QMimeType mime = m_mimeDb.mimeTypeForName(mimeType);
0115     return mime.globPatterns();
0116 }
0117 
0118 KMimeType::Ptr KMimeTypeRepository::defaultMimeTypePtr()
0119 {
0120     QWriteLocker lock(&m_mutex);
0121     if (!m_defaultMimeType) {
0122         // Try to find the default type
0123         QMimeType qmime = m_mimeDb.mimeTypeForName(KMimeType::defaultMimeType());
0124         KMimeType::Ptr mime(new KMimeType(qmime));
0125         m_defaultMimeType = mime;
0126     }
0127     return m_defaultMimeType;
0128 }
0129 
0130 bool KMimeTypeRepository::useFavIcons()
0131 {
0132     // this method will be called quite often, so better not read the config
0133     // again and again.
0134     m_mutex.lockForWrite();
0135     if (!m_useFavIconsChecked) {
0136         m_useFavIconsChecked = true;
0137         KConfigGroup cg(KSharedConfig::openConfig(), "HTML Settings");
0138         m_useFavIcons = cg.readEntry("EnableFavicon", true);
0139     }
0140     m_mutex.unlock();
0141     return m_useFavIcons;
0142 }
0143 
0144 static void addPlatformSpecificPkgConfigPath(QStringList &paths)
0145 {
0146 #if defined (Q_OS_FREEBSD)
0147     paths << QLatin1String("/usr/local/libdata/pkgconfig"); // FreeBSD
0148 #elif defined(Q_OS_OPENBSD) || defined(Q_OS_NETBSD) || defined(Q_OS_SOLARIS)
0149     paths << QLatin1String("/usr/local/lib/pkgconfig"); // {Net,Open}BSD/OpenSolaris
0150 #elif defined (Q_OS_UNIX)
0151     paths << QLatin1String("/usr/share/pkgconfig"); // Linux and all other unix
0152 #endif
0153 }
0154 
0155 static int mimeDataBaseVersion()
0156 {
0157     // TODO: Remove the #idef'ed code below once the issue is fixed either
0158     // in QProcess or the shared-mime-info utility provides its version number.
0159 #ifdef Q_OS_UNIX
0160     // Try to read the version number from the shared-mime-info.pc file
0161     QStringList paths;
0162     const QByteArray pkgConfigPath = qgetenv("PKG_CONFIG_PATH");
0163     if (!pkgConfigPath.isEmpty()) {
0164         paths << QFile::decodeName(pkgConfigPath).split(QLatin1Char(':'), QString::SkipEmptyParts);
0165     }
0166 
0167     // Add platform specific hard-coded default paths to the list...
0168     addPlatformSpecificPkgConfigPath(paths);
0169 
0170     Q_FOREACH (const QString &path, paths) {
0171         const QString fileName = path + QLatin1String("/shared-mime-info.pc");
0172         if (!QFile::exists(fileName)) {
0173             continue;
0174         }
0175 
0176         QFile file(fileName);
0177         if (!file.open(QIODevice::ReadOnly)) {
0178             break;
0179         }
0180 
0181         while (!file.atEnd()) {
0182             const QByteArray line = file.readLine().simplified();
0183             if (!line.startsWith("Version")) { // krazy:exclude=strings
0184                 continue;
0185             }
0186             QRegExp versionRe(QString::fromLatin1("Version: (\\d+)\\.(\\d+)(\\.(\\d+))?"));
0187             if (versionRe.indexIn(QString::fromLocal8Bit(line)) > -1) {
0188                 return KDE_MAKE_VERSION(versionRe.cap(1).toInt(), versionRe.cap(2).toInt(), versionRe.cap(4).toInt());
0189             }
0190         }
0191     }
0192 #endif
0193 
0194     // Execute "update-mime-database -v" to determine version number.
0195     // NOTE: On *nix, the code below is known to cause freezes/hangs in apps
0196     // that block signals. See https://bugs.kde.org/show_bug.cgi?id=260719.
0197     const QString umd = QStandardPaths::findExecutable(QString::fromLatin1("update-mime-database"));
0198     if (umd.isEmpty()) {
0199         kWarning() << "update-mime-database not found!";
0200         return -1;
0201     }
0202 
0203     QProcess smi;
0204     smi.start(umd, QStringList() << QString::fromLatin1("-v"));
0205     smi.waitForStarted();
0206     smi.waitForFinished();
0207     const QString out = QString::fromLocal8Bit(smi.readAllStandardError());
0208     QRegExp versionRe(QString::fromLatin1("update-mime-database \\(shared-mime-info\\) (\\d+)\\.(\\d+)(\\.(\\d+))?"));
0209     if (versionRe.indexIn(out) > -1) {
0210         return KDE_MAKE_VERSION(versionRe.cap(1).toInt(), versionRe.cap(2).toInt(), versionRe.cap(4).toInt());
0211     }
0212 
0213     kWarning() << "Unexpected version scheme from update-mime-database -v: got" << out;
0214     return -1;
0215 }
0216 
0217 int KMimeTypeRepository::sharedMimeInfoVersion()
0218 {
0219     m_mutex.lockForWrite();
0220     if (m_sharedMimeInfoVersion == 0) {
0221         m_sharedMimeInfoVersion = mimeDataBaseVersion();
0222     }
0223     m_mutex.unlock();
0224     return m_sharedMimeInfoVersion;
0225 }