Absolute File Name: | /home/qt/qt5_coco/qt5/qtbase/src/corelib/mimetypes/qmimeprovider.cpp |
Source code | Switch to Preprocessed file |
Line | Source | Count | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | /**************************************************************************** | - | ||||||||||||||||||
2 | ** | - | ||||||||||||||||||
3 | ** Copyright (C) 2016 The Qt Company Ltd. | - | ||||||||||||||||||
4 | ** Copyright (C) 2015 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com> | - | ||||||||||||||||||
5 | ** Contact: https://www.qt.io/licensing/ | - | ||||||||||||||||||
6 | ** | - | ||||||||||||||||||
7 | ** This file is part of the QtCore module of the Qt Toolkit. | - | ||||||||||||||||||
8 | ** | - | ||||||||||||||||||
9 | ** $QT_BEGIN_LICENSE:LGPL$ | - | ||||||||||||||||||
10 | ** Commercial License Usage | - | ||||||||||||||||||
11 | ** Licensees holding valid commercial Qt licenses may use this file in | - | ||||||||||||||||||
12 | ** accordance with the commercial license agreement provided with the | - | ||||||||||||||||||
13 | ** Software or, alternatively, in accordance with the terms contained in | - | ||||||||||||||||||
14 | ** a written agreement between you and The Qt Company. For licensing terms | - | ||||||||||||||||||
15 | ** and conditions see https://www.qt.io/terms-conditions. For further | - | ||||||||||||||||||
16 | ** information use the contact form at https://www.qt.io/contact-us. | - | ||||||||||||||||||
17 | ** | - | ||||||||||||||||||
18 | ** GNU Lesser General Public License Usage | - | ||||||||||||||||||
19 | ** Alternatively, this file may be used under the terms of the GNU Lesser | - | ||||||||||||||||||
20 | ** General Public License version 3 as published by the Free Software | - | ||||||||||||||||||
21 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the | - | ||||||||||||||||||
22 | ** packaging of this file. Please review the following information to | - | ||||||||||||||||||
23 | ** ensure the GNU Lesser General Public License version 3 requirements | - | ||||||||||||||||||
24 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. | - | ||||||||||||||||||
25 | ** | - | ||||||||||||||||||
26 | ** GNU General Public License Usage | - | ||||||||||||||||||
27 | ** Alternatively, this file may be used under the terms of the GNU | - | ||||||||||||||||||
28 | ** General Public License version 2.0 or (at your option) the GNU General | - | ||||||||||||||||||
29 | ** Public license version 3 or any later version approved by the KDE Free | - | ||||||||||||||||||
30 | ** Qt Foundation. The licenses are as published by the Free Software | - | ||||||||||||||||||
31 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 | - | ||||||||||||||||||
32 | ** included in the packaging of this file. Please review the following | - | ||||||||||||||||||
33 | ** information to ensure the GNU General Public License requirements will | - | ||||||||||||||||||
34 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and | - | ||||||||||||||||||
35 | ** https://www.gnu.org/licenses/gpl-3.0.html. | - | ||||||||||||||||||
36 | ** | - | ||||||||||||||||||
37 | ** $QT_END_LICENSE$ | - | ||||||||||||||||||
38 | ** | - | ||||||||||||||||||
39 | ****************************************************************************/ | - | ||||||||||||||||||
40 | - | |||||||||||||||||||
41 | #include "qmimeprovider_p.h" | - | ||||||||||||||||||
42 | - | |||||||||||||||||||
43 | #ifndef QT_NO_MIMETYPE | - | ||||||||||||||||||
44 | - | |||||||||||||||||||
45 | #include "qmimetypeparser_p.h" | - | ||||||||||||||||||
46 | #include <qstandardpaths.h> | - | ||||||||||||||||||
47 | #include "qmimemagicrulematcher_p.h" | - | ||||||||||||||||||
48 | - | |||||||||||||||||||
49 | #include <QXmlStreamReader> | - | ||||||||||||||||||
50 | #include <QDir> | - | ||||||||||||||||||
51 | #include <QFile> | - | ||||||||||||||||||
52 | #include <QByteArrayMatcher> | - | ||||||||||||||||||
53 | #include <QDebug> | - | ||||||||||||||||||
54 | #include <QDateTime> | - | ||||||||||||||||||
55 | #include <QtEndian> | - | ||||||||||||||||||
56 | - | |||||||||||||||||||
57 | static void initResources() | - | ||||||||||||||||||
58 | { | - | ||||||||||||||||||
59 | Q_INIT_RESOURCE(mimetypes); | - | ||||||||||||||||||
60 | } | - | ||||||||||||||||||
61 | - | |||||||||||||||||||
62 | QT_BEGIN_NAMESPACE | - | ||||||||||||||||||
63 | - | |||||||||||||||||||
64 | static QString fallbackParent(const QString &mimeTypeName) | - | ||||||||||||||||||
65 | { | - | ||||||||||||||||||
66 | const QString myGroup = mimeTypeName.left(mimeTypeName.indexOf(QLatin1Char('/'))); | - | ||||||||||||||||||
67 | // All text/* types are subclasses of text/plain. | - | ||||||||||||||||||
68 | if (myGroup == QLatin1String("text") && mimeTypeName != QLatin1String("text/plain")) | - | ||||||||||||||||||
69 | return QLatin1String("text/plain"); | - | ||||||||||||||||||
70 | // All real-file mimetypes implicitly derive from application/octet-stream | - | ||||||||||||||||||
71 | if (myGroup != QLatin1String("inode") && | - | ||||||||||||||||||
72 | // ignore non-file extensions | - | ||||||||||||||||||
73 | myGroup != QLatin1String("all") && myGroup != QLatin1String("fonts") && myGroup != QLatin1String("print") && myGroup != QLatin1String("uri") | - | ||||||||||||||||||
74 | && mimeTypeName != QLatin1String("application/octet-stream")) { | - | ||||||||||||||||||
75 | return QLatin1String("application/octet-stream"); | - | ||||||||||||||||||
76 | } | - | ||||||||||||||||||
77 | return QString(); | - | ||||||||||||||||||
78 | } | - | ||||||||||||||||||
79 | - | |||||||||||||||||||
80 | QMimeProviderBase::QMimeProviderBase(QMimeDatabasePrivate *db) | - | ||||||||||||||||||
81 | : m_db(db) | - | ||||||||||||||||||
82 | { | - | ||||||||||||||||||
83 | } | - | ||||||||||||||||||
84 | - | |||||||||||||||||||
85 | Q_CORE_EXPORT int qmime_secondsBetweenChecks = 5; // exported for the unit test | - | ||||||||||||||||||
86 | - | |||||||||||||||||||
87 | bool QMimeProviderBase::shouldCheck() | - | ||||||||||||||||||
88 | { | - | ||||||||||||||||||
89 | if (m_lastCheck.isValid() && m_lastCheck.elapsed() < qmime_secondsBetweenChecks * 1000) | - | ||||||||||||||||||
90 | return false; | - | ||||||||||||||||||
91 | m_lastCheck.start(); | - | ||||||||||||||||||
92 | return true; | - | ||||||||||||||||||
93 | } | - | ||||||||||||||||||
94 | - | |||||||||||||||||||
95 | QMimeBinaryProvider::QMimeBinaryProvider(QMimeDatabasePrivate *db) | - | ||||||||||||||||||
96 | : QMimeProviderBase(db), m_mimetypeListLoaded(false) | - | ||||||||||||||||||
97 | { | - | ||||||||||||||||||
98 | } | - | ||||||||||||||||||
99 | - | |||||||||||||||||||
100 | #if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY) | - | ||||||||||||||||||
101 | #define QT_USE_MMAP | - | ||||||||||||||||||
102 | #endif | - | ||||||||||||||||||
103 | - | |||||||||||||||||||
104 | struct QMimeBinaryProvider::CacheFile | - | ||||||||||||||||||
105 | { | - | ||||||||||||||||||
106 | CacheFile(const QString &fileName); | - | ||||||||||||||||||
107 | ~CacheFile(); | - | ||||||||||||||||||
108 | - | |||||||||||||||||||
109 | bool isValid() const { return m_valid; } | - | ||||||||||||||||||
110 | inline quint16 getUint16(int offset) const | - | ||||||||||||||||||
111 | { | - | ||||||||||||||||||
112 | return qFromBigEndian(*reinterpret_cast<quint16 *>(data + offset)); | - | ||||||||||||||||||
113 | } | - | ||||||||||||||||||
114 | inline quint32 getUint32(int offset) const | - | ||||||||||||||||||
115 | { | - | ||||||||||||||||||
116 | return qFromBigEndian(*reinterpret_cast<quint32 *>(data + offset)); | - | ||||||||||||||||||
117 | } | - | ||||||||||||||||||
118 | inline const char *getCharStar(int offset) const | - | ||||||||||||||||||
119 | { | - | ||||||||||||||||||
120 | return reinterpret_cast<const char *>(data + offset); | - | ||||||||||||||||||
121 | } | - | ||||||||||||||||||
122 | bool load(); | - | ||||||||||||||||||
123 | bool reload(); | - | ||||||||||||||||||
124 | - | |||||||||||||||||||
125 | QFile file; | - | ||||||||||||||||||
126 | uchar *data; | - | ||||||||||||||||||
127 | QDateTime m_mtime; | - | ||||||||||||||||||
128 | bool m_valid; | - | ||||||||||||||||||
129 | }; | - | ||||||||||||||||||
130 | - | |||||||||||||||||||
131 | QMimeBinaryProvider::CacheFile::CacheFile(const QString &fileName) | - | ||||||||||||||||||
132 | : file(fileName), m_valid(false) | - | ||||||||||||||||||
133 | { | - | ||||||||||||||||||
134 | load(); | - | ||||||||||||||||||
135 | } | - | ||||||||||||||||||
136 | - | |||||||||||||||||||
137 | QMimeBinaryProvider::CacheFile::~CacheFile() | - | ||||||||||||||||||
138 | { | - | ||||||||||||||||||
139 | } | - | ||||||||||||||||||
140 | - | |||||||||||||||||||
141 | bool QMimeBinaryProvider::CacheFile::load() | - | ||||||||||||||||||
142 | { | - | ||||||||||||||||||
143 | if (!file.open(QIODevice::ReadOnly)) | - | ||||||||||||||||||
144 | return false; | - | ||||||||||||||||||
145 | data = file.map(0, file.size()); | - | ||||||||||||||||||
146 | if (data) { | - | ||||||||||||||||||
147 | const int major = getUint16(0); | - | ||||||||||||||||||
148 | const int minor = getUint16(2); | - | ||||||||||||||||||
149 | m_valid = (major == 1 && minor >= 1 && minor <= 2); | - | ||||||||||||||||||
150 | } | - | ||||||||||||||||||
151 | m_mtime = QFileInfo(file).lastModified(); | - | ||||||||||||||||||
152 | return m_valid; | - | ||||||||||||||||||
153 | } | - | ||||||||||||||||||
154 | - | |||||||||||||||||||
155 | bool QMimeBinaryProvider::CacheFile::reload() | - | ||||||||||||||||||
156 | { | - | ||||||||||||||||||
157 | //qDebug() << "reload!" << file->fileName(); | - | ||||||||||||||||||
158 | m_valid = false; | - | ||||||||||||||||||
159 | if (file.isOpen()) { | - | ||||||||||||||||||
160 | file.close(); | - | ||||||||||||||||||
161 | } | - | ||||||||||||||||||
162 | data = 0; | - | ||||||||||||||||||
163 | return load(); | - | ||||||||||||||||||
164 | } | - | ||||||||||||||||||
165 | - | |||||||||||||||||||
166 | QMimeBinaryProvider::CacheFile *QMimeBinaryProvider::CacheFileList::findCacheFile(const QString &fileName) const | - | ||||||||||||||||||
167 | { | - | ||||||||||||||||||
168 | for (const_iterator it = begin(); it != end(); ++it) { | - | ||||||||||||||||||
169 | if ((*it)->file.fileName() == fileName) | - | ||||||||||||||||||
170 | return *it; | - | ||||||||||||||||||
171 | } | - | ||||||||||||||||||
172 | return 0; | - | ||||||||||||||||||
173 | } | - | ||||||||||||||||||
174 | - | |||||||||||||||||||
175 | QMimeBinaryProvider::~QMimeBinaryProvider() | - | ||||||||||||||||||
176 | { | - | ||||||||||||||||||
177 | qDeleteAll(m_cacheFiles); | - | ||||||||||||||||||
178 | } | - | ||||||||||||||||||
179 | - | |||||||||||||||||||
180 | // Position of the "list offsets" values, at the beginning of the mime.cache file | - | ||||||||||||||||||
181 | enum { | - | ||||||||||||||||||
182 | PosAliasListOffset = 4, | - | ||||||||||||||||||
183 | PosParentListOffset = 8, | - | ||||||||||||||||||
184 | PosLiteralListOffset = 12, | - | ||||||||||||||||||
185 | PosReverseSuffixTreeOffset = 16, | - | ||||||||||||||||||
186 | PosGlobListOffset = 20, | - | ||||||||||||||||||
187 | PosMagicListOffset = 24, | - | ||||||||||||||||||
188 | // PosNamespaceListOffset = 28, | - | ||||||||||||||||||
189 | PosIconsListOffset = 32, | - | ||||||||||||||||||
190 | PosGenericIconsListOffset = 36 | - | ||||||||||||||||||
191 | }; | - | ||||||||||||||||||
192 | - | |||||||||||||||||||
193 | bool QMimeBinaryProvider::isValid() | - | ||||||||||||||||||
194 | { | - | ||||||||||||||||||
195 | #if defined(QT_USE_MMAP) | - | ||||||||||||||||||
196 | if (!qEnvironmentVariableIsEmpty("QT_NO_MIME_CACHE"))
| 1-24 | ||||||||||||||||||
197 | return false; executed 1 time by 1 test: return false; Executed by:
| 1 | ||||||||||||||||||
198 | - | |||||||||||||||||||
199 | Q_ASSERT(m_cacheFiles.isEmpty()); // this method is only ever called once | - | ||||||||||||||||||
200 | checkCache(); | - | ||||||||||||||||||
201 | - | |||||||||||||||||||
202 | if (m_cacheFiles.count() > 1)
| 0-24 | ||||||||||||||||||
203 | return true; never executed: return true; | 0 | ||||||||||||||||||
204 | if (m_cacheFiles.isEmpty())
| 1-23 | ||||||||||||||||||
205 | return false; executed 1 time by 1 test: return false; Executed by:
| 1 | ||||||||||||||||||
206 | - | |||||||||||||||||||
207 | // We found exactly one file; is it the user-modified mimes, or a system file? | - | ||||||||||||||||||
208 | const QString foundFile = m_cacheFiles.firstconstFirst()->file.fileName(); | - | ||||||||||||||||||
209 | const QString localCacheFile = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/mime/mime.cache"); | - | ||||||||||||||||||
210 | - | |||||||||||||||||||
211 | return foundFile != localCacheFile; executed 23 times by 23 tests: return foundFile != localCacheFile; Executed by:
| 23 | ||||||||||||||||||
212 | #else | - | ||||||||||||||||||
213 | return false; | - | ||||||||||||||||||
214 | #endif | - | ||||||||||||||||||
215 | } | - | ||||||||||||||||||
216 | - | |||||||||||||||||||
217 | bool QMimeBinaryProvider::CacheFileList::checkCacheChanged() | - | ||||||||||||||||||
218 | { | - | ||||||||||||||||||
219 | bool somethingChanged = false; | - | ||||||||||||||||||
220 | QMutableListIterator<CacheFile *> it(*this); | - | ||||||||||||||||||
221 | while (it.hasNext()) { | - | ||||||||||||||||||
222 | CacheFile *cacheFile = it.next(); | - | ||||||||||||||||||
223 | QFileInfo fileInfo(cacheFile->file); | - | ||||||||||||||||||
224 | if (!fileInfo.exists()) { // This can't happen by just running update-mime-database. But the user could use rm -rf :-) | - | ||||||||||||||||||
225 | delete cacheFile; | - | ||||||||||||||||||
226 | it.remove(); | - | ||||||||||||||||||
227 | somethingChanged = true; | - | ||||||||||||||||||
228 | } else if (fileInfo.lastModified() > cacheFile->m_mtime) { | - | ||||||||||||||||||
229 | if (!cacheFile->reload()) { | - | ||||||||||||||||||
230 | delete cacheFile; | - | ||||||||||||||||||
231 | it.remove(); | - | ||||||||||||||||||
232 | } | - | ||||||||||||||||||
233 | somethingChanged = true; | - | ||||||||||||||||||
234 | } | - | ||||||||||||||||||
235 | } | - | ||||||||||||||||||
236 | return somethingChanged; | - | ||||||||||||||||||
237 | } | - | ||||||||||||||||||
238 | - | |||||||||||||||||||
239 | void QMimeBinaryProvider::checkCache() | - | ||||||||||||||||||
240 | { | - | ||||||||||||||||||
241 | if (!shouldCheck())
| 96-11745 | ||||||||||||||||||
242 | return; executed 11745 times by 23 tests: return; Executed by:
| 11745 | ||||||||||||||||||
243 | - | |||||||||||||||||||
244 | // First iterate over existing known cache files and check for uptodate | - | ||||||||||||||||||
245 | if (m_cacheFiles.checkCacheChanged())
| 4-92 | ||||||||||||||||||
246 | m_mimetypeListLoaded = false; executed 4 times by 1 test: m_mimetypeListLoaded = false; Executed by:
| 4 | ||||||||||||||||||
247 | - | |||||||||||||||||||
248 | // Then check if new cache files appeared | - | ||||||||||||||||||
249 | const QStringList cacheFileNames = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QLatin1String("mime/mime.cache")); | - | ||||||||||||||||||
250 | if (cacheFileNames != m_cacheFileNames) {
| 25-71 | ||||||||||||||||||
251 | foreachfor (const QString &cacheFileName ,: cacheFileNames) { | - | ||||||||||||||||||
252 | CacheFile *cacheFile = m_cacheFiles.findCacheFile(cacheFileName); | - | ||||||||||||||||||
253 | if (!cacheFile) {
| 2-24 | ||||||||||||||||||
254 | //qDebug() << "new file:" << cacheFileName; | - | ||||||||||||||||||
255 | cacheFile = new CacheFile(cacheFileName); | - | ||||||||||||||||||
256 | if (cacheFile->isValid()) // verify version
| 0-24 | ||||||||||||||||||
257 | m_cacheFiles.append(cacheFile); executed 24 times by 23 tests: m_cacheFiles.append(cacheFile); Executed by:
| 24 | ||||||||||||||||||
258 | else | - | ||||||||||||||||||
259 | delete cacheFile; never executed: delete cacheFile; | 0 | ||||||||||||||||||
260 | } | - | ||||||||||||||||||
261 | } executed 26 times by 23 tests: end of block Executed by:
| 26 | ||||||||||||||||||
262 | m_cacheFileNames = cacheFileNames; | - | ||||||||||||||||||
263 | m_mimetypeListLoaded = false; | - | ||||||||||||||||||
264 | } executed 25 times by 23 tests: end of block Executed by:
| 25 | ||||||||||||||||||
265 | } executed 96 times by 24 tests: end of block Executed by:
| 96 | ||||||||||||||||||
266 | - | |||||||||||||||||||
267 | static QMimeType mimeTypeForNameUnchecked(const QString &name) | - | ||||||||||||||||||
268 | { | - | ||||||||||||||||||
269 | QMimeTypePrivate data; | - | ||||||||||||||||||
270 | data.name = name; | - | ||||||||||||||||||
271 | // The rest is retrieved on demand. | - | ||||||||||||||||||
272 | // comment and globPatterns: in loadMimeTypePrivate | - | ||||||||||||||||||
273 | // iconName: in loadIcon | - | ||||||||||||||||||
274 | // genericIconName: in loadGenericIcon | - | ||||||||||||||||||
275 | return QMimeType(data); | - | ||||||||||||||||||
276 | } | - | ||||||||||||||||||
277 | - | |||||||||||||||||||
278 | QMimeType QMimeBinaryProvider::mimeTypeForName(const QString &name) | - | ||||||||||||||||||
279 | { | - | ||||||||||||||||||
280 | checkCache(); | - | ||||||||||||||||||
281 | if (!m_mimetypeListLoaded) | - | ||||||||||||||||||
282 | loadMimeTypeList(); | - | ||||||||||||||||||
283 | if (!m_mimetypeNames.contains(name)) | - | ||||||||||||||||||
284 | return QMimeType(); // unknown mimetype | - | ||||||||||||||||||
285 | return mimeTypeForNameUnchecked(name); | - | ||||||||||||||||||
286 | } | - | ||||||||||||||||||
287 | - | |||||||||||||||||||
288 | QStringList QMimeBinaryProvider::findByFileName(const QString &fileName, QString *foundSuffix) | - | ||||||||||||||||||
289 | { | - | ||||||||||||||||||
290 | checkCache(); | - | ||||||||||||||||||
291 | if (fileName.isEmpty())
| 2-2523 | ||||||||||||||||||
292 | return QStringList(); executed 2 times by 1 test: return QStringList(); Executed by:
| 2 | ||||||||||||||||||
293 | const QString lowerFileName = fileName.toLower(); | - | ||||||||||||||||||
294 | QMimeGlobMatchResult result; | - | ||||||||||||||||||
295 | // TODO this parses in the order (local, global). Check that it handles "NOGLOBS" correctly. | - | ||||||||||||||||||
296 | foreachfor (CacheFile *cacheFile ,: qAsConst(m_cacheFiles))) { | - | ||||||||||||||||||
297 | matchGlobList(result, cacheFile, cacheFile->getUint32(PosLiteralListOffset), fileName); | - | ||||||||||||||||||
298 | matchGlobList(result, cacheFile, cacheFile->getUint32(PosGlobListOffset), fileName); | - | ||||||||||||||||||
299 | const int reverseSuffixTreeOffset = cacheFile->getUint32(PosReverseSuffixTreeOffset); | - | ||||||||||||||||||
300 | const int numRoots = cacheFile->getUint32(reverseSuffixTreeOffset); | - | ||||||||||||||||||
301 | const int firstRootOffset = cacheFile->getUint32(reverseSuffixTreeOffset + 4); | - | ||||||||||||||||||
302 | matchSuffixTree(result, cacheFile, numRoots, firstRootOffset, lowerFileName, fileName.length() - 1, false); | - | ||||||||||||||||||
303 | if (result.m_matchingMimeTypes.isEmpty())
| 34-2492 | ||||||||||||||||||
304 | matchSuffixTree(result, cacheFile, numRoots, firstRootOffset, fileName, fileName.length() - 1, true); executed 34 times by 3 tests: matchSuffixTree(result, cacheFile, numRoots, firstRootOffset, fileName, fileName.length() - 1, true); Executed by:
| 34 | ||||||||||||||||||
305 | } executed 2526 times by 22 tests: end of block Executed by:
| 2526 | ||||||||||||||||||
306 | if (foundSuffix)
| 8-2515 | ||||||||||||||||||
307 | *foundSuffix = result.m_foundSuffix; executed 8 times by 1 test: *foundSuffix = result.m_foundSuffix; Executed by:
| 8 | ||||||||||||||||||
308 | return result.m_matchingMimeTypes; executed 2523 times by 22 tests: return result.m_matchingMimeTypes; Executed by:
| 2523 | ||||||||||||||||||
309 | } | - | ||||||||||||||||||
310 | - | |||||||||||||||||||
311 | void QMimeBinaryProvider::matchGlobList(QMimeGlobMatchResult &result, CacheFile *cacheFile, int off, const QString &fileName) | - | ||||||||||||||||||
312 | { | - | ||||||||||||||||||
313 | const int numGlobs = cacheFile->getUint32(off); | - | ||||||||||||||||||
314 | //qDebug() << "Loading" << numGlobs << "globs from" << cacheFile->file.fileName() << "at offset" << cacheFile->globListOffset; | - | ||||||||||||||||||
315 | for (int i = 0; i < numGlobs; ++i) { | - | ||||||||||||||||||
316 | const int globOffset = cacheFile->getUint32(off + 4 + 12 * i); | - | ||||||||||||||||||
317 | const int mimeTypeOffset = cacheFile->getUint32(off + 4 + 12 * i + 4); | - | ||||||||||||||||||
318 | const int flagsAndWeight = cacheFile->getUint32(off + 4 + 12 * i + 8); | - | ||||||||||||||||||
319 | const int weight = flagsAndWeight & 0xff; | - | ||||||||||||||||||
320 | const bool caseSensitive = flagsAndWeight & 0x100; | - | ||||||||||||||||||
321 | const Qt::CaseSensitivity qtCaseSensitive = caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive; | - | ||||||||||||||||||
322 | const QString pattern = QLatin1String(cacheFile->getCharStar(globOffset)); | - | ||||||||||||||||||
323 | - | |||||||||||||||||||
324 | const char *mimeType = cacheFile->getCharStar(mimeTypeOffset); | - | ||||||||||||||||||
325 | //qDebug() << pattern << mimeType << weight << caseSensitive; | - | ||||||||||||||||||
326 | QMimeGlobPattern glob(pattern, QString() /*unused*/, weight, qtCaseSensitive); | - | ||||||||||||||||||
327 | - | |||||||||||||||||||
328 | // TODO: this could be done faster for literals where a simple == would do. | - | ||||||||||||||||||
329 | if (glob.matchFileName(fileName)) | - | ||||||||||||||||||
330 | result.addMatch(QLatin1String(mimeType), weight, pattern); | - | ||||||||||||||||||
331 | } | - | ||||||||||||||||||
332 | } | - | ||||||||||||||||||
333 | - | |||||||||||||||||||
334 | bool QMimeBinaryProvider::matchSuffixTree(QMimeGlobMatchResult &result, QMimeBinaryProvider::CacheFile *cacheFile, int numEntries, int firstOffset, const QString &fileName, int charPos, bool caseSensitiveCheck) | - | ||||||||||||||||||
335 | { | - | ||||||||||||||||||
336 | QChar fileChar = fileName[charPos]; | - | ||||||||||||||||||
337 | int min = 0; | - | ||||||||||||||||||
338 | int max = numEntries - 1; | - | ||||||||||||||||||
339 | while (min <= max) { | - | ||||||||||||||||||
340 | const int mid = (min + max) / 2; | - | ||||||||||||||||||
341 | const int off = firstOffset + 12 * mid; | - | ||||||||||||||||||
342 | const QChar ch = cacheFile->getUint32(off); | - | ||||||||||||||||||
343 | if (ch < fileChar) | - | ||||||||||||||||||
344 | min = mid + 1; | - | ||||||||||||||||||
345 | else if (ch > fileChar) | - | ||||||||||||||||||
346 | max = mid - 1; | - | ||||||||||||||||||
347 | else { | - | ||||||||||||||||||
348 | --charPos; | - | ||||||||||||||||||
349 | int numChildren = cacheFile->getUint32(off + 4); | - | ||||||||||||||||||
350 | int childrenOffset = cacheFile->getUint32(off + 8); | - | ||||||||||||||||||
351 | bool success = false; | - | ||||||||||||||||||
352 | if (charPos > 0) | - | ||||||||||||||||||
353 | success = matchSuffixTree(result, cacheFile, numChildren, childrenOffset, fileName, charPos, caseSensitiveCheck); | - | ||||||||||||||||||
354 | if (!success) { | - | ||||||||||||||||||
355 | for (int i = 0; i < numChildren; ++i) { | - | ||||||||||||||||||
356 | const int childOff = childrenOffset + 12 * i; | - | ||||||||||||||||||
357 | const int mch = cacheFile->getUint32(childOff); | - | ||||||||||||||||||
358 | if (mch != 0) | - | ||||||||||||||||||
359 | break; | - | ||||||||||||||||||
360 | const int mimeTypeOffset = cacheFile->getUint32(childOff + 4); | - | ||||||||||||||||||
361 | const char *mimeType = cacheFile->getCharStar(mimeTypeOffset); | - | ||||||||||||||||||
362 | const int flagsAndWeight = cacheFile->getUint32(childOff + 8); | - | ||||||||||||||||||
363 | const int weight = flagsAndWeight & 0xff; | - | ||||||||||||||||||
364 | const bool caseSensitive = flagsAndWeight & 0x100; | - | ||||||||||||||||||
365 | if (caseSensitiveCheck || !caseSensitive) { | - | ||||||||||||||||||
366 | result.addMatch(QLatin1String(mimeType), weight, QLatin1Char('*') + fileName.mid(charPos+1)); | - | ||||||||||||||||||
367 | success = true; | - | ||||||||||||||||||
368 | } | - | ||||||||||||||||||
369 | } | - | ||||||||||||||||||
370 | } | - | ||||||||||||||||||
371 | return success; | - | ||||||||||||||||||
372 | } | - | ||||||||||||||||||
373 | } | - | ||||||||||||||||||
374 | return false; | - | ||||||||||||||||||
375 | } | - | ||||||||||||||||||
376 | - | |||||||||||||||||||
377 | bool QMimeBinaryProvider::matchMagicRule(QMimeBinaryProvider::CacheFile *cacheFile, int numMatchlets, int firstOffset, const QByteArray &data) | - | ||||||||||||||||||
378 | { | - | ||||||||||||||||||
379 | const char *dataPtr = data.constData(); | - | ||||||||||||||||||
380 | const int dataSize = data.size(); | - | ||||||||||||||||||
381 | for (int matchlet = 0; matchlet < numMatchlets; ++matchlet) { | - | ||||||||||||||||||
382 | const int off = firstOffset + matchlet * 32; | - | ||||||||||||||||||
383 | const int rangeStart = cacheFile->getUint32(off); | - | ||||||||||||||||||
384 | const int rangeLength = cacheFile->getUint32(off + 4); | - | ||||||||||||||||||
385 | //const int wordSize = cacheFile->getUint32(off + 8); | - | ||||||||||||||||||
386 | const int valueLength = cacheFile->getUint32(off + 12); | - | ||||||||||||||||||
387 | const int valueOffset = cacheFile->getUint32(off + 16); | - | ||||||||||||||||||
388 | const int maskOffset = cacheFile->getUint32(off + 20); | - | ||||||||||||||||||
389 | const char *mask = maskOffset ? cacheFile->getCharStar(maskOffset) : NULL; | - | ||||||||||||||||||
390 | - | |||||||||||||||||||
391 | if (!QMimeMagicRule::matchSubstring(dataPtr, dataSize, rangeStart, rangeLength, valueLength, cacheFile->getCharStar(valueOffset), mask)) | - | ||||||||||||||||||
392 | continue; | - | ||||||||||||||||||
393 | - | |||||||||||||||||||
394 | const int numChildren = cacheFile->getUint32(off + 24); | - | ||||||||||||||||||
395 | const int firstChildOffset = cacheFile->getUint32(off + 28); | - | ||||||||||||||||||
396 | if (numChildren == 0) // No submatch? Then we are done. | - | ||||||||||||||||||
397 | return true; | - | ||||||||||||||||||
398 | // Check that one of the submatches matches too | - | ||||||||||||||||||
399 | if (matchMagicRule(cacheFile, numChildren, firstChildOffset, data)) | - | ||||||||||||||||||
400 | return true; | - | ||||||||||||||||||
401 | } | - | ||||||||||||||||||
402 | return false; | - | ||||||||||||||||||
403 | } | - | ||||||||||||||||||
404 | - | |||||||||||||||||||
405 | QMimeType QMimeBinaryProvider::findByMagic(const QByteArray &data, int *accuracyPtr) | - | ||||||||||||||||||
406 | { | - | ||||||||||||||||||
407 | checkCache(); | - | ||||||||||||||||||
408 | foreachfor (CacheFile *cacheFile ,: qAsConst(m_cacheFiles))) { | - | ||||||||||||||||||
409 | const int magicListOffset = cacheFile->getUint32(PosMagicListOffset); | - | ||||||||||||||||||
410 | const int numMatches = cacheFile->getUint32(magicListOffset); | - | ||||||||||||||||||
411 | //const int maxExtent = cacheFile->getUint32(magicListOffset + 4); | - | ||||||||||||||||||
412 | const int firstMatchOffset = cacheFile->getUint32(magicListOffset + 8); | - | ||||||||||||||||||
413 | - | |||||||||||||||||||
414 | for (int i = 0; i < numMatches; ++i) {
| 9-5895 | ||||||||||||||||||
415 | const int off = firstMatchOffset + i * 16; | - | ||||||||||||||||||
416 | const int numMatchlets = cacheFile->getUint32(off + 8); | - | ||||||||||||||||||
417 | const int firstMatchletOffset = cacheFile->getUint32(off + 12); | - | ||||||||||||||||||
418 | if (matchMagicRule(cacheFile, numMatchlets, firstMatchletOffset, data)) {
| 23-5872 | ||||||||||||||||||
419 | const int mimeTypeOffset = cacheFile->getUint32(off + 4); | - | ||||||||||||||||||
420 | const char *mimeType = cacheFile->getCharStar(mimeTypeOffset); | - | ||||||||||||||||||
421 | *accuracyPtr = cacheFile->getUint32(off); | - | ||||||||||||||||||
422 | // Return the first match. We have no rules for conflicting magic data... | - | ||||||||||||||||||
423 | // (mime.cache itself is sorted, but what about local overrides with a lower prio?) | - | ||||||||||||||||||
424 | return mimeTypeForNameUnchecked(QLatin1String(mimeType)); executed 23 times by 1 test: return mimeTypeForNameUnchecked(QLatin1String(mimeType)); Executed by:
| 23 | ||||||||||||||||||
425 | } | - | ||||||||||||||||||
426 | } executed 5872 times by 1 test: end of block Executed by:
| 5872 | ||||||||||||||||||
427 | } executed 9 times by 1 test: end of block Executed by:
| 9 | ||||||||||||||||||
428 | return QMimeType(); executed 9 times by 1 test: return QMimeType(); Executed by:
| 9 | ||||||||||||||||||
429 | } | - | ||||||||||||||||||
430 | - | |||||||||||||||||||
431 | QStringList QMimeBinaryProvider::parents(const QString &mime) | - | ||||||||||||||||||
432 | { | - | ||||||||||||||||||
433 | checkCache(); | - | ||||||||||||||||||
434 | const QByteArray mimeStr = mime.toLatin1(); | - | ||||||||||||||||||
435 | QStringList result; | - | ||||||||||||||||||
436 | foreachfor (CacheFile *cacheFile ,: qAsConst(m_cacheFiles))) { | - | ||||||||||||||||||
437 | const int parentListOffset = cacheFile->getUint32(PosParentListOffset); | - | ||||||||||||||||||
438 | const int numEntries = cacheFile->getUint32(parentListOffset); | - | ||||||||||||||||||
439 | - | |||||||||||||||||||
440 | int begin = 0; | - | ||||||||||||||||||
441 | int end = numEntries - 1; | - | ||||||||||||||||||
442 | while (begin <= end) {
| 34-466 | ||||||||||||||||||
443 | const int medium = (begin + end) / 2; | - | ||||||||||||||||||
444 | const int off = parentListOffset + 4 + 8 * medium; | - | ||||||||||||||||||
445 | const int mimeOffset = cacheFile->getUint32(off); | - | ||||||||||||||||||
446 | const char *aMime = cacheFile->getCharStar(mimeOffset); | - | ||||||||||||||||||
447 | const int cmp = qstrcmp(aMime, mimeStr); | - | ||||||||||||||||||
448 | if (cmp < 0) {
| 230-236 | ||||||||||||||||||
449 | begin = medium + 1; | - | ||||||||||||||||||
450 | } else if (cmp > 0) { executed 230 times by 1 test: end of block Executed by:
| 26-230 | ||||||||||||||||||
451 | end = medium - 1; | - | ||||||||||||||||||
452 | } else { executed 210 times by 1 test: end of block Executed by:
| 210 | ||||||||||||||||||
453 | const int parentsOffset = cacheFile->getUint32(off + 4); | - | ||||||||||||||||||
454 | const int numParents = cacheFile->getUint32(parentsOffset); | - | ||||||||||||||||||
455 | for (int i = 0; i < numParents; ++i) {
| 26-34 | ||||||||||||||||||
456 | const int parentOffset = cacheFile->getUint32(parentsOffset + 4 + 4 * i); | - | ||||||||||||||||||
457 | const char *aParent = cacheFile->getCharStar(parentOffset); | - | ||||||||||||||||||
458 | result.append(QString::fromLatin1(aParent)); | - | ||||||||||||||||||
459 | } executed 34 times by 1 test: end of block Executed by:
| 34 | ||||||||||||||||||
460 | break; executed 26 times by 1 test: break; Executed by:
| 26 | ||||||||||||||||||
461 | } | - | ||||||||||||||||||
462 | } | - | ||||||||||||||||||
463 | } executed 60 times by 1 test: end of block Executed by:
| 60 | ||||||||||||||||||
464 | if (result.isEmpty()) {
| 26-34 | ||||||||||||||||||
465 | const QString parent = fallbackParent(mime); | - | ||||||||||||||||||
466 | if (!parent.isEmpty())
| 12-22 | ||||||||||||||||||
467 | result.append(parent); executed 22 times by 1 test: result.append(parent); Executed by:
| 22 | ||||||||||||||||||
468 | } executed 34 times by 1 test: end of block Executed by:
| 34 | ||||||||||||||||||
469 | return result; executed 60 times by 1 test: return result; Executed by:
| 60 | ||||||||||||||||||
470 | } | - | ||||||||||||||||||
471 | - | |||||||||||||||||||
472 | QString QMimeBinaryProvider::resolveAlias(const QString &name) | - | ||||||||||||||||||
473 | { | - | ||||||||||||||||||
474 | checkCache(); | - | ||||||||||||||||||
475 | const QByteArray input = name.toLatin1(); | - | ||||||||||||||||||
476 | foreachfor (CacheFile *cacheFile ,: qAsConst(m_cacheFiles))) { | - | ||||||||||||||||||
477 | const int aliasListOffset = cacheFile->getUint32(PosAliasListOffset); | - | ||||||||||||||||||
478 | const int numEntries = cacheFile->getUint32(aliasListOffset); | - | ||||||||||||||||||
479 | int begin = 0; | - | ||||||||||||||||||
480 | int end = numEntries - 1; | - | ||||||||||||||||||
481 | while (begin <= end) {
| 4609-36002 | ||||||||||||||||||
482 | const int medium = (begin + end) / 2; | - | ||||||||||||||||||
483 | const int off = aliasListOffset + 4 + 8 * medium; | - | ||||||||||||||||||
484 | const int aliasOffset = cacheFile->getUint32(off); | - | ||||||||||||||||||
485 | const char *alias = cacheFile->getCharStar(aliasOffset); | - | ||||||||||||||||||
486 | const int cmp = qstrcmp(alias, input); | - | ||||||||||||||||||
487 | if (cmp < 0) {
| 17721-18281 | ||||||||||||||||||
488 | begin = medium + 1; | - | ||||||||||||||||||
489 | } else if (cmp > 0) { executed 18281 times by 23 tests: end of block Executed by:
| 9-18281 | ||||||||||||||||||
490 | end = medium - 1; | - | ||||||||||||||||||
491 | } else { executed 17712 times by 23 tests: end of block Executed by:
| 17712 | ||||||||||||||||||
492 | const int mimeOffset = cacheFile->getUint32(off + 4); | - | ||||||||||||||||||
493 | const char *mimeType = cacheFile->getCharStar(mimeOffset); | - | ||||||||||||||||||
494 | return QLatin1String(mimeType); executed 9 times by 1 test: return QLatin1String(mimeType); Executed by:
| 9 | ||||||||||||||||||
495 | } | - | ||||||||||||||||||
496 | } | - | ||||||||||||||||||
497 | } executed 4609 times by 23 tests: end of block Executed by:
| 4609 | ||||||||||||||||||
498 | - | |||||||||||||||||||
499 | return name; executed 4598 times by 23 tests: return name; Executed by:
| 4598 | ||||||||||||||||||
500 | } | - | ||||||||||||||||||
501 | - | |||||||||||||||||||
502 | QStringList QMimeBinaryProvider::listAliases(const QString &name) | - | ||||||||||||||||||
503 | { | - | ||||||||||||||||||
504 | checkCache(); | - | ||||||||||||||||||
505 | QStringList result; | - | ||||||||||||||||||
506 | const QByteArray input = name.toLatin1(); | - | ||||||||||||||||||
507 | foreachfor (CacheFile *cacheFile ,: qAsConst(m_cacheFiles))) { | - | ||||||||||||||||||
508 | const int aliasListOffset = cacheFile->getUint32(PosAliasListOffset); | - | ||||||||||||||||||
509 | const int numEntries = cacheFile->getUint32(aliasListOffset); | - | ||||||||||||||||||
510 | for (int pos = 0; pos < numEntries; ++pos) {
| 4-776 | ||||||||||||||||||
511 | const int off = aliasListOffset + 4 + 8 * pos; | - | ||||||||||||||||||
512 | const int mimeOffset = cacheFile->getUint32(off + 4); | - | ||||||||||||||||||
513 | const char *mimeType = cacheFile->getCharStar(mimeOffset); | - | ||||||||||||||||||
514 | - | |||||||||||||||||||
515 | if (input == mimeType) {
| 4-772 | ||||||||||||||||||
516 | const int aliasOffset = cacheFile->getUint32(off); | - | ||||||||||||||||||
517 | const char *alias = cacheFile->getCharStar(aliasOffset); | - | ||||||||||||||||||
518 | result.append(QString::fromLatin1(alias)); | - | ||||||||||||||||||
519 | } executed 4 times by 1 test: end of block Executed by:
| 4 | ||||||||||||||||||
520 | } executed 776 times by 1 test: end of block Executed by:
| 776 | ||||||||||||||||||
521 | } executed 4 times by 1 test: end of block Executed by:
| 4 | ||||||||||||||||||
522 | return result; executed 4 times by 1 test: return result; Executed by:
| 4 | ||||||||||||||||||
523 | } | - | ||||||||||||||||||
524 | - | |||||||||||||||||||
525 | void QMimeBinaryProvider::loadMimeTypeList() | - | ||||||||||||||||||
526 | { | - | ||||||||||||||||||
527 | if (!m_mimetypeListLoaded) {
| 5-28 | ||||||||||||||||||
528 | m_mimetypeListLoaded = true; | - | ||||||||||||||||||
529 | m_mimetypeNames.clear(); | - | ||||||||||||||||||
530 | // Unfortunately mime.cache doesn't have a full list of all mimetypes. | - | ||||||||||||||||||
531 | // So we have to parse the plain-text files called "types". | - | ||||||||||||||||||
532 | const QStringList typesFilenames = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QLatin1String("mime/types")); | - | ||||||||||||||||||
533 | foreachfor (const QString &typeFilename ,: typesFilenames) { | - | ||||||||||||||||||
534 | QFile file(typeFilename); | - | ||||||||||||||||||
535 | if (file.open(QIODevice::ReadOnly)) {
| 0-31 | ||||||||||||||||||
536 | while (!file.atEnd()) {
| 31-19818 | ||||||||||||||||||
537 | QByteArray line = file.readLine(); | - | ||||||||||||||||||
538 | line.chop(1); | - | ||||||||||||||||||
539 | m_mimetypeNames.insert(QString::fromLatin1(line.constData(), line.size())); | - | ||||||||||||||||||
540 | } executed 19818 times by 23 tests: end of block Executed by:
| 19818 | ||||||||||||||||||
541 | } executed 31 times by 23 tests: end of block Executed by:
| 31 | ||||||||||||||||||
542 | } executed 31 times by 23 tests: end of block Executed by:
| 31 | ||||||||||||||||||
543 | } executed 28 times by 23 tests: end of block Executed by:
| 28 | ||||||||||||||||||
544 | } executed 33 times by 23 tests: end of block Executed by:
| 33 | ||||||||||||||||||
545 | - | |||||||||||||||||||
546 | QList<QMimeType> QMimeBinaryProvider::allMimeTypes() | - | ||||||||||||||||||
547 | { | - | ||||||||||||||||||
548 | QList<QMimeType> result; | - | ||||||||||||||||||
549 | loadMimeTypeList(); | - | ||||||||||||||||||
550 | result.reserve(m_mimetypeNames.count()); | - | ||||||||||||||||||
551 | - | |||||||||||||||||||
552 | for (QSet<QString>::const_iterator it = m_mimetypeNames.constBegin(); | - | ||||||||||||||||||
553 | it != m_mimetypeNames.constEnd(); ++it) | - | ||||||||||||||||||
554 | result.append(mimeTypeForNameUnchecked(*it)); | - | ||||||||||||||||||
555 | - | |||||||||||||||||||
556 | return result; | - | ||||||||||||||||||
557 | } | - | ||||||||||||||||||
558 | - | |||||||||||||||||||
559 | void QMimeBinaryProvider::loadMimeTypePrivate(QMimeTypePrivate &data) | - | ||||||||||||||||||
560 | { | - | ||||||||||||||||||
561 | #ifdef QT_NO_XMLSTREAMREADER | - | ||||||||||||||||||
562 | qWarning() << ("Cannot load mime type since QXmlStreamReader is not available.";); | - | ||||||||||||||||||
563 | return; | - | ||||||||||||||||||
564 | #else | - | ||||||||||||||||||
565 | if (data.loaded)
| 10-2447 | ||||||||||||||||||
566 | return; executed 10 times by 1 test: return; Executed by:
| 10 | ||||||||||||||||||
567 | data.loaded = true; | - | ||||||||||||||||||
568 | // load comment and globPatterns | - | ||||||||||||||||||
569 | - | |||||||||||||||||||
570 | const QString file = data.name + QLatin1String(".xml"); | - | ||||||||||||||||||
571 | // shared-mime-info since 1.3 lowercases the xml files | - | ||||||||||||||||||
572 | QStringList mimeFiles = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QString::fromLatin1("mime/") + file.toLower()); | - | ||||||||||||||||||
573 | if (mimeFiles.isEmpty()) {
| 0-2447 | ||||||||||||||||||
574 | mimeFiles = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QString::fromLatin1("mime/") + file); // pre-1.3 | - | ||||||||||||||||||
575 | } never executed: end of block | 0 | ||||||||||||||||||
576 | if (mimeFiles.isEmpty()) {
| 0-2447 | ||||||||||||||||||
577 | qWarning() << "No file found for" << file << ", even though update-mime-info said it would exist.\n" | - | ||||||||||||||||||
578 | "Either it was just removed, or the directory doesn't have executable permission..." | - | ||||||||||||||||||
579 | << QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QLatin1String("mime"), QStandardPaths::LocateDirectory); | - | ||||||||||||||||||
580 | return; never executed: return; | 0 | ||||||||||||||||||
581 | } | - | ||||||||||||||||||
582 | - | |||||||||||||||||||
583 | QString comment;QString mainPattern; | - | ||||||||||||||||||
584 | - | |||||||||||||||||||
585 | const QString preferredLanguage = QLocale().name();for (QStringList::const_reverse_iterator it = mimeFiles.crbegin(), end = mimeFiles.crend(); it != end; ++it) { // global first, then local.
| 2447 | ||||||||||||||||||
586 | QFile qfile(*it); | - | ||||||||||||||||||
587 | if (!qfile.open(QFile::ReadOnly))
| 0-2447 | ||||||||||||||||||
588 | continue; never executed: continue; | 0 | ||||||||||||||||||
589 | - | |||||||||||||||||||
590 | QXmlStreamReader xml(&qfile); | - | ||||||||||||||||||
591 | if (xml.readNextStartElement()) {
| 0-2447 | ||||||||||||||||||
592 | if (xml.name() != QLatin1String("mime-type")) {
| 0-2447 | ||||||||||||||||||
593 | continue; never executed: continue; | 0 | ||||||||||||||||||
594 | } | - | ||||||||||||||||||
595 | const QStringRef name = xml.attributes().value(QLatin1String("type")); | - | ||||||||||||||||||
596 | if (name.isEmpty())
| 0-2447 | ||||||||||||||||||
597 | continue; never executed: continue; | 0 | ||||||||||||||||||
598 | if (name.compare(data.name, Qt::CaseInsensitive))
| 0-2447 | ||||||||||||||||||
599 | qWarning() << "Got name" << name << "in file" << file << "expected" << data.name; never executed: QMessageLogger(__FILE__, 599, __PRETTY_FUNCTION__).warning() << "Got name" << name << "in file" << file << "expected" << data.name; | 0 | ||||||||||||||||||
600 | - | |||||||||||||||||||
601 | while (xml.readNextStartElement()) {
| 2447-117409 | ||||||||||||||||||
602 | const QStringRef tag = xml.name(); | - | ||||||||||||||||||
603 | if (tag == QLatin1String("comment")) {
| 2500-114909 | ||||||||||||||||||
604 | QString lang = xml.attributes().value(QLatin1String("xml:lang")).toString(); | - | ||||||||||||||||||
605 | const QString text = xml.readElementText(); | - | ||||||||||||||||||
606 | if (lang.isEmpty()) {
| 2447-112462 | ||||||||||||||||||
607 | lang = QLatin1String("en_US"); | - | ||||||||||||||||||
608 | } executed 2447 times by 22 tests: end of block Executed by:
| 2447 | ||||||||||||||||||
609 | data.localeComments.insert(lang, text); | - | ||||||||||||||||||
610 | continue; // we called readElementText, so we're at the EndElement already. executed 114909 times by 22 tests: continue; Executed by:
| 114909 | ||||||||||||||||||
611 | } else if (tag == QLatin1String("icon")) { // as written out by shared-mime-info >= 0.40
| 0-2500 | ||||||||||||||||||
612 | data.iconName = xml.attributes().value(QLatin1String("name")).toString(); | - | ||||||||||||||||||
613 | } else if (tag == QLatin1String("glob-deleteall")) { // as written out by shared-mime-info >= 0.70 never executed: end of block
| 0-2499 | ||||||||||||||||||
614 | data.globPatterns.clear(); | - | ||||||||||||||||||
615 | } else if (tag == QLatin1String("glob")) { // as written out by shared-mime-info >= 0.70 executed 1 time by 1 test: end of block Executed by:
| 1-2463 | ||||||||||||||||||
616 | const QString pattern = xml.attributes().value(QLatin1String("pattern")).toString(); | - | ||||||||||||||||||
617 | if (mainPattern.isEmpty() && pattern.startsWith(QLatin1Char('*'))) {
| 1-2443 | ||||||||||||||||||
618 | mainPattern = pattern; | - | ||||||||||||||||||
619 | } executed 2442 times by 22 tests: end of block Executed by:
| 2442 | ||||||||||||||||||
620 | if (!data.globPatterns.contains(pattern))
| 0-2463 | ||||||||||||||||||
621 | data.globPatterns.append(pattern); executed 2463 times by 22 tests: data.globPatterns.append(pattern); Executed by:
| 2463 | ||||||||||||||||||
622 | } executed 2463 times by 22 tests: end of block Executed by:
| 2463 | ||||||||||||||||||
623 | xml.skipCurrentElement(); | - | ||||||||||||||||||
624 | } executed 2500 times by 22 tests: end of block Executed by:
| 2500 | ||||||||||||||||||
625 | Q_ASSERT(xml.name() == QLatin1String("mime-type")); | - | ||||||||||||||||||
626 | } executed 2447 times by 22 tests: end of block Executed by:
| 2447 | ||||||||||||||||||
627 | } executed 2447 times by 22 tests: end of block Executed by:
| 2447 | ||||||||||||||||||
628 | - | |||||||||||||||||||
629 | // Let's assume that shared-mime-info is at least version 0.70 | - | ||||||||||||||||||
630 | // Otherwise we would need 1) a version check, and 2) code for parsing patterns from the globs file. | - | ||||||||||||||||||
631 | #if 1 | - | ||||||||||||||||||
632 | if (!mainPattern.isEmpty() && (data.globPatterns.isEmpty() || data.globPatterns.firstconstFirst() != mainPattern)) {
| 0-2442 | ||||||||||||||||||
633 | // ensure it's first in the list of patterns | - | ||||||||||||||||||
634 | data.globPatterns.removeAll(mainPattern); | - | ||||||||||||||||||
635 | data.globPatterns.prepend(mainPattern); | - | ||||||||||||||||||
636 | } executed 1 time by 1 test: end of block Executed by:
| 1 | ||||||||||||||||||
637 | #else | - | ||||||||||||||||||
638 | const bool globsInXml = sharedMimeInfoVersion() >= QT_VERSION_CHECK(0, 70, 0); | - | ||||||||||||||||||
639 | if (globsInXml) { | - | ||||||||||||||||||
640 | if (!mainPattern.isEmpty() && data.globPatterns.firstconstFirst() != mainPattern) { | - | ||||||||||||||||||
641 | // ensure it's first in the list of patterns | - | ||||||||||||||||||
642 | data.globPatterns.removeAll(mainPattern); | - | ||||||||||||||||||
643 | data.globPatterns.prepend(mainPattern); | - | ||||||||||||||||||
644 | } | - | ||||||||||||||||||
645 | } else { | - | ||||||||||||||||||
646 | // Fallback: get the patterns from the globs file | - | ||||||||||||||||||
647 | // TODO: This would be the only way to support shared-mime-info < 0.70 | - | ||||||||||||||||||
648 | // But is this really worth the effort? | - | ||||||||||||||||||
649 | } | - | ||||||||||||||||||
650 | #endif | - | ||||||||||||||||||
651 | #endif //QT_NO_XMLSTREAMREADER | - | ||||||||||||||||||
652 | } executed 2447 times by 22 tests: end of block Executed by:
| 2447 | ||||||||||||||||||
653 | - | |||||||||||||||||||
654 | // Binary search in the icons or generic-icons list | - | ||||||||||||||||||
655 | QString QMimeBinaryProvider::iconForMime(CacheFile *cacheFile, int posListOffset, const QByteArray &inputMime) | - | ||||||||||||||||||
656 | { | - | ||||||||||||||||||
657 | const int iconsListOffset = cacheFile->getUint32(posListOffset); | - | ||||||||||||||||||
658 | const int numIcons = cacheFile->getUint32(iconsListOffset); | - | ||||||||||||||||||
659 | int begin = 0; | - | ||||||||||||||||||
660 | int end = numIcons - 1; | - | ||||||||||||||||||
661 | while (begin <= end) { | - | ||||||||||||||||||
662 | const int medium = (begin + end) / 2; | - | ||||||||||||||||||
663 | const int off = iconsListOffset + 4 + 8 * medium; | - | ||||||||||||||||||
664 | const int mimeOffset = cacheFile->getUint32(off); | - | ||||||||||||||||||
665 | const char *mime = cacheFile->getCharStar(mimeOffset); | - | ||||||||||||||||||
666 | const int cmp = qstrcmp(mime, inputMime); | - | ||||||||||||||||||
667 | if (cmp < 0) | - | ||||||||||||||||||
668 | begin = medium + 1; | - | ||||||||||||||||||
669 | else if (cmp > 0) | - | ||||||||||||||||||
670 | end = medium - 1; | - | ||||||||||||||||||
671 | else { | - | ||||||||||||||||||
672 | const int iconOffset = cacheFile->getUint32(off + 4); | - | ||||||||||||||||||
673 | return QLatin1String(cacheFile->getCharStar(iconOffset)); | - | ||||||||||||||||||
674 | } | - | ||||||||||||||||||
675 | } | - | ||||||||||||||||||
676 | return QString(); | - | ||||||||||||||||||
677 | } | - | ||||||||||||||||||
678 | - | |||||||||||||||||||
679 | void QMimeBinaryProvider::loadIcon(QMimeTypePrivate &data) | - | ||||||||||||||||||
680 | { | - | ||||||||||||||||||
681 | checkCache(); | - | ||||||||||||||||||
682 | const QByteArray inputMime = data.name.toLatin1(); | - | ||||||||||||||||||
683 | foreachfor (CacheFile *cacheFile ,: qAsConst(m_cacheFiles))) { | - | ||||||||||||||||||
684 | const QString icon = iconForMime(cacheFile, PosIconsListOffset, inputMime); | - | ||||||||||||||||||
685 | if (!icon.isEmpty()) {
| 0-4 | ||||||||||||||||||
686 | data.iconName = icon; | - | ||||||||||||||||||
687 | return; never executed: return; | 0 | ||||||||||||||||||
688 | } | - | ||||||||||||||||||
689 | } executed 4 times by 1 test: end of block Executed by:
| 4 | ||||||||||||||||||
690 | } executed 4 times by 1 test: end of block Executed by:
| 4 | ||||||||||||||||||
691 | - | |||||||||||||||||||
692 | void QMimeBinaryProvider::loadGenericIcon(QMimeTypePrivate &data) | - | ||||||||||||||||||
693 | { | - | ||||||||||||||||||
694 | checkCache(); | - | ||||||||||||||||||
695 | const QByteArray inputMime = data.name.toLatin1(); | - | ||||||||||||||||||
696 | foreachfor (CacheFile *cacheFile ,: qAsConst(m_cacheFiles))) { | - | ||||||||||||||||||
697 | const QString icon = iconForMime(cacheFile, PosGenericIconsListOffset, inputMime); | - | ||||||||||||||||||
698 | if (!icon.isEmpty()) {
| 2 | ||||||||||||||||||
699 | data.genericIconName = icon; | - | ||||||||||||||||||
700 | return; executed 2 times by 1 test: return; Executed by:
| 2 | ||||||||||||||||||
701 | } | - | ||||||||||||||||||
702 | } executed 2 times by 1 test: end of block Executed by:
| 2 | ||||||||||||||||||
703 | } executed 2 times by 1 test: end of block Executed by:
| 2 | ||||||||||||||||||
704 | - | |||||||||||||||||||
705 | //// | - | ||||||||||||||||||
706 | - | |||||||||||||||||||
707 | QMimeXMLProvider::QMimeXMLProvider(QMimeDatabasePrivate *db) | - | ||||||||||||||||||
708 | : QMimeProviderBase(db), m_loaded(false) | - | ||||||||||||||||||
709 | { | - | ||||||||||||||||||
710 | initResources(); | - | ||||||||||||||||||
711 | } | - | ||||||||||||||||||
712 | - | |||||||||||||||||||
713 | QMimeXMLProvider::~QMimeXMLProvider() | - | ||||||||||||||||||
714 | { | - | ||||||||||||||||||
715 | } | - | ||||||||||||||||||
716 | - | |||||||||||||||||||
717 | bool QMimeXMLProvider::isValid() | - | ||||||||||||||||||
718 | { | - | ||||||||||||||||||
719 | return true; | - | ||||||||||||||||||
720 | } | - | ||||||||||||||||||
721 | - | |||||||||||||||||||
722 | QMimeType QMimeXMLProvider::mimeTypeForName(const QString &name) | - | ||||||||||||||||||
723 | { | - | ||||||||||||||||||
724 | ensureLoaded(); | - | ||||||||||||||||||
725 | - | |||||||||||||||||||
726 | return m_nameMimeTypeMap.value(name); | - | ||||||||||||||||||
727 | } | - | ||||||||||||||||||
728 | - | |||||||||||||||||||
729 | QStringList QMimeXMLProvider::findByFileName(const QString &fileName, QString *foundSuffix) | - | ||||||||||||||||||
730 | { | - | ||||||||||||||||||
731 | ensureLoaded(); | - | ||||||||||||||||||
732 | - | |||||||||||||||||||
733 | const QStringList matchingMimeTypes = m_mimeTypeGlobs.matchingGlobs(fileName, foundSuffix); | - | ||||||||||||||||||
734 | return matchingMimeTypes; | - | ||||||||||||||||||
735 | } | - | ||||||||||||||||||
736 | - | |||||||||||||||||||
737 | QMimeType QMimeXMLProvider::findByMagic(const QByteArray &data, int *accuracyPtr) | - | ||||||||||||||||||
738 | { | - | ||||||||||||||||||
739 | ensureLoaded(); | - | ||||||||||||||||||
740 | - | |||||||||||||||||||
741 | QString candidate; | - | ||||||||||||||||||
742 | - | |||||||||||||||||||
743 | foreachfor (const QMimeMagicRuleMatcher &matcher ,: qAsConst(m_magicMatchers))) { | - | ||||||||||||||||||
744 | if (matcher.matches(data)) {
| 37-11003 | ||||||||||||||||||
745 | const int priority = matcher.priority(); | - | ||||||||||||||||||
746 | if (priority > *accuracyPtr) {
| 14-23 | ||||||||||||||||||
747 | *accuracyPtr = priority; | - | ||||||||||||||||||
748 | candidate = matcher.mimetype(); | - | ||||||||||||||||||
749 | } executed 23 times by 1 test: end of block Executed by:
| 23 | ||||||||||||||||||
750 | } executed 37 times by 1 test: end of block Executed by:
| 37 | ||||||||||||||||||
751 | } executed 11040 times by 1 test: end of block Executed by:
| 11040 | ||||||||||||||||||
752 | return mimeTypeForName(candidate); executed 32 times by 1 test: return mimeTypeForName(candidate); Executed by:
| 32 | ||||||||||||||||||
753 | } | - | ||||||||||||||||||
754 | - | |||||||||||||||||||
755 | void QMimeXMLProvider::ensureLoaded() | - | ||||||||||||||||||
756 | { | - | ||||||||||||||||||
757 | if (!m_loaded || shouldCheck()) {
| 1-4556 | ||||||||||||||||||
758 | bool fdoXmlFound = false; | - | ||||||||||||||||||
759 | QStringList allFiles; | - | ||||||||||||||||||
760 | - | |||||||||||||||||||
761 | const QStringList packageDirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QLatin1String("mime/packages"), QStandardPaths::LocateDirectory); | - | ||||||||||||||||||
762 | //qDebug() << "packageDirs=" << packageDirs; | - | ||||||||||||||||||
763 | foreachfor (const QString &packageDir ,: packageDirs) { | - | ||||||||||||||||||
764 | QDir dir(packageDir); | - | ||||||||||||||||||
765 | const QStringList files = dir.entryList(QDir::Files | QDir::NoDotAndDotDot); | - | ||||||||||||||||||
766 | //qDebug() << static_cast<const void *>(this) << packageDir << files; | - | ||||||||||||||||||
767 | if (!fdoXmlFound)
| 0-88 | ||||||||||||||||||
768 | fdoXmlFound = files.contains(QLatin1String("freedesktop.org.xml")); executed 88 times by 1 test: fdoXmlFound = files.contains(QLatin1String("freedesktop.org.xml")); Executed by:
| 88 | ||||||||||||||||||
769 | QStringList::const_iterator endIt(files.constEnd()); | - | ||||||||||||||||||
770 | for (QStringList::const_iterator it(files.constBegin()); it != endIt; ++it) {
| 88-261 | ||||||||||||||||||
771 | allFiles.append(packageDir + QLatin1Char('/') + *it); | - | ||||||||||||||||||
772 | } executed 261 times by 1 test: end of block Executed by:
| 261 | ||||||||||||||||||
773 | } executed 88 times by 1 test: end of block Executed by:
| 88 | ||||||||||||||||||
774 | - | |||||||||||||||||||
775 | if (!fdoXmlFound) {
| 0-57 | ||||||||||||||||||
776 | // We could instead install the file as part of installing Qt? | - | ||||||||||||||||||
777 | allFiles.prepend(QLatin1String(":/qt-project.org/qmime/freedesktop.org.xml")); | - | ||||||||||||||||||
778 | } never executed: end of block | 0 | ||||||||||||||||||
779 | - | |||||||||||||||||||
780 | if (m_allFiles == allFiles)
| 5-52 | ||||||||||||||||||
781 | return; executed 52 times by 1 test: return; Executed by:
| 52 | ||||||||||||||||||
782 | m_allFiles = allFiles; | - | ||||||||||||||||||
783 | - | |||||||||||||||||||
784 | m_nameMimeTypeMap.clear(); | - | ||||||||||||||||||
785 | m_aliases.clear(); | - | ||||||||||||||||||
786 | m_parents.clear(); | - | ||||||||||||||||||
787 | m_mimeTypeGlobs.clear(); | - | ||||||||||||||||||
788 | m_magicMatchers.clear(); | - | ||||||||||||||||||
789 | - | |||||||||||||||||||
790 | //qDebug() << "Loading" << m_allFiles; | - | ||||||||||||||||||
791 | - | |||||||||||||||||||
792 | foreachfor (const QString &file ,: qAsConst(allFiles))) | - | ||||||||||||||||||
793 | load(file); executed 17 times by 1 test: load(file); Executed by:
| 17 | ||||||||||||||||||
794 | } executed 5 times by 1 test: end of block Executed by:
| 5 | ||||||||||||||||||
795 | } executed 4505 times by 1 test: end of block Executed by:
| 4505 | ||||||||||||||||||
796 | - | |||||||||||||||||||
797 | void QMimeXMLProvider::load(const QString &fileName) | - | ||||||||||||||||||
798 | { | - | ||||||||||||||||||
799 | QString errorMessage; | - | ||||||||||||||||||
800 | if (!load(fileName, &errorMessage)) | - | ||||||||||||||||||
801 | qWarning("QMimeDatabase: Error loading %s\n%s", qPrintable(fileName), qPrintable(errorMessage)); | - | ||||||||||||||||||
802 | } | - | ||||||||||||||||||
803 | - | |||||||||||||||||||
804 | bool QMimeXMLProvider::load(const QString &fileName, QString *errorMessage) | - | ||||||||||||||||||
805 | { | - | ||||||||||||||||||
806 | m_loaded = true; | - | ||||||||||||||||||
807 | - | |||||||||||||||||||
808 | QFile file(fileName); | - | ||||||||||||||||||
809 | if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { | - | ||||||||||||||||||
810 | if (errorMessage) | - | ||||||||||||||||||
811 | *errorMessage = QString::fromLatin1("Cannot open %1: %2").arg(fileName, file.errorString()); | - | ||||||||||||||||||
812 | return false; | - | ||||||||||||||||||
813 | } | - | ||||||||||||||||||
814 | - | |||||||||||||||||||
815 | if (errorMessage) | - | ||||||||||||||||||
816 | errorMessage->clear(); | - | ||||||||||||||||||
817 | - | |||||||||||||||||||
818 | QMimeTypeParser parser(*this); | - | ||||||||||||||||||
819 | return parser.parse(&file, fileName, errorMessage); | - | ||||||||||||||||||
820 | } | - | ||||||||||||||||||
821 | - | |||||||||||||||||||
822 | void QMimeXMLProvider::addGlobPattern(const QMimeGlobPattern &glob) | - | ||||||||||||||||||
823 | { | - | ||||||||||||||||||
824 | m_mimeTypeGlobs.addGlob(glob); | - | ||||||||||||||||||
825 | } | - | ||||||||||||||||||
826 | - | |||||||||||||||||||
827 | void QMimeXMLProvider::addMimeType(const QMimeType &mt) | - | ||||||||||||||||||
828 | { | - | ||||||||||||||||||
829 | m_nameMimeTypeMap.insert(mt.name(), mt); | - | ||||||||||||||||||
830 | } | - | ||||||||||||||||||
831 | - | |||||||||||||||||||
832 | QStringList QMimeXMLProvider::parents(const QString &mime) | - | ||||||||||||||||||
833 | { | - | ||||||||||||||||||
834 | ensureLoaded(); | - | ||||||||||||||||||
835 | QStringList result = m_parents.value(mime); | - | ||||||||||||||||||
836 | if (result.isEmpty()) { | - | ||||||||||||||||||
837 | const QString parent = fallbackParent(mime); | - | ||||||||||||||||||
838 | if (!parent.isEmpty()) | - | ||||||||||||||||||
839 | result.append(parent); | - | ||||||||||||||||||
840 | } | - | ||||||||||||||||||
841 | return result; | - | ||||||||||||||||||
842 | } | - | ||||||||||||||||||
843 | - | |||||||||||||||||||
844 | void QMimeXMLProvider::addParent(const QString &child, const QString &parent) | - | ||||||||||||||||||
845 | { | - | ||||||||||||||||||
846 | m_parents[child].append(parent); | - | ||||||||||||||||||
847 | } | - | ||||||||||||||||||
848 | - | |||||||||||||||||||
849 | QStringList QMimeXMLProvider::listAliases(const QString &name) | - | ||||||||||||||||||
850 | { | - | ||||||||||||||||||
851 | ensureLoaded(); | - | ||||||||||||||||||
852 | // Iterate through the whole hash. This method is rarely used. | - | ||||||||||||||||||
853 | return m_aliases.keys(name); | - | ||||||||||||||||||
854 | } | - | ||||||||||||||||||
855 | - | |||||||||||||||||||
856 | QString QMimeXMLProvider::resolveAlias(const QString &name) | - | ||||||||||||||||||
857 | { | - | ||||||||||||||||||
858 | ensureLoaded(); | - | ||||||||||||||||||
859 | return m_aliases.value(name, name); | - | ||||||||||||||||||
860 | } | - | ||||||||||||||||||
861 | - | |||||||||||||||||||
862 | void QMimeXMLProvider::addAlias(const QString &alias, const QString &name) | - | ||||||||||||||||||
863 | { | - | ||||||||||||||||||
864 | m_aliases.insert(alias, name); | - | ||||||||||||||||||
865 | } | - | ||||||||||||||||||
866 | - | |||||||||||||||||||
867 | QList<QMimeType> QMimeXMLProvider::allMimeTypes() | - | ||||||||||||||||||
868 | { | - | ||||||||||||||||||
869 | ensureLoaded(); | - | ||||||||||||||||||
870 | return m_nameMimeTypeMap.values(); | - | ||||||||||||||||||
871 | } | - | ||||||||||||||||||
872 | - | |||||||||||||||||||
873 | void QMimeXMLProvider::addMagicMatcher(const QMimeMagicRuleMatcher &matcher) | - | ||||||||||||||||||
874 | { | - | ||||||||||||||||||
875 | m_magicMatchers.append(matcher); | - | ||||||||||||||||||
876 | } | - | ||||||||||||||||||
877 | - | |||||||||||||||||||
878 | QT_END_NAMESPACE | - | ||||||||||||||||||
879 | - | |||||||||||||||||||
880 | #endif // QT_NO_MIMETYPE | - | ||||||||||||||||||
Source code | Switch to Preprocessed file |