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 !=
"inode"_L1 &&
274 myGroup !=
"all"_L1 && myGroup !=
"fonts"_L1 && myGroup !=
"print"_L1 && myGroup !=
"uri"_L1
275 && mimeTypeName != defaultMimeType()) {
276 return defaultMimeType();
283 QMutexLocker locker(&mutex);
284 return parents(mimeName);
290 Q_ASSERT(!mutex.tryLock());
293 for (
const auto &provider : providers())
294 provider->addParents(mimeName, result);
299 if (mimeName.startsWith(
"text/"_L1) && mimeName != plainTextMimeType()
300 && !result.contains(plainTextMimeType())) {
301 result.append(plainTextMimeType());
304 if (result.isEmpty()) {
305 const QString parent = fallbackParent(mimeName);
306 if (!parent.isEmpty())
307 result.append(parent);
314 QMutexLocker locker(&mutex);
316 for (
const auto &provider : providers())
317 provider->addAliases(mimeName, result);
323 QMutexLocker locker(&mutex);
324 return inherits(mime, parent);
330 static const char bigEndianBOM[] =
"\xFE\xFF";
331 static const char littleEndianBOM[] =
"\xFF\xFE";
332 if (data.startsWith(bigEndianBOM) || data.startsWith(littleEndianBOM))
336 const char *p = data.constData();
337 const char *e = p + qMin(128, data.size());
338 for ( ; p < e; ++p) {
339 if (
static_cast<
unsigned char>(*p) < 32 && *p != 9 && *p !=10 && *p != 13)
348 if (data.isEmpty()) {
350 return mimeTypeForName(QStringLiteral(
"application/x-zerosize"));
354 for (
const auto &provider : providers())
355 provider->findByMagic(data, result);
359 return QMimeType(QMimeTypePrivate(result.candidate));
364 return mimeTypeForName(plainTextMimeType());
367 return mimeTypeForName(defaultMimeType());
379 QMimeGlobMatchResult candidatesByName = findByFileName(fileName);
380 if (candidatesByName.m_allMatchingMimeTypes.size() == 1) {
381 const QMimeType mime = mimeTypeForName(candidatesByName.m_matchingMimeTypes.at(0));
384 candidatesByName = {};
389 const auto matchOnContent = [
this, &candidatesByName](QIODevice *device) {
390 const bool openedByUs = !device->isOpen() && device->open(QIODevice::ReadOnly);
391 if (device->isOpen()) {
399 int magicAccuracy = 0;
400 QMimeType candidateByData(findByData(data, &magicAccuracy));
403 if (candidateByData.isValid() && magicAccuracy > 0) {
404 const QString sniffedMime = candidateByData.name();
406 if (candidatesByName.m_matchingMimeTypes.contains(sniffedMime))
407 return candidateByData;
409 for (
const QString &m : std::as_const(candidatesByName.m_allMatchingMimeTypes)) {
410 if (inherits(m, sniffedMime)) {
412 return mimeTypeForName(m);
415 if (candidatesByName.m_allMatchingMimeTypes.isEmpty()) {
417 return candidateByData;
422 if (candidatesByName.m_allMatchingMimeTypes.size() > 1) {
423 candidatesByName.m_matchingMimeTypes.sort();
424 const QMimeType mime = mimeTypeForName(candidatesByName.m_matchingMimeTypes.at(0));
429 return mimeTypeForName(defaultMimeType());
433 return matchOnContent(device);
435 QFile fallbackFile(fileName);
436 return matchOnContent(&fallbackFile);
441 const QStringList matches = mimeTypeForFileName(fileName);
442 if (matches.isEmpty()) {
443 return mimeTypeForName(defaultMimeType());
446 return mimeTypeForName(matches.first());
453 const bool openedByUs = !device->isOpen() && device->open(QIODevice::ReadOnly);
454 if (device->isOpen()) {
458 QMimeType result = findByData(data, &accuracy);
463 return mimeTypeForName(defaultMimeType());
467 const QFileInfo &fileInfo,
468 QMimeDatabase::MatchMode mode)
472 }
else if (fileInfo.isNativePath()) {
475 const QByteArray nativeFilePath = QFile::encodeName(fileName);
476 QT_STATBUF statBuffer;
477 if (QT_STAT(nativeFilePath.constData(), &statBuffer) == 0) {
478 if (S_ISDIR(statBuffer.st_mode))
479 return mimeTypeForName(directoryMimeType());
480 if (S_ISCHR(statBuffer.st_mode))
481 return mimeTypeForName(QStringLiteral(
"inode/chardevice"));
482 if (S_ISBLK(statBuffer.st_mode))
483 return mimeTypeForName(QStringLiteral(
"inode/blockdevice"));
484 if (S_ISFIFO(statBuffer.st_mode))
485 return mimeTypeForName(QStringLiteral(
"inode/fifo"));
486 if (S_ISSOCK(statBuffer.st_mode))
487 return mimeTypeForName(QStringLiteral(
"inode/socket"));
490 }
else if (fileInfo.isDir()) {
491 return mimeTypeForName(directoryMimeType());
495 case QMimeDatabase::MatchDefault:
497 case QMimeDatabase::MatchExtension:
498 return mimeTypeForFileExtension(fileName);
499 case QMimeDatabase::MatchContent: {
500 QFile file(fileName);
501 return mimeTypeForData(&file);
505 return mimeTypeForFileNameAndData(fileName,
nullptr);
510 QList<QMimeType> result;
511 for (
const auto &provider : providers())
512 provider->addAllMimeTypes(result);
518 const QString resolvedParent = resolveAlias(parent);
519 QDuplicateTracker<QString> seen;
520 std::stack<QString, QStringList> toCheck;
522 while (!toCheck.empty()) {
523 if (toCheck.top() == resolvedParent)
525 const QString mimeName = toCheck.top();
527 const auto parentList = parents(mimeName);
528 for (
const QString &par : parentList) {
529 const QString resolvedPar = resolveAlias(par);
530 if (!seen.hasSeen(resolvedPar))
531 toCheck.push(resolvedPar);
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
568
569
570
571
572
573
574
575
578
579
580
581
582
583
584
585
586QMimeDatabase::QMimeDatabase() :
587 d(staticQMimeDatabase())
592
593
594
595QMimeDatabase::~QMimeDatabase()
601
602
603
604QMimeType QMimeDatabase::mimeTypeForName(
const QString &nameOrAlias)
const
606 QMutexLocker locker(&d->mutex);
608 return d->mimeTypeForName(nameOrAlias);
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639QMimeType QMimeDatabase::mimeTypeForFile(
const QFileInfo &fileInfo, MatchMode mode)
const
641 QMutexLocker locker(&d->mutex);
643 return d->mimeTypeForFile(fileInfo.filePath(), fileInfo, mode);
647
648
649
650
651QMimeType QMimeDatabase::mimeTypeForFile(
const QString &fileName, MatchMode mode)
const
653 QMutexLocker locker(&d->mutex);
655 if (mode == MatchExtension) {
656 return d->mimeTypeForFileExtension(fileName);
658 QFileInfo fileInfo(fileName);
659 return d->mimeTypeForFile(fileName, fileInfo, mode);
664
665
666
667
668
669
670
671
672
673
674
675QList<QMimeType> QMimeDatabase::mimeTypesForFileName(
const QString &fileName)
const
677 QMutexLocker locker(&d->mutex);
679 const QStringList matches = d->mimeTypeForFileName(fileName);
680 QList<QMimeType> mimes;
681 mimes.reserve(matches.size());
682 for (
const QString &mime : matches)
683 mimes.append(d->mimeTypeForName(mime));
687
688
689
690
691
692QString QMimeDatabase::suffixForFileName(
const QString &fileName)
const
694 QMutexLocker locker(&d->mutex);
695 const qsizetype suffixLength = d->findByFileName(fileName).m_knownSuffixLength;
696 return fileName.right(suffixLength);
700
701
702
703
704
705
706QMimeType QMimeDatabase::mimeTypeForData(
const QByteArray &data)
const
708 QMutexLocker locker(&d->mutex);
711 return d->findByData(data, &accuracy);
715
716
717
718
719
720
721QMimeType QMimeDatabase::mimeTypeForData(QIODevice *device)
const
723 QMutexLocker locker(&d->mutex);
725 return d->mimeTypeForData(device);
729
730
731
732
733
734
735
736
737
738
739
740
741
742QMimeType QMimeDatabase::mimeTypeForUrl(
const QUrl &url)
const
744 if (url.isLocalFile())
745 return mimeTypeForFile(url.toLocalFile());
747 const QString scheme = url.scheme();
748 if (scheme.startsWith(
"http"_L1) || scheme ==
"mailto"_L1)
749 return mimeTypeForName(d->defaultMimeType());
751 return mimeTypeForFile(url.path(), MatchExtension);
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773QMimeType QMimeDatabase::mimeTypeForFileNameAndData(
const QString &fileName, QIODevice *device)
const
775 QMutexLocker locker(&d->mutex);
777 if (fileName.endsWith(u'/'))
778 return d->mimeTypeForName(directoryMimeType());
780 const QMimeType result = d->mimeTypeForFileNameAndData(fileName, device);
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800QMimeType QMimeDatabase::mimeTypeForFileNameAndData(
const QString &fileName,
const QByteArray &data)
const
802 QMutexLocker locker(&d->mutex);
804 if (fileName.endsWith(u'/'))
805 return d->mimeTypeForName(directoryMimeType());
807 QBuffer buffer(
const_cast<QByteArray *>(&data));
808 buffer.open(QIODevice::ReadOnly);
809 return d->mimeTypeForFileNameAndData(fileName, &buffer);
813
814
815
816
817
818
819QList<QMimeType> QMimeDatabase::allMimeTypes()
const
821 QMutexLocker locker(&d->mutex);
823 return d->allMimeTypes();
827
828
829
830
831
832
833
834
835
836
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()