Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qmimeprovider.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 The Qt Company Ltd.
2// Copyright (C) 2018 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>
3// Copyright (C) 2019 Intel Corporation.
4// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
5
6#include "qmimeprovider_p.h"
7
8#include "qmimetypeparser_p.h"
9#include <qstandardpaths.h>
11
12#include <QXmlStreamReader>
13#include <QBuffer>
14#include <QDir>
15#include <QFile>
16#include <QByteArrayMatcher>
17#include <QDebug>
18#include <QDateTime>
19#include <QtEndian>
20
21#if QT_CONFIG(mimetype_database)
22# if defined(Q_CC_MSVC_ONLY)
23# pragma section(".qtmimedatabase", read, shared)
24__declspec(allocate(".qtmimedatabase")) __declspec(align(4096))
25# elif defined(Q_OS_DARWIN)
26__attribute__((section("__TEXT,.qtmimedatabase"), aligned(4096)))
27# elif (defined(Q_OF_ELF) || defined(Q_OS_WIN)) && defined(Q_CC_GNU)
28__attribute__((section(".qtmimedatabase"), aligned(4096)))
29# endif
30
31# include "qmimeprovider_database.cpp"
32
33# ifdef MIME_DATABASE_IS_ZSTD
34# if !QT_CONFIG(zstd)
35# error "MIME database is zstd but no support compiled in!"
36# endif
37# include <zstd.h>
38# endif
39# ifdef MIME_DATABASE_IS_GZIP
40# ifdef QT_NO_COMPRESS
41# error "MIME database is zlib but no support compiled in!"
42# endif
43# define ZLIB_CONST
44# include <zconf.h>
45# include <zlib.h>
46# endif
47#endif
48
50
51using namespace Qt::StringLiterals;
52
54{
56 ~CacheFile();
57
58 bool isValid() const { return m_valid; }
59 inline quint16 getUint16(int offset) const
60 {
61 return qFromBigEndian(*reinterpret_cast<quint16 *>(data + offset));
62 }
63 inline quint32 getUint32(int offset) const
64 {
65 return qFromBigEndian(*reinterpret_cast<quint32 *>(data + offset));
66 }
67 inline const char *getCharStar(int offset) const
68 {
69 return reinterpret_cast<const char *>(data + offset);
70 }
71 bool load();
72 bool reload();
73
77 bool m_valid;
78};
79
80static inline void appendIfNew(QStringList &list, const QString &str)
81{
82 if (!list.contains(str))
84}
85
90
95
100
102{
103 if (m_overrideProvider) {
105 return true;
107 }
108 return false;
109}
110
116
122
126
128{
130 return false;
131 data = file.map(0, file.size());
132 if (data) {
133 const int major = getUint16(0);
134 const int minor = getUint16(2);
135 m_valid = (major == 1 && minor >= 1 && minor <= 2);
136 }
138 return m_valid;
139}
140
142{
143 m_valid = false;
144 if (file.isOpen()) {
145 file.close();
146 }
147 data = nullptr;
148 return load();
149}
150
152
154{
155 return m_cacheFile != nullptr;
156}
157
159{
160 return false;
161}
162
163// Position of the "list offsets" values, at the beginning of the mime.cache file
164enum {
171 // PosNamespaceListOffset = 28,
175
176bool QMimeBinaryProvider::checkCacheChanged()
177{
178 QFileInfo fileInfo(m_cacheFile->file);
179 if (fileInfo.lastModified(QTimeZone::UTC) > m_cacheFile->m_mtime) {
180 // Deletion can't happen by just running update-mime-database.
181 // But the user could use rm -rf :-)
182 m_cacheFile->reload(); // will mark itself as invalid on failure
183 return true;
184 }
185 return false;
186}
187
189{
190 if (!m_cacheFile) {
191 const QString cacheFileName = m_directory + "/mime.cache"_L1;
192 m_cacheFile = std::make_unique<CacheFile>(cacheFileName);
193 m_mimetypeListLoaded = false;
194 m_mimetypeExtra.clear();
195 } else {
196 if (checkCacheChanged()) {
197 m_mimetypeListLoaded = false;
198 m_mimetypeExtra.clear();
199 } else {
200 return; // nothing to do
201 }
202 }
203 if (!m_cacheFile->isValid()) // verify existence and version
204 m_cacheFile.reset();
205}
206
208{
209 if (!m_mimetypeListLoaded)
210 loadMimeTypeList();
211 return m_mimetypeNames.contains(name);
212}
213
215{
216 if (fileName.isEmpty())
217 return;
218 Q_ASSERT(m_cacheFile);
219 int numMatches = 0;
220 // Check literals (e.g. "Makefile")
221 numMatches = matchGlobList(result, m_cacheFile.get(),
222 m_cacheFile->getUint32(PosLiteralListOffset), fileName);
223 // Check the very common *.txt cases with the suffix tree
224 if (numMatches == 0) {
225 const QString lowerFileName = fileName.toLower();
226 const int reverseSuffixTreeOffset = m_cacheFile->getUint32(PosReverseSuffixTreeOffset);
227 const int numRoots = m_cacheFile->getUint32(reverseSuffixTreeOffset);
228 const int firstRootOffset = m_cacheFile->getUint32(reverseSuffixTreeOffset + 4);
229 if (matchSuffixTree(result, m_cacheFile.get(), numRoots, firstRootOffset, lowerFileName,
230 lowerFileName.size() - 1, false)) {
231 ++numMatches;
232 } else if (matchSuffixTree(result, m_cacheFile.get(), numRoots, firstRootOffset, fileName,
233 fileName.size() - 1, true)) {
234 ++numMatches;
235 }
236 }
237 // Check complex globs (e.g. "callgrind.out[0-9]*" or "README*")
238 if (numMatches == 0)
239 matchGlobList(result, m_cacheFile.get(), m_cacheFile->getUint32(PosGlobListOffset),
240 fileName);
241}
242
243int QMimeBinaryProvider::matchGlobList(QMimeGlobMatchResult &result, CacheFile *cacheFile, int off,
244 const QString &fileName)
245{
246 int numMatches = 0;
247 const int numGlobs = cacheFile->getUint32(off);
248 //qDebug() << "Loading" << numGlobs << "globs from" << cacheFile->file.fileName() << "at offset" << cacheFile->globListOffset;
249 for (int i = 0; i < numGlobs; ++i) {
250 const int globOffset = cacheFile->getUint32(off + 4 + 12 * i);
251 const int mimeTypeOffset = cacheFile->getUint32(off + 4 + 12 * i + 4);
252 const int flagsAndWeight = cacheFile->getUint32(off + 4 + 12 * i + 8);
253 const int weight = flagsAndWeight & 0xff;
254 const bool caseSensitive = flagsAndWeight & 0x100;
255 const Qt::CaseSensitivity qtCaseSensitive = caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
256 const QString pattern = QLatin1StringView(cacheFile->getCharStar(globOffset));
257
258 const QLatin1StringView mimeType(cacheFile->getCharStar(mimeTypeOffset));
259 //qDebug() << pattern << mimeType << weight << caseSensitive;
261 continue;
262
263 QMimeGlobPattern glob(pattern, QString() /*unused*/, weight, qtCaseSensitive);
264 if (glob.matchFileName(fileName)) {
265 result.addMatch(mimeType, weight, pattern);
266 ++numMatches;
267 }
268 }
269 return numMatches;
270}
271
272bool QMimeBinaryProvider::matchSuffixTree(QMimeGlobMatchResult &result,
273 QMimeBinaryProvider::CacheFile *cacheFile, int numEntries,
274 int firstOffset, const QString &fileName,
275 qsizetype charPos, bool caseSensitiveCheck)
276{
277 QChar fileChar = fileName[charPos];
278 int min = 0;
279 int max = numEntries - 1;
280 while (min <= max) {
281 const int mid = (min + max) / 2;
282 const int off = firstOffset + 12 * mid;
283 const QChar ch = char16_t(cacheFile->getUint32(off));
284 if (ch < fileChar)
285 min = mid + 1;
286 else if (ch > fileChar)
287 max = mid - 1;
288 else {
289 --charPos;
290 int numChildren = cacheFile->getUint32(off + 4);
291 int childrenOffset = cacheFile->getUint32(off + 8);
292 bool success = false;
293 if (charPos > 0)
294 success = matchSuffixTree(result, cacheFile, numChildren, childrenOffset, fileName, charPos, caseSensitiveCheck);
295 if (!success) {
296 for (int i = 0; i < numChildren; ++i) {
297 const int childOff = childrenOffset + 12 * i;
298 const int mch = cacheFile->getUint32(childOff);
299 if (mch != 0)
300 break;
301 const int mimeTypeOffset = cacheFile->getUint32(childOff + 4);
302 const QLatin1StringView mimeType(cacheFile->getCharStar(mimeTypeOffset));
304 continue;
305 const int flagsAndWeight = cacheFile->getUint32(childOff + 8);
306 const int weight = flagsAndWeight & 0xff;
307 const bool caseSensitive = flagsAndWeight & 0x100;
308 if (caseSensitiveCheck || !caseSensitive) {
309 result.addMatch(mimeType, weight,
310 u'*' + QStringView{ fileName }.mid(charPos + 1),
311 fileName.size() - charPos - 2);
312 success = true;
313 }
314 }
315 }
316 return success;
317 }
318 }
319 return false;
320}
321
322bool QMimeBinaryProvider::matchMagicRule(QMimeBinaryProvider::CacheFile *cacheFile, int numMatchlets, int firstOffset, const QByteArray &data)
323{
324 const char *dataPtr = data.constData();
325 const qsizetype dataSize = data.size();
326 for (int matchlet = 0; matchlet < numMatchlets; ++matchlet) {
327 const int off = firstOffset + matchlet * 32;
328 const int rangeStart = cacheFile->getUint32(off);
329 const int rangeLength = cacheFile->getUint32(off + 4);
330 //const int wordSize = cacheFile->getUint32(off + 8);
331 const int valueLength = cacheFile->getUint32(off + 12);
332 const int valueOffset = cacheFile->getUint32(off + 16);
333 const int maskOffset = cacheFile->getUint32(off + 20);
334 const char *mask = maskOffset ? cacheFile->getCharStar(maskOffset) : nullptr;
335
336 if (!QMimeMagicRule::matchSubstring(dataPtr, dataSize, rangeStart, rangeLength, valueLength, cacheFile->getCharStar(valueOffset), mask))
337 continue;
338
339 const int numChildren = cacheFile->getUint32(off + 24);
340 const int firstChildOffset = cacheFile->getUint32(off + 28);
341 if (numChildren == 0) // No submatch? Then we are done.
342 return true;
343 // Check that one of the submatches matches too
344 if (matchMagicRule(cacheFile, numChildren, firstChildOffset, data))
345 return true;
346 }
347 return false;
348}
349
351{
352 const int magicListOffset = m_cacheFile->getUint32(PosMagicListOffset);
353 const int numMatches = m_cacheFile->getUint32(magicListOffset);
354 //const int maxExtent = cacheFile->getUint32(magicListOffset + 4);
355 const int firstMatchOffset = m_cacheFile->getUint32(magicListOffset + 8);
356
357 for (int i = 0; i < numMatches; ++i) {
358 const int off = firstMatchOffset + i * 16;
359 const int numMatchlets = m_cacheFile->getUint32(off + 8);
360 const int firstMatchletOffset = m_cacheFile->getUint32(off + 12);
361 if (matchMagicRule(m_cacheFile.get(), numMatchlets, firstMatchletOffset, data)) {
362 const int mimeTypeOffset = m_cacheFile->getUint32(off + 4);
363 const char *mimeType = m_cacheFile->getCharStar(mimeTypeOffset);
364 const int accuracy = static_cast<int>(m_cacheFile->getUint32(off));
365 if (accuracy > result.accuracy) {
366 result.accuracy = accuracy;
368 // Return the first match, mime.cache is sorted
369 return;
370 }
371 }
372 }
373}
374
376{
377 const QByteArray mimeStr = mime.toLatin1();
378 const int parentListOffset = m_cacheFile->getUint32(PosParentListOffset);
379 const int numEntries = m_cacheFile->getUint32(parentListOffset);
380
381 int begin = 0;
382 int end = numEntries - 1;
383 while (begin <= end) {
384 const int medium = (begin + end) / 2;
385 const int off = parentListOffset + 4 + 8 * medium;
386 const int mimeOffset = m_cacheFile->getUint32(off);
387 const char *aMime = m_cacheFile->getCharStar(mimeOffset);
388 const int cmp = qstrcmp(aMime, mimeStr);
389 if (cmp < 0) {
390 begin = medium + 1;
391 } else if (cmp > 0) {
392 end = medium - 1;
393 } else {
394 const int parentsOffset = m_cacheFile->getUint32(off + 4);
395 const int numParents = m_cacheFile->getUint32(parentsOffset);
396 for (int i = 0; i < numParents; ++i) {
397 const int parentOffset = m_cacheFile->getUint32(parentsOffset + 4 + 4 * i);
398 const char *aParent = m_cacheFile->getCharStar(parentOffset);
399 const QString strParent = QString::fromLatin1(aParent);
400 appendIfNew(result, strParent);
401 }
402 break;
403 }
404 }
405}
406
408{
409 const QByteArray input = name.toLatin1();
410 const int aliasListOffset = m_cacheFile->getUint32(PosAliasListOffset);
411 const int numEntries = m_cacheFile->getUint32(aliasListOffset);
412 int begin = 0;
413 int end = numEntries - 1;
414 while (begin <= end) {
415 const int medium = (begin + end) / 2;
416 const int off = aliasListOffset + 4 + 8 * medium;
417 const int aliasOffset = m_cacheFile->getUint32(off);
418 const char *alias = m_cacheFile->getCharStar(aliasOffset);
419 const int cmp = qstrcmp(alias, input);
420 if (cmp < 0) {
421 begin = medium + 1;
422 } else if (cmp > 0) {
423 end = medium - 1;
424 } else {
425 const int mimeOffset = m_cacheFile->getUint32(off + 4);
426 const char *mimeType = m_cacheFile->getCharStar(mimeOffset);
428 }
429 }
430 return QString();
431}
432
434{
435 const QByteArray input = name.toLatin1();
436 const int aliasListOffset = m_cacheFile->getUint32(PosAliasListOffset);
437 const int numEntries = m_cacheFile->getUint32(aliasListOffset);
438 for (int pos = 0; pos < numEntries; ++pos) {
439 const int off = aliasListOffset + 4 + 8 * pos;
440 const int mimeOffset = m_cacheFile->getUint32(off + 4);
441 const char *mimeType = m_cacheFile->getCharStar(mimeOffset);
442
443 if (input == mimeType) {
444 const int aliasOffset = m_cacheFile->getUint32(off);
445 const char *alias = m_cacheFile->getCharStar(aliasOffset);
446 const QString strAlias = QString::fromLatin1(alias);
447 appendIfNew(result, strAlias);
448 }
449 }
450}
451
452void QMimeBinaryProvider::loadMimeTypeList()
453{
454 if (!m_mimetypeListLoaded) {
455 m_mimetypeListLoaded = true;
456 m_mimetypeNames.clear();
457 // Unfortunately mime.cache doesn't have a full list of all mimetypes.
458 // So we have to parse the plain-text files called "types".
459 QFile file(m_directory + QStringView(u"/types"));
461 while (!file.atEnd()) {
462 const QByteArray line = file.readLine();
463 auto lineView = QByteArrayView(line);
464 if (lineView.endsWith('\n'))
465 lineView.chop(1);
466 m_mimetypeNames.insert(QString::fromLatin1(lineView));
467 }
468 }
469 }
470}
471
473{
474 loadMimeTypeList();
475 if (result.isEmpty()) {
476 result.reserve(m_mimetypeNames.size());
477 for (const QString &name : std::as_const(m_mimetypeNames))
479 } else {
480 for (const QString &name : std::as_const(m_mimetypeNames))
481 if (std::find_if(result.constBegin(), result.constEnd(), [name](const QMimeType &mime) -> bool { return mime.name() == name; })
482 == result.constEnd())
484 }
485}
486
488{
489 MimeTypeExtraMap::const_iterator it = loadMimeTypeExtra(name);
490 if (it != m_mimetypeExtra.cend())
491 return it->second.localeComments;
492 return {};
493}
494
496{
497 MimeTypeExtraMap::const_iterator it = loadMimeTypeExtra(name);
498 if (it != m_mimetypeExtra.cend())
499 return it->second.hasGlobDeleteAll;
500 return {};
501}
502
504{
505 MimeTypeExtraMap::const_iterator it = loadMimeTypeExtra(name);
506 if (it != m_mimetypeExtra.cend())
507 return it->second.globPatterns;
508 return {};
509}
510
511QMimeBinaryProvider::MimeTypeExtraMap::const_iterator
512QMimeBinaryProvider::loadMimeTypeExtra(const QString &mimeName)
513{
514#if QT_CONFIG(xmlstreamreader)
515 auto it = m_mimetypeExtra.find(mimeName);
516 if (it == m_mimetypeExtra.cend()) {
517 // load comment and globPatterns
518
519 // shared-mime-info since 1.3 lowercases the xml files
520 QString mimeFile = m_directory + u'/' + mimeName.toLower() + ".xml"_L1;
521 if (!QFile::exists(mimeFile))
522 mimeFile = m_directory + u'/' + mimeName + ".xml"_L1; // pre-1.3
523
524 QFile qfile(mimeFile);
525 if (!qfile.open(QFile::ReadOnly))
526 return m_mimetypeExtra.cend();
527
528 it = m_mimetypeExtra.try_emplace(mimeName).first;
529 MimeTypeExtra &extra = it->second;
530 QString mainPattern;
531
532 QXmlStreamReader xml(&qfile);
533 if (xml.readNextStartElement()) {
534 if (xml.name() != "mime-type"_L1) {
535 return m_mimetypeExtra.cend();
536 }
537 const auto name = xml.attributes().value("type"_L1);
538 if (name.isEmpty())
539 return m_mimetypeExtra.cend();
540 if (name.compare(mimeName, Qt::CaseInsensitive))
541 qWarning() << "Got name" << name << "in file" << mimeFile << "expected" << mimeName;
542
543 while (xml.readNextStartElement()) {
544 const auto tag = xml.name();
545 if (tag == "comment"_L1) {
546 QString lang = xml.attributes().value("xml:lang"_L1).toString();
547 const QString text = xml.readElementText();
548 if (lang.isEmpty()) {
549 lang = "default"_L1; // no locale attribute provided, treat it as default.
550 }
551 extra.localeComments.insert(lang, text);
552 continue; // we called readElementText, so we're at the EndElement already.
553 } else if (tag == "glob-deleteall"_L1) { // as written out by shared-mime-info >= 0.70
554 extra.hasGlobDeleteAll = true;
555 } else if (tag == "glob"_L1) { // as written out by shared-mime-info >= 0.70
556 const QString pattern = xml.attributes().value("pattern"_L1).toString();
557 if (mainPattern.isEmpty() && pattern.startsWith(u'*')) {
558 mainPattern = pattern;
559 }
560 appendIfNew(extra.globPatterns, pattern);
561 }
562 xml.skipCurrentElement();
563 }
564 Q_ASSERT(xml.name() == "mime-type"_L1);
565 }
566
567 // Let's assume that shared-mime-info is at least version 0.70
568 // Otherwise we would need 1) a version check, and 2) code for parsing patterns from the globs file.
569 if (!mainPattern.isEmpty() &&
570 (extra.globPatterns.isEmpty() || extra.globPatterns.constFirst() != mainPattern)) {
571 // ensure it's first in the list of patterns
572 extra.globPatterns.removeAll(mainPattern);
573 extra.globPatterns.prepend(mainPattern);
574 }
575 }
576 return it;
577#else
578 Q_UNUSED(mimeName);
579 qWarning("Cannot load mime type since QXmlStreamReader is not available.");
580 return m_mimetypeExtra.cend();
581#endif // feature xmlstreamreader
582}
583
584// Binary search in the icons or generic-icons list
585QLatin1StringView QMimeBinaryProvider::iconForMime(CacheFile *cacheFile, int posListOffset,
586 const QByteArray &inputMime)
587{
588 const int iconsListOffset = cacheFile->getUint32(posListOffset);
589 const int numIcons = cacheFile->getUint32(iconsListOffset);
590 int begin = 0;
591 int end = numIcons - 1;
592 while (begin <= end) {
593 const int medium = (begin + end) / 2;
594 const int off = iconsListOffset + 4 + 8 * medium;
595 const int mimeOffset = cacheFile->getUint32(off);
596 const char *mime = cacheFile->getCharStar(mimeOffset);
597 const int cmp = qstrcmp(mime, inputMime);
598 if (cmp < 0)
599 begin = medium + 1;
600 else if (cmp > 0)
601 end = medium - 1;
602 else {
603 const int iconOffset = cacheFile->getUint32(off + 4);
604 return QLatin1StringView(cacheFile->getCharStar(iconOffset));
605 }
606 }
607 return QLatin1StringView();
608}
609
611{
612 const QByteArray inputMime = name.toLatin1();
613 return iconForMime(m_cacheFile.get(), PosIconsListOffset, inputMime);
614}
615
617{
618 const QByteArray inputMime = name.toLatin1();
619 return iconForMime(m_cacheFile.get(), PosGenericIconsListOffset, inputMime);
620}
621
623
624#if QT_CONFIG(mimetype_database)
625static QString internalMimeFileName()
626{
627 return QStringLiteral("<internal MIME data>");
628}
629
631 : QMimeProviderBase(db, internalMimeFileName())
632{
633 static_assert(sizeof(mimetype_database), "Bundled MIME database is empty");
634 static_assert(sizeof(mimetype_database) <= MimeTypeDatabaseOriginalSize,
635 "Compressed MIME database is larger than the original size");
636 static_assert(MimeTypeDatabaseOriginalSize <= 16*1024*1024,
637 "Bundled MIME database is too big");
638 const char *data = reinterpret_cast<const char *>(mimetype_database);
639 qsizetype size = MimeTypeDatabaseOriginalSize;
640
641#ifdef MIME_DATABASE_IS_ZSTD
642 // uncompress with libzstd
643 std::unique_ptr<char []> uncompressed(new char[size]);
644 size = ZSTD_decompress(uncompressed.get(), size, mimetype_database, sizeof(mimetype_database));
645 Q_ASSERT(!ZSTD_isError(size));
646 data = uncompressed.get();
647#elif defined(MIME_DATABASE_IS_GZIP)
648 std::unique_ptr<char []> uncompressed(new char[size]);
649 z_stream zs = {};
650 zs.next_in = const_cast<Bytef *>(mimetype_database);
651 zs.avail_in = sizeof(mimetype_database);
652 zs.next_out = reinterpret_cast<Bytef *>(uncompressed.get());
653 zs.avail_out = size;
654
655 int res = inflateInit2(&zs, MAX_WBITS | 32);
656 Q_ASSERT(res == Z_OK);
657 res = inflate(&zs, Z_FINISH);
658 Q_ASSERT(res == Z_STREAM_END);
659 res = inflateEnd(&zs);
660 Q_ASSERT(res == Z_OK);
661
662 data = uncompressed.get();
663 size = zs.total_out;
664#endif
665
666 load(data, size);
667}
668#else // !QT_CONFIG(mimetype_database)
669// never called in release mode, but some debug builds may need
670// this to be defined.
676#endif // QT_CONFIG(mimetype_database)
677
683
687
689{
690 // If you change this method, adjust the logic in QMimeDatabasePrivate::loadProviders,
691 // which assumes isValid==false is only possible in QMimeBinaryProvider.
692 return true;
693}
694
696{
697#if QT_CONFIG(mimetype_database)
698 return m_directory == internalMimeFileName();
699#else
700 return false;
701#endif
702}
703
705{
706 return m_nameMimeTypeMap.contains(name);
707}
708
710{
711 auto filterFunc = [this](const QString &name) { return !isMimeTypeGlobsExcluded(name); };
712 m_mimeTypeGlobs.matchingGlobs(fileName, result, filterFunc);
713}
714
716{
717 for (const QMimeMagicRuleMatcher &matcher : std::as_const(m_magicMatchers)) {
718 if (matcher.matches(data)) {
719 const int priority = matcher.priority();
720 if (priority > result.accuracy) {
721 result.accuracy = priority;
722 result.candidate = matcher.mimetype();
723 }
724 }
725 }
726}
727
729{
730 QStringList allFiles;
731 const QString packageDir = m_directory + QStringView(u"/packages");
732 QDir dir(packageDir);
734 allFiles.reserve(files.size());
735 for (const QString &xmlFile : files)
736 allFiles.append(packageDir + u'/' + xmlFile);
737
738 if (m_allFiles == allFiles)
739 return;
740 m_allFiles = allFiles;
741
742 m_nameMimeTypeMap.clear();
743 m_aliases.clear();
744 m_parents.clear();
745 m_mimeTypeGlobs.clear();
746 m_magicMatchers.clear();
747
748 //qDebug() << "Loading" << m_allFiles;
749
750 for (const QString &file : std::as_const(allFiles))
751 load(file);
752}
753
758
760{
761 return m_nameMimeTypeMap.value(name).hasGlobDeleteAll;
762}
763
765{
766 return m_nameMimeTypeMap.value(name).globPatterns;
767}
768
770{
771 return m_nameMimeTypeMap.value(name).iconName;
772}
773
775{
776 return m_nameMimeTypeMap.value(name).genericIconName;
777}
778
780{
782 if (!load(fileName, &errorMessage))
783 qWarning("QMimeDatabase: Error loading %ls\n%ls", qUtf16Printable(fileName), qUtf16Printable(errorMessage));
784}
785
787{
790 if (errorMessage)
791 *errorMessage = "Cannot open "_L1 + fileName + ": "_L1 + file.errorString();
792 return false;
793 }
794
795 if (errorMessage)
796 errorMessage->clear();
797
798 QMimeTypeParser parser(*this);
799 return parser.parse(&file, fileName, errorMessage);
800}
801
802#if QT_CONFIG(mimetype_database)
803void QMimeXMLProvider::load(const char *data, qsizetype len)
804{
809 QMimeTypeParser parser(*this);
810 if (!parser.parse(&buffer, internalMimeFileName(), &errorMessage))
811 qWarning("QMimeDatabase: Error loading internal MIME data\n%s", qPrintable(errorMessage));
812}
813#endif
814
816{
817 m_mimeTypeGlobs.addGlob(glob);
818}
819
821{
822 m_nameMimeTypeMap.insert(mt.name, mt);
823}
824
826{
827 for (const QString &parent : m_parents.value(mime)) {
828 if (!result.contains(parent))
829 result.append(parent);
830 }
831}
832
834{
835 m_parents[child].append(parent);
836}
837
839{
840 // Iterate through the whole hash. This method is rarely used.
841 for (const auto &[alias, mimeName] : std::as_const(m_aliases).asKeyValueRange()) {
842 if (mimeName == name)
843 appendIfNew(result, alias);
844 }
845}
846
848{
849 return m_aliases.value(name);
850}
851
853{
854 m_aliases.insert(alias, name);
855}
856
858{
859 if (result.isEmpty()) { // fast path
860 for (auto it = m_nameMimeTypeMap.constBegin(), end = m_nameMimeTypeMap.constEnd();
861 it != end; ++it) {
862 result.append(QMimeType(QMimeTypePrivate(it.value().name)));
863 }
864 } else {
865 for (auto it = m_nameMimeTypeMap.constBegin(), end = m_nameMimeTypeMap.constEnd() ; it != end ; ++it) {
866 const QString newMime = it.key();
867 if (std::find_if(result.constBegin(), result.constEnd(), [newMime](const QMimeType &mime) -> bool { return mime.name() == newMime; })
868 == result.constEnd())
869 result.append(QMimeType(QMimeTypePrivate(it.value().name)));
870 }
871 }
872}
873
878
struct capHdr __attribute__
\inmodule QtCore \reentrant
Definition qbuffer.h:16
void setData(const QByteArray &data)
Sets the contents of the internal buffer to be data.
Definition qbuffer.cpp:259
\inmodule QtCore
Definition qbytearray.h:57
static QByteArray fromRawData(const char *data, qsizetype size)
Constructs a QByteArray that uses the first size bytes of the data array.
Definition qbytearray.h:409
\inmodule QtCore
\inmodule QtCore\reentrant
Definition qdatetime.h:283
\inmodule QtCore
Definition qdir.h:20
@ Files
Definition qdir.h:23
@ NoDotAndDotDot
Definition qdir.h:44
uchar * map(qint64 offset, qint64 size, MemoryMapFlags flags=NoOptions)
Maps size bytes of the file into memory starting at offset.
bool atEnd() const override
Returns true if the end of the file has been reached; otherwise returns false.
void close() override
Calls QFileDevice::flush() and closes the file.
QDateTime lastModified() const
Returns the date and time when the file was last modified.
Definition qfileinfo.h:160
\inmodule QtCore
Definition qfile.h:93
QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition qfile.cpp:904
bool exists() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qfile.cpp:351
qint64 size() const override
\reimp
Definition qfile.cpp:1179
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
Definition qhash.h:1219
const_iterator constBegin() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1215
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
Definition qhash.h:1007
T value(const Key &key) const noexcept
Definition qhash.h:1054
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Removes all items from the hash and frees up all memory used by it.
Definition qhash.h:951
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1303
qint64 readLine(char *data, qint64 maxlen)
This function reads a line of ASCII characters from the device, up to a maximum of maxSize - 1 bytes,...
bool isOpen() const
Returns true if the device is open; otherwise returns false.
QString errorString() const
Returns a human-readable description of the last device error that occurred.
void push_back(parameter_type t)
Definition qlist.h:675
void append(parameter_type t)
Definition qlist.h:458
void clear()
Definition qlist.h:434
void addGlob(const QMimeGlobPattern &glob)
void matchingGlobs(const QString &fileName, QMimeGlobMatchResult &result, const AddMatchFilterFunc &filterFunc) const
void addFileNameMatches(const QString &fileName, QMimeGlobMatchResult &result) override
QString resolveAlias(const QString &name) override
void findByMagic(const QByteArray &data, QMimeMagicResult &result) override
bool knowsMimeType(const QString &name) override
QString icon(const QString &name) override
bool hasGlobDeleteAll(const QString &name) override
void ensureLoaded() override
bool isValid() override
void addAliases(const QString &name, QStringList &result) override
virtual ~QMimeBinaryProvider()
void addAllMimeTypes(QList< QMimeType > &result) override
void addParents(const QString &mime, QStringList &result) override
QMimeBinaryProvider(QMimeDatabasePrivate *db, const QString &directory)
QStringList globPatterns(const QString &name) override
QString genericIcon(const QString &name) override
bool isInternalDatabase() const override
QMimeTypePrivate::LocaleHash localeComments(const QString &name) override
The QMimeGlobPattern class contains the glob pattern for file names for MIME type matching.
The QMimeMagicRuleMatcher class checks a number of rules based on operator "or".
static bool matchSubstring(const char *dataPtr, qsizetype dataSize, int rangeStart, int rangeLength, qsizetype valueLength, const char *valueData, const char *mask)
bool isMimeTypeGlobsExcluded(const QString &name) const
QMimeProviderBase * m_overrideProvider
virtual bool hasGlobDeleteAll(const QString &name)=0
QMimeProviderBase * overrideProvider() const
void setOverrideProvider(QMimeProviderBase *provider)
QMimeProviderBase(QMimeDatabasePrivate *db, const QString &directory)
bool parse(QIODevice *dev, const QString &fileName, QString *errorMessage)
\inmodule QtCore
QStringList globPatterns
QMimeTypePrivate::LocaleHash localeComments
\inmodule QtCore
Definition qmimetype.h:25
void addFileNameMatches(const QString &fileName, QMimeGlobMatchResult &result) override
void addGlobPattern(const QMimeGlobPattern &glob)
void addAliases(const QString &name, QStringList &result) override
void addAlias(const QString &alias, const QString &name)
QMimeTypePrivate::LocaleHash localeComments(const QString &name) override
QStringList globPatterns(const QString &name) override
bool load(const QString &fileName, QString *errorMessage)
void ensureLoaded() override
bool knowsMimeType(const QString &name) override
bool isValid() override
bool isInternalDatabase() const override
QString resolveAlias(const QString &name) override
void addMimeType(const QMimeTypeXMLData &mt)
void findByMagic(const QByteArray &data, QMimeMagicResult &result) override
QString icon(const QString &name) override
void addParents(const QString &mime, QStringList &result) override
void addAllMimeTypes(QList< QMimeType > &result) override
QMimeXMLProvider(QMimeDatabasePrivate *db, InternalDatabaseEnum)
void addMagicMatcher(const QMimeMagicRuleMatcher &matcher)
bool hasGlobDeleteAll(const QString &name) override
void addParent(const QString &child, const QString &parent)
QString genericIcon(const QString &name) override
qsizetype size() const
Definition qset.h:50
void clear()
Definition qset.h:61
bool contains(const T &value) const
Definition qset.h:71
iterator insert(const T &value)
Definition qset.h:155
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Returns the substring of length length starting at position start in this object.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
void reserve(qsizetype size)
Ensures the string has space for at least size characters.
Definition qstring.h:1325
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
QString & insert(qsizetype i, QChar c)
Definition qstring.cpp:3132
QString toLower() const &
Definition qstring.h:435
QString str
[2]
p1 load("image.bmp")
QString text
QSet< QString >::iterator it
Combined button and popup list for selecting options.
constexpr const T & min(const T &a, const T &b)
Definition qnumeric.h:366
CaseSensitivity
@ CaseInsensitive
@ CaseSensitive
Q_CORE_EXPORT int qstrcmp(const char *str1, const char *str2)
AudioChannelLayoutTag tag
constexpr T qFromBigEndian(T source)
Definition qendian.h:174
const char * mimeType
#define qWarning
Definition qlogging.h:166
@ PosReverseSuffixTreeOffset
@ PosGlobListOffset
@ PosIconsListOffset
@ PosLiteralListOffset
@ PosAliasListOffset
@ PosMagicListOffset
@ PosParentListOffset
@ PosGenericIconsListOffset
static void appendIfNew(QStringList &list, const QString &str)
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLuint end
GLenum GLsizei dataSize
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint GLuint GLfloat weight
GLenum GLuint buffer
GLenum GLuint GLintptr offset
GLuint name
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLuint res
GLuint64EXT * result
[6]
GLenum GLsizei len
GLubyte * pattern
GLenum GLenum GLenum input
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
Int aligned(Int v, Int byteAlign)
#define qPrintable(string)
Definition qstring.h:1531
#define qUtf16Printable(string)
Definition qstring.h:1543
#define QStringLiteral(str)
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:50
unsigned char uchar
Definition qtypes.h:32
unsigned short quint16
Definition qtypes.h:48
ptrdiff_t qsizetype
Definition qtypes.h:165
static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition)
Definition qurl.cpp:3517
static int inflate(Bytef *dest, ulong *destLen, const Bytef *source, ulong sourceLen)
Definition qzip.cpp:92
QList< int > list
[14]
QFile file
[0]
application x qt windows mime
[2]
QMimeDatabase db
[0]
static const auto matcher
[0]
QXmlStreamReader xml
[0]
QString dir
[11]
QStringList files
[8]
QLayoutItem * child
[0]
bool contains(const AT &t) const noexcept
Definition qlist.h:45
const char * getCharStar(int offset) const
quint16 getUint16(int offset) const
CacheFile(const QString &fileName)
quint32 getUint32(int offset) const
The QMimeGlobMatchResult class accumulates results from glob matching.