5#include <qplatformdefs.h>
13#include <private/qduplicatetracker_p.h>
14#include <private/qfilesystementry_p.h>
16#include <QtCore/QFile>
17#include <QtCore/QFileInfo>
18#include <QtCore/QStandardPaths>
19#include <QtCore/QBuffer>
21#include <QtCore/QDebug>
29using namespace Qt::StringLiterals;
33 return QStringLiteral(
"inode/directory");
37 return QStringLiteral(
"text/plain");
44 return staticQMimeDatabase();
48 : m_defaultMimeType(QStringLiteral(
"application/octet-stream"))
57#ifdef QT_BUILD_INTERNAL
66 if (m_lastCheck.isValid() && m_lastCheck.elapsed() < qmime_secondsBetweenChecks * 1000)
75 QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral(
"mime"),
76 QStandardPaths::LocateDirectory);
77 dirs.append(u":/qt-project.org/qmime"_s);
81#if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY)
88 const QStringList mimeDirs = locateMimeDirectories();
89 const auto fdoIterator =
std::find_if(mimeDirs.constBegin(), mimeDirs.constEnd(), [](
const QString &mimeDir) ->
bool {
90 return QFileInfo::exists(mimeDir +
"/packages/freedesktop.org.xml"_L1); }
95 Providers currentProviders;
96 std::swap(m_providers, currentProviders);
98 m_providers.reserve(mimeDirs.size() + (needInternalDB ? 1 : 0));
100 for (
const QString &mimeDir : mimeDirs) {
101 const QString cacheFile = mimeDir +
"/mime.cache"_L1;
103 const auto predicate = [mimeDir](
const std::unique_ptr<QMimeProviderBase> &prov)
105 return prov && prov->directory() == mimeDir;
107 const auto it = std::find_if(currentProviders.begin(), currentProviders.end(), predicate);
108 if (it == currentProviders.end()) {
109 std::unique_ptr<QMimeProviderBase> provider;
110#if defined(QT_USE_MMAP)
111 if (qEnvironmentVariableIsEmpty(
"QT_NO_MIME_CACHE") && QFileInfo::exists(cacheFile)) {
112 provider.reset(
new QMimeBinaryProvider(
this, mimeDir));
114 if (!provider->isValid()) {
120 provider.reset(
new QMimeXMLProvider(
this, mimeDir));
123 m_providers.push_back(std::move(provider));
125 auto provider = std::move(*it);
126 provider->ensureLoaded();
127 if (!provider->isValid()) {
128 provider.reset(
new QMimeXMLProvider(
this, mimeDir));
131 m_providers.push_back(std::move(provider));
136 if (needInternalDB) {
138 const auto isInternal = [](
const std::unique_ptr<QMimeProviderBase> &prov)
140 return prov && prov->isInternalDatabase();
142 const auto it =
std::find_if(currentProviders.begin(), currentProviders.end(), isInternal);
143 if (it == currentProviders.end()) {
144 m_providers.push_back(Providers::value_type(
new QMimeXMLProvider(
this, QMimeXMLProvider::InternalDatabase)));
146 m_providers.push_back(std::move(*it));
150 auto it = m_providers.begin();
151 (*it)->setOverrideProvider(
nullptr);
153 const auto end = m_providers.end();
154 for (; it != end; ++it)
155 (*it)->setOverrideProvider((it - 1)->get());
161 Q_ASSERT(!mutex.tryLock());
163 if (m_providers.empty()) {
175 for (
const auto &provider : providers()) {
176 const QString ret = provider->resolveAlias(nameOrAlias);
184
185
186
189 const QString mimeName = resolveAlias(nameOrAlias);
190 for (
const auto &provider : providers()) {
191 if (provider->knowsMimeType(mimeName))
192 return QMimeType(QMimeTypePrivate(mimeName));
199 if (fileName.endsWith(u'/'))
200 return { directoryMimeType() };
202 const QMimeGlobMatchResult result = findByFileName(fileName);
203 QStringList matchingMimeTypes = result.m_matchingMimeTypes;
204 matchingMimeTypes.sort();
205 return matchingMimeTypes;
210 QMimeGlobMatchResult result;
211 const QString fileNameExcludingPath = QFileSystemEntry(fileName).fileName();
212 for (
const auto &provider : providers())
213 provider->addFileNameMatches(fileNameExcludingPath, result);
219 QMutexLocker locker(&mutex);
220 for (
const auto &provider : providers()) {
221 auto comments = provider->localeComments(name);
222 if (!comments.isEmpty())
231 QMutexLocker locker(&mutex);
232 QStringList patterns;
233 const auto &providerList = providers();
236 for (
auto rit = providerList.rbegin(); rit != providerList.rend(); ++rit) {
237 auto *provider = rit->get();
238 if (provider->hasGlobDeleteAll(name))
240 patterns += provider->globPatterns(name);
247 QMutexLocker locker(&mutex);
248 for (
const auto &provider : providers()) {
249 QString genericIconName = provider->genericIcon(name);
250 if (!genericIconName.isEmpty())
251 return genericIconName;
258 QMutexLocker locker(&mutex);
259 for (
const auto &provider : providers()) {
260 QString iconName = provider->icon(name);
261 if (!iconName.isEmpty())
269 const QStringView myGroup = QStringView{mimeTypeName}.left(mimeTypeName.indexOf(u'/'));
271 if (myGroup ==
"text"_L1 && mimeTypeName != plainTextMimeType())
272 return plainTextMimeType();
274 if (myGroup !=
"inode"_L1 &&
276 myGroup !=
"all"_L1 && myGroup !=
"fonts"_L1 && myGroup !=
"print"_L1 && myGroup !=
"uri"_L1
277 && mimeTypeName != defaultMimeType()) {
278 return defaultMimeType();
285 QMutexLocker locker(&mutex);
286 return parents(mimeName);
291 Q_ASSERT(!mutex.tryLock());
293 for (
const auto &provider : providers())
294 provider->addParents(mimeName, result);
295 if (result.isEmpty()) {
296 const QString parent = fallbackParent(mimeName);
297 if (!parent.isEmpty())
298 result.append(parent);
305 QMutexLocker locker(&mutex);
307 for (
const auto &provider : providers())
308 provider->addAliases(mimeName, result);
314 QMutexLocker locker(&mutex);
315 return inherits(mime, parent);
321 static const char bigEndianBOM[] =
"\xFE\xFF";
322 static const char littleEndianBOM[] =
"\xFF\xFE";
323 if (data.startsWith(bigEndianBOM) || data.startsWith(littleEndianBOM))
327 const char *p = data.constData();
328 const char *e = p + qMin(128, data.size());
329 for ( ; p < e; ++p) {
330 if (
static_cast<
unsigned char>(*p) < 32 && *p != 9 && *p !=10 && *p != 13)
339 if (data.isEmpty()) {
341 return mimeTypeForName(QStringLiteral(
"application/x-zerosize"));
345 for (
const auto &provider : providers())
346 provider->findByMagic(data, result);
350 return QMimeType(QMimeTypePrivate(result.candidate));
355 return mimeTypeForName(plainTextMimeType());
358 return mimeTypeForName(defaultMimeType());
370 QMimeGlobMatchResult candidatesByName = findByFileName(fileName);
371 if (candidatesByName.m_allMatchingMimeTypes.size() == 1) {
372 const QMimeType mime = mimeTypeForName(candidatesByName.m_matchingMimeTypes.at(0));
375 candidatesByName = {};
380 const auto matchOnContent = [
this, &candidatesByName](QIODevice *device) {
381 const bool openedByUs = !device->isOpen() && device->open(QIODevice::ReadOnly);
382 if (device->isOpen()) {
390 int magicAccuracy = 0;
391 QMimeType candidateByData(findByData(data, &magicAccuracy));
394 if (candidateByData.isValid() && magicAccuracy > 0) {
395 const QString sniffedMime = candidateByData.name();
397 if (candidatesByName.m_matchingMimeTypes.contains(sniffedMime)) {
398 return candidateByData;
400 for (
const QString &m : std::as_const(candidatesByName.m_allMatchingMimeTypes)) {
401 if (inherits(m, sniffedMime)) {
403 return mimeTypeForName(m);
406 if (candidatesByName.m_allMatchingMimeTypes.isEmpty()) {
408 return candidateByData;
413 if (candidatesByName.m_allMatchingMimeTypes.size() > 1) {
414 candidatesByName.m_matchingMimeTypes.sort();
415 const QMimeType mime = mimeTypeForName(candidatesByName.m_matchingMimeTypes.at(0));
420 return mimeTypeForName(defaultMimeType());
424 return matchOnContent(device);
426 QFile fallbackFile(fileName);
427 return matchOnContent(&fallbackFile);
432 const QStringList matches = mimeTypeForFileName(fileName);
433 if (matches.isEmpty()) {
434 return mimeTypeForName(defaultMimeType());
437 return mimeTypeForName(matches.first());
444 const bool openedByUs = !device->isOpen() && device->open(QIODevice::ReadOnly);
445 if (device->isOpen()) {
449 QMimeType result = findByData(data, &accuracy);
454 return mimeTypeForName(defaultMimeType());
458 const QFileInfo &fileInfo,
459 QMimeDatabase::MatchMode mode)
463 }
else if (fileInfo.isNativePath()) {
466 const QByteArray nativeFilePath = QFile::encodeName(fileName);
467 QT_STATBUF statBuffer;
468 if (QT_STAT(nativeFilePath.constData(), &statBuffer) == 0) {
469 if (S_ISDIR(statBuffer.st_mode))
470 return mimeTypeForName(directoryMimeType());
471 if (S_ISCHR(statBuffer.st_mode))
472 return mimeTypeForName(QStringLiteral(
"inode/chardevice"));
473 if (S_ISBLK(statBuffer.st_mode))
474 return mimeTypeForName(QStringLiteral(
"inode/blockdevice"));
475 if (S_ISFIFO(statBuffer.st_mode))
476 return mimeTypeForName(QStringLiteral(
"inode/fifo"));
477 if (S_ISSOCK(statBuffer.st_mode))
478 return mimeTypeForName(QStringLiteral(
"inode/socket"));
481 }
else if (fileInfo.isDir()) {
482 return mimeTypeForName(directoryMimeType());
486 case QMimeDatabase::MatchDefault:
488 case QMimeDatabase::MatchExtension:
489 return mimeTypeForFileExtension(fileName);
490 case QMimeDatabase::MatchContent: {
491 QFile file(fileName);
492 return mimeTypeForData(&file);
496 return mimeTypeForFileNameAndData(fileName,
nullptr);
501 QList<QMimeType> result;
502 for (
const auto &provider : providers())
503 provider->addAllMimeTypes(result);
509 const QString resolvedParent = resolveAlias(parent);
510 QDuplicateTracker<QString> seen;
511 std::stack<QString, QStringList> toCheck;
513 while (!toCheck.empty()) {
514 if (toCheck.top() == resolvedParent)
516 const QString mimeName = toCheck.top();
518 const auto parentList = parents(mimeName);
519 for (
const QString &par : parentList) {
520 const QString resolvedPar = resolveAlias(par);
521 if (!seen.hasSeen(resolvedPar))
522 toCheck.push(resolvedPar);
529
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
569
570
571
572
573
574
575
576
577QMimeDatabase::QMimeDatabase() :
578 d(staticQMimeDatabase())
583
584
585
586QMimeDatabase::~QMimeDatabase()
592
593
594
595QMimeType QMimeDatabase::mimeTypeForName(
const QString &nameOrAlias)
const
597 QMutexLocker locker(&d->mutex);
599 return d->mimeTypeForName(nameOrAlias);
603
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
630QMimeType QMimeDatabase::mimeTypeForFile(
const QFileInfo &fileInfo, MatchMode mode)
const
632 QMutexLocker locker(&d->mutex);
634 return d->mimeTypeForFile(fileInfo.filePath(), fileInfo, mode);
638
639
640
641
642QMimeType QMimeDatabase::mimeTypeForFile(
const QString &fileName, MatchMode mode)
const
644 QMutexLocker locker(&d->mutex);
646 if (mode == MatchExtension) {
647 return d->mimeTypeForFileExtension(fileName);
649 QFileInfo fileInfo(fileName);
650 return d->mimeTypeForFile(fileName, fileInfo, mode);
655
656
657
658
659
660
661
662
663
664
665
666QList<QMimeType> QMimeDatabase::mimeTypesForFileName(
const QString &fileName)
const
668 QMutexLocker locker(&d->mutex);
670 const QStringList matches = d->mimeTypeForFileName(fileName);
671 QList<QMimeType> mimes;
672 mimes.reserve(matches.size());
673 for (
const QString &mime : matches)
674 mimes.append(d->mimeTypeForName(mime));
678
679
680
681
682
683QString QMimeDatabase::suffixForFileName(
const QString &fileName)
const
685 QMutexLocker locker(&d->mutex);
686 const qsizetype suffixLength = d->findByFileName(fileName).m_knownSuffixLength;
687 return fileName.right(suffixLength);
691
692
693
694
695
696
697QMimeType QMimeDatabase::mimeTypeForData(
const QByteArray &data)
const
699 QMutexLocker locker(&d->mutex);
702 return d->findByData(data, &accuracy);
706
707
708
709
710
711
712QMimeType QMimeDatabase::mimeTypeForData(QIODevice *device)
const
714 QMutexLocker locker(&d->mutex);
716 return d->mimeTypeForData(device);
720
721
722
723
724
725
726
727
728
729
730
731
732
733QMimeType QMimeDatabase::mimeTypeForUrl(
const QUrl &url)
const
735 if (url.isLocalFile())
736 return mimeTypeForFile(url.toLocalFile());
738 const QString scheme = url.scheme();
739 if (scheme.startsWith(
"http"_L1) || scheme ==
"mailto"_L1)
740 return mimeTypeForName(d->defaultMimeType());
742 return mimeTypeForFile(url.path(), MatchExtension);
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764QMimeType QMimeDatabase::mimeTypeForFileNameAndData(
const QString &fileName, QIODevice *device)
const
766 QMutexLocker locker(&d->mutex);
768 if (fileName.endsWith(u'/'))
769 return d->mimeTypeForName(directoryMimeType());
771 const QMimeType result = d->mimeTypeForFileNameAndData(fileName, device);
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791QMimeType QMimeDatabase::mimeTypeForFileNameAndData(
const QString &fileName,
const QByteArray &data)
const
793 QMutexLocker locker(&d->mutex);
795 if (fileName.endsWith(u'/'))
796 return d->mimeTypeForName(directoryMimeType());
798 QBuffer buffer(
const_cast<QByteArray *>(&data));
799 buffer.open(QIODevice::ReadOnly);
800 return d->mimeTypeForFileNameAndData(fileName, &buffer);
804
805
806
807
808
809
810QList<QMimeType> QMimeDatabase::allMimeTypes()
const
812 QMutexLocker locker(&d->mutex);
814 return d->allMimeTypes();
818
819
820
821
822
823
824
825
826
827
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()