File indexing completed on 2023-09-24 04:04:53
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 }