6#include <qplatformdefs.h>
14#include <private/qduplicatetracker_p.h>
15#include <private/qfilesystementry_p.h>
17#include <QtCore/QFile>
18#include <QtCore/QFileInfo>
19#include <QtCore/QStandardPaths>
20#include <QtCore/QBuffer>
22#include <QtCore/QDebug>
30using namespace Qt::StringLiterals;
34 return QStringLiteral(
"inode/directory");
38 return QStringLiteral(
"text/plain");
45 return staticQMimeDatabase();
49 : m_defaultMimeType(QStringLiteral(
"application/octet-stream"))
58#ifdef QT_BUILD_INTERNAL
67 if (m_lastCheck.isValid() && m_lastCheck.elapsed() < qmime_secondsBetweenChecks * 1000)
76 QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral(
"mime"),
77 QStandardPaths::LocateDirectory);
78 dirs.append(u":/qt-project.org/qmime"_s);
82#if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY)
89 const QStringList mimeDirs = locateMimeDirectories();
90 const auto fdoIterator =
std::find_if(mimeDirs.constBegin(), mimeDirs.constEnd(), [](
const QString &mimeDir) ->
bool {
91 return QFileInfo::exists(mimeDir +
"/packages/freedesktop.org.xml"_L1); }
96 Providers currentProviders;
97 std::swap(m_providers, currentProviders);
99 m_providers.reserve(mimeDirs.size() + (needInternalDB ? 1 : 0));
101 for (
const QString &mimeDir : mimeDirs) {
102 const QString cacheFile = mimeDir +
"/mime.cache"_L1;
104 const auto predicate = [mimeDir](
const std::unique_ptr<QMimeProviderBase> &prov)
106 return prov && prov->directory() == mimeDir;
108 const auto it = std::find_if(currentProviders.begin(), currentProviders.end(), predicate);
109 if (it == currentProviders.end()) {
110 std::unique_ptr<QMimeProviderBase> provider;
111#if defined(QT_USE_MMAP)
112 if (qEnvironmentVariableIsEmpty(
"QT_NO_MIME_CACHE") && QFileInfo::exists(cacheFile)) {
113 provider.reset(
new QMimeBinaryProvider(
this, mimeDir));
115 if (!provider->isValid()) {
121 provider.reset(
new QMimeXMLProvider(
this, mimeDir));
124 m_providers.push_back(std::move(provider));
126 auto provider = std::move(*it);
127 provider->ensureLoaded();
128 if (!provider->isValid()) {
129 provider.reset(
new QMimeXMLProvider(
this, mimeDir));
132 m_providers.push_back(std::move(provider));
137 if (needInternalDB) {
139 const auto isInternal = [](
const std::unique_ptr<QMimeProviderBase> &prov)
141 return prov && prov->isInternalDatabase();
143 const auto it =
std::find_if(currentProviders.begin(), currentProviders.end(), isInternal);
144 if (it == currentProviders.end()) {
145 m_providers.push_back(Providers::value_type(
new QMimeXMLProvider(
this, QMimeXMLProvider::InternalDatabase)));
147 m_providers.push_back(std::move(*it));
151 auto it = m_providers.begin();
152 (*it)->setOverrideProvider(
nullptr);
154 const auto end = m_providers.end();
155 for (; it != end; ++it)
156 (*it)->setOverrideProvider((it - 1)->get());
162 Q_ASSERT(!mutex.tryLock());
164 if (m_providers.empty()) {
176 for (
const auto &provider : providers()) {
177 const QString ret = provider->resolveAlias(nameOrAlias);
185
186
187
190 const QString mimeName = resolveAlias(nameOrAlias);
191 for (
const auto &provider : providers()) {
192 if (provider->knowsMimeType(mimeName))
193 return QMimeType(QMimeTypePrivate(mimeName));
200 if (fileName.endsWith(u'/'))
201 return { directoryMimeType() };
203 const QMimeGlobMatchResult result = findByFileName(fileName);
204 QStringList matchingMimeTypes = result.m_matchingMimeTypes;
205 matchingMimeTypes.sort();
206 return matchingMimeTypes;
211 QMimeGlobMatchResult result;
212 const QString fileNameExcludingPath = QFileSystemEntry(fileName).fileName();
213 for (
const auto &provider : providers())
214 provider->addFileNameMatches(fileNameExcludingPath, result);
220 QMutexLocker locker(&mutex);
221 for (
const auto &provider : providers()) {
222 auto comments = provider->localeComments(name);
223 if (!comments.isEmpty())
232 QMutexLocker locker(&mutex);
233 QStringList patterns;
234 const auto &providerList = providers();
237 for (
auto rit = providerList.rbegin(); rit != providerList.rend(); ++rit) {
238 auto *provider = rit->get();
239 if (provider->hasGlobDeleteAll(name))
241 patterns += provider->globPatterns(name);
248 QMutexLocker locker(&mutex);
249 for (
const auto &provider : providers()) {
250 QString genericIconName = provider->genericIcon(name);
251 if (!genericIconName.isEmpty())
252 return genericIconName;
259 QMutexLocker locker(&mutex);
260 for (
const auto &provider : providers()) {
261 QString iconName = provider->icon(name);
262 if (!iconName.isEmpty())
270 const QStringView myGroup = QStringView{mimeTypeName}.left(mimeTypeName.indexOf(u'/'));
272 if (myGroup ==
"text"_L1 && mimeTypeName != plainTextMimeType())
273 return plainTextMimeType();
275 if (myGroup !=
"inode"_L1 &&
277 myGroup !=
"all"_L1 && myGroup !=
"fonts"_L1 && myGroup !=
"print"_L1 && myGroup !=
"uri"_L1
278 && mimeTypeName != defaultMimeType()) {
279 return defaultMimeType();
286 QMutexLocker locker(&mutex);
287 return parents(mimeName);
292 Q_ASSERT(!mutex.tryLock());
294 for (
const auto &provider : providers())
295 provider->addParents(mimeName, result);
296 if (result.isEmpty()) {
297 const QString parent = fallbackParent(mimeName);
298 if (!parent.isEmpty())
299 result.append(parent);
306 QMutexLocker locker(&mutex);
308 for (
const auto &provider : providers())
309 provider->addAliases(mimeName, result);
315 QMutexLocker locker(&mutex);
316 return inherits(mime, parent);
322 static const char bigEndianBOM[] =
"\xFE\xFF";
323 static const char littleEndianBOM[] =
"\xFF\xFE";
324 if (data.startsWith(bigEndianBOM) || data.startsWith(littleEndianBOM))
328 const char *p = data.constData();
329 const char *e = p + qMin(128, data.size());
330 for ( ; p < e; ++p) {
331 if (
static_cast<
unsigned char>(*p) < 32 && *p != 9 && *p !=10 && *p != 13)
340 if (data.isEmpty()) {
342 return mimeTypeForName(QStringLiteral(
"application/x-zerosize"));
346 for (
const auto &provider : providers())
347 provider->findByMagic(data, result);
351 return QMimeType(QMimeTypePrivate(result.candidate));
356 return mimeTypeForName(plainTextMimeType());
359 return mimeTypeForName(defaultMimeType());
371 QMimeGlobMatchResult candidatesByName = findByFileName(fileName);
372 if (candidatesByName.m_allMatchingMimeTypes.size() == 1) {
373 const QMimeType mime = mimeTypeForName(candidatesByName.m_matchingMimeTypes.at(0));
376 candidatesByName = {};
381 const auto matchOnContent = [
this, &candidatesByName](QIODevice *device) {
382 const bool openedByUs = !device->isOpen() && device->open(QIODevice::ReadOnly);
383 if (device->isOpen()) {
391 int magicAccuracy = 0;
392 QMimeType candidateByData(findByData(data, &magicAccuracy));
395 if (candidateByData.isValid() && magicAccuracy > 0) {
396 const QString sniffedMime = candidateByData.name();
398 if (candidatesByName.m_matchingMimeTypes.contains(sniffedMime))
399 return candidateByData;
401 for (
const QString &m : std::as_const(candidatesByName.m_allMatchingMimeTypes)) {
402 if (inherits(m, sniffedMime)) {
404 return mimeTypeForName(m);
407 if (candidatesByName.m_allMatchingMimeTypes.isEmpty()) {
409 return candidateByData;
414 if (candidatesByName.m_allMatchingMimeTypes.size() > 1) {
415 candidatesByName.m_matchingMimeTypes.sort();
416 const QMimeType mime = mimeTypeForName(candidatesByName.m_matchingMimeTypes.at(0));
421 return mimeTypeForName(defaultMimeType());
425 return matchOnContent(device);
427 QFile fallbackFile(fileName);
428 return matchOnContent(&fallbackFile);
433 const QStringList matches = mimeTypeForFileName(fileName);
434 if (matches.isEmpty()) {
435 return mimeTypeForName(defaultMimeType());
438 return mimeTypeForName(matches.first());
445 const bool openedByUs = !device->isOpen() && device->open(QIODevice::ReadOnly);
446 if (device->isOpen()) {
450 QMimeType result = findByData(data, &accuracy);
455 return mimeTypeForName(defaultMimeType());
459 const QFileInfo &fileInfo,
460 QMimeDatabase::MatchMode mode)
464 }
else if (fileInfo.isNativePath()) {
467 const QByteArray nativeFilePath = QFile::encodeName(fileName);
468 QT_STATBUF statBuffer;
469 if (QT_STAT(nativeFilePath.constData(), &statBuffer) == 0) {
470 if (S_ISDIR(statBuffer.st_mode))
471 return mimeTypeForName(directoryMimeType());
472 if (S_ISCHR(statBuffer.st_mode))
473 return mimeTypeForName(QStringLiteral(
"inode/chardevice"));
474 if (S_ISBLK(statBuffer.st_mode))
475 return mimeTypeForName(QStringLiteral(
"inode/blockdevice"));
476 if (S_ISFIFO(statBuffer.st_mode))
477 return mimeTypeForName(QStringLiteral(
"inode/fifo"));
478 if (S_ISSOCK(statBuffer.st_mode))
479 return mimeTypeForName(QStringLiteral(
"inode/socket"));
482 }
else if (fileInfo.isDir()) {
483 return mimeTypeForName(directoryMimeType());
487 case QMimeDatabase::MatchDefault:
489 case QMimeDatabase::MatchExtension:
490 return mimeTypeForFileExtension(fileName);
491 case QMimeDatabase::MatchContent: {
492 QFile file(fileName);
493 return mimeTypeForData(&file);
497 return mimeTypeForFileNameAndData(fileName,
nullptr);
502 QList<QMimeType> result;
503 for (
const auto &provider : providers())
504 provider->addAllMimeTypes(result);
510 const QString resolvedParent = resolveAlias(parent);
511 QDuplicateTracker<QString> seen;
512 std::stack<QString, QStringList> toCheck;
514 while (!toCheck.empty()) {
515 if (toCheck.top() == resolvedParent)
517 const QString mimeName = toCheck.top();
519 const auto parentList = parents(mimeName);
520 for (
const QString &par : parentList) {
521 const QString resolvedPar = resolveAlias(par);
522 if (!seen.hasSeen(resolvedPar))
523 toCheck.push(resolvedPar);
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
570
571
572
573
574
575
576
577
578QMimeDatabase::QMimeDatabase() :
579 d(staticQMimeDatabase())
584
585
586
587QMimeDatabase::~QMimeDatabase()
593
594
595
596QMimeType QMimeDatabase::mimeTypeForName(
const QString &nameOrAlias)
const
598 QMutexLocker locker(&d->mutex);
600 return d->mimeTypeForName(nameOrAlias);
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631QMimeType QMimeDatabase::mimeTypeForFile(
const QFileInfo &fileInfo, MatchMode mode)
const
633 QMutexLocker locker(&d->mutex);
635 return d->mimeTypeForFile(fileInfo.filePath(), fileInfo, mode);
639
640
641
642
643QMimeType QMimeDatabase::mimeTypeForFile(
const QString &fileName, MatchMode mode)
const
645 QMutexLocker locker(&d->mutex);
647 if (mode == MatchExtension) {
648 return d->mimeTypeForFileExtension(fileName);
650 QFileInfo fileInfo(fileName);
651 return d->mimeTypeForFile(fileName, fileInfo, mode);
656
657
658
659
660
661
662
663
664
665
666
667QList<QMimeType> QMimeDatabase::mimeTypesForFileName(
const QString &fileName)
const
669 QMutexLocker locker(&d->mutex);
671 const QStringList matches = d->mimeTypeForFileName(fileName);
672 QList<QMimeType> mimes;
673 mimes.reserve(matches.size());
674 for (
const QString &mime : matches)
675 mimes.append(d->mimeTypeForName(mime));
679
680
681
682
683
684QString QMimeDatabase::suffixForFileName(
const QString &fileName)
const
686 QMutexLocker locker(&d->mutex);
687 const qsizetype suffixLength = d->findByFileName(fileName).m_knownSuffixLength;
688 return fileName.right(suffixLength);
692
693
694
695
696
697
698QMimeType QMimeDatabase::mimeTypeForData(
const QByteArray &data)
const
700 QMutexLocker locker(&d->mutex);
703 return d->findByData(data, &accuracy);
707
708
709
710
711
712
713QMimeType QMimeDatabase::mimeTypeForData(QIODevice *device)
const
715 QMutexLocker locker(&d->mutex);
717 return d->mimeTypeForData(device);
721
722
723
724
725
726
727
728
729
730
731
732
733
734QMimeType QMimeDatabase::mimeTypeForUrl(
const QUrl &url)
const
736 if (url.isLocalFile())
737 return mimeTypeForFile(url.toLocalFile());
739 const QString scheme = url.scheme();
740 if (scheme.startsWith(
"http"_L1) || scheme ==
"mailto"_L1)
741 return mimeTypeForName(d->defaultMimeType());
743 return mimeTypeForFile(url.path(), MatchExtension);
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765QMimeType QMimeDatabase::mimeTypeForFileNameAndData(
const QString &fileName, QIODevice *device)
const
767 QMutexLocker locker(&d->mutex);
769 if (fileName.endsWith(u'/'))
770 return d->mimeTypeForName(directoryMimeType());
772 const QMimeType result = d->mimeTypeForFileNameAndData(fileName, device);
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792QMimeType QMimeDatabase::mimeTypeForFileNameAndData(
const QString &fileName,
const QByteArray &data)
const
794 QMutexLocker locker(&d->mutex);
796 if (fileName.endsWith(u'/'))
797 return d->mimeTypeForName(directoryMimeType());
799 QBuffer buffer(
const_cast<QByteArray *>(&data));
800 buffer.open(QIODevice::ReadOnly);
801 return d->mimeTypeForFileNameAndData(fileName, &buffer);
805
806
807
808
809
810
811QList<QMimeType> QMimeDatabase::allMimeTypes()
const
813 QMutexLocker locker(&d->mutex);
815 return d->allMimeTypes();
819
820
821
822
823
824
825
826
827
828
QString resolveAlias(const QString &nameOrAlias)
QStringList listAliases(const QString &mimeName)
QList< QMimeType > allMimeTypes()
QString genericIcon(const QString &name)
QMimeTypePrivate::LocaleHash localeComments(const QString &name)
bool mimeInherits(const QString &mime, const QString &parent)
QMimeType mimeTypeForFileExtension(const QString &fileName)
QMimeType mimeTypeForFileNameAndData(const QString &fileName, QIODevice *device)
QMimeType mimeTypeForData(QIODevice *device)
QStringList mimeTypeForFileName(const QString &fileName)
bool inherits(const QString &mime, const QString &parent)
QMimeType mimeTypeForName(const QString &nameOrAlias)
QStringList mimeParents(const QString &mimeName)
QStringList globPatterns(const QString &name)
QString icon(const QString &name)
static QMimeDatabasePrivate * instance()
QMimeType mimeTypeForFile(const QString &fileName, const QFileInfo &fileInfo, QMimeDatabase::MatchMode mode)
QStringList parents(const QString &mimeName)
QMimeGlobMatchResult findByFileName(const QString &fileName)
QMimeType findByData(const QByteArray &data, int *priorityPtr)
@ InternalDatabaseAvailable
static bool isTextFile(const QByteArray &data)
static Q_CONSTINIT const int qmime_secondsBetweenChecks
static QStringList locateMimeDirectories()
static QString directoryMimeType()
static QString plainTextMimeType()