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);
293 Q_ASSERT(!mutex.tryLock());
296 for (
const auto &provider : providers())
297 provider->addParents(mimeName, result);
298 if (result.isEmpty()) {
299 const QString parent = fallbackParent(mimeName);
300 if (!parent.isEmpty())
301 result.append(parent);
308 QMutexLocker locker(&mutex);
310 for (
const auto &provider : providers())
311 provider->addAliases(mimeName, result);
317 QMutexLocker locker(&mutex);
318 return inherits(mime, parent);
324 static const char bigEndianBOM[] =
"\xFE\xFF";
325 static const char littleEndianBOM[] =
"\xFF\xFE";
326 if (data.startsWith(bigEndianBOM) || data.startsWith(littleEndianBOM))
330 const char *p = data.constData();
331 const char *e = p + qMin(128, data.size());
332 for ( ; p < e; ++p) {
333 if (
static_cast<
unsigned char>(*p) < 32 && *p != 9 && *p !=10 && *p != 13)
342 if (data.isEmpty()) {
344 return mimeTypeForName(QStringLiteral(
"application/x-zerosize"));
348 for (
const auto &provider : providers())
349 provider->findByMagic(data, result);
353 return QMimeType(QMimeTypePrivate(result.candidate));
358 return mimeTypeForName(plainTextMimeType());
361 return mimeTypeForName(defaultMimeType());
373 QMimeGlobMatchResult candidatesByName = findByFileName(fileName);
374 if (candidatesByName.m_allMatchingMimeTypes.size() == 1) {
375 const QMimeType mime = mimeTypeForName(candidatesByName.m_matchingMimeTypes.at(0));
378 candidatesByName = {};
383 const auto matchOnContent = [
this, &candidatesByName](QIODevice *device) {
384 const bool openedByUs = !device->isOpen() && device->open(QIODevice::ReadOnly);
385 if (device->isOpen()) {
393 int magicAccuracy = 0;
394 QMimeType candidateByData(findByData(data, &magicAccuracy));
397 if (candidateByData.isValid() && magicAccuracy > 0) {
398 const QString sniffedMime = candidateByData.name();
400 if (candidatesByName.m_matchingMimeTypes.contains(sniffedMime))
401 return candidateByData;
403 for (
const QString &m : std::as_const(candidatesByName.m_allMatchingMimeTypes)) {
404 if (inherits(m, sniffedMime)) {
406 return mimeTypeForName(m);
409 if (candidatesByName.m_allMatchingMimeTypes.isEmpty()) {
411 return candidateByData;
416 if (candidatesByName.m_allMatchingMimeTypes.size() > 1) {
417 candidatesByName.m_matchingMimeTypes.sort();
418 const QMimeType mime = mimeTypeForName(candidatesByName.m_matchingMimeTypes.at(0));
423 return mimeTypeForName(defaultMimeType());
427 return matchOnContent(device);
429 QFile fallbackFile(fileName);
430 return matchOnContent(&fallbackFile);
435 const QStringList matches = mimeTypeForFileName(fileName);
436 if (matches.isEmpty()) {
437 return mimeTypeForName(defaultMimeType());
440 return mimeTypeForName(matches.first());
447 const bool openedByUs = !device->isOpen() && device->open(QIODevice::ReadOnly);
448 if (device->isOpen()) {
452 QMimeType result = findByData(data, &accuracy);
457 return mimeTypeForName(defaultMimeType());
461 const QFileInfo &fileInfo,
462 QMimeDatabase::MatchMode mode)
466 }
else if (fileInfo.isNativePath()) {
469 const QByteArray nativeFilePath = QFile::encodeName(fileName);
470 QT_STATBUF statBuffer;
471 if (QT_STAT(nativeFilePath.constData(), &statBuffer) == 0) {
472 if (S_ISDIR(statBuffer.st_mode))
473 return mimeTypeForName(directoryMimeType());
474 if (S_ISCHR(statBuffer.st_mode))
475 return mimeTypeForName(QStringLiteral(
"inode/chardevice"));
476 if (S_ISBLK(statBuffer.st_mode))
477 return mimeTypeForName(QStringLiteral(
"inode/blockdevice"));
478 if (S_ISFIFO(statBuffer.st_mode))
479 return mimeTypeForName(QStringLiteral(
"inode/fifo"));
480 if (S_ISSOCK(statBuffer.st_mode))
481 return mimeTypeForName(QStringLiteral(
"inode/socket"));
484 }
else if (fileInfo.isDir()) {
485 return mimeTypeForName(directoryMimeType());
489 case QMimeDatabase::MatchDefault:
491 case QMimeDatabase::MatchExtension:
492 return mimeTypeForFileExtension(fileName);
493 case QMimeDatabase::MatchContent: {
494 QFile file(fileName);
495 return mimeTypeForData(&file);
499 return mimeTypeForFileNameAndData(fileName,
nullptr);
504 QList<QMimeType> result;
505 for (
const auto &provider : providers())
506 provider->addAllMimeTypes(result);
512 const QString resolvedParent = resolveAlias(parent);
513 QDuplicateTracker<QString> seen;
514 std::stack<QString, QStringList> toCheck;
516 while (!toCheck.empty()) {
517 if (toCheck.top() == resolvedParent)
519 const QString mimeName = toCheck.top();
521 const auto parentList = parents(mimeName);
522 for (
const QString &par : parentList) {
523 const QString resolvedPar = resolveAlias(par);
524 if (!seen.hasSeen(resolvedPar))
525 toCheck.push(resolvedPar);
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
568
569
572
573
574
575
576
577
578
579
580QMimeDatabase::QMimeDatabase() :
581 d(staticQMimeDatabase())
586
587
588
589QMimeDatabase::~QMimeDatabase()
595
596
597
598QMimeType QMimeDatabase::mimeTypeForName(
const QString &nameOrAlias)
const
600 QMutexLocker locker(&d->mutex);
602 return d->mimeTypeForName(nameOrAlias);
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
631
632
633QMimeType QMimeDatabase::mimeTypeForFile(
const QFileInfo &fileInfo, MatchMode mode)
const
635 QMutexLocker locker(&d->mutex);
637 return d->mimeTypeForFile(fileInfo.filePath(), fileInfo, mode);
641
642
643
644
645QMimeType QMimeDatabase::mimeTypeForFile(
const QString &fileName, MatchMode mode)
const
647 QMutexLocker locker(&d->mutex);
649 if (mode == MatchExtension) {
650 return d->mimeTypeForFileExtension(fileName);
652 QFileInfo fileInfo(fileName);
653 return d->mimeTypeForFile(fileName, fileInfo, mode);
658
659
660
661
662
663
664
665
666
667
668
669QList<QMimeType> QMimeDatabase::mimeTypesForFileName(
const QString &fileName)
const
671 QMutexLocker locker(&d->mutex);
673 const QStringList matches = d->mimeTypeForFileName(fileName);
674 QList<QMimeType> mimes;
675 mimes.reserve(matches.size());
676 for (
const QString &mime : matches)
677 mimes.append(d->mimeTypeForName(mime));
681
682
683
684
685
686QString QMimeDatabase::suffixForFileName(
const QString &fileName)
const
688 QMutexLocker locker(&d->mutex);
689 const qsizetype suffixLength = d->findByFileName(fileName).m_knownSuffixLength;
690 return fileName.right(suffixLength);
694
695
696
697
698
699
700QMimeType QMimeDatabase::mimeTypeForData(
const QByteArray &data)
const
702 QMutexLocker locker(&d->mutex);
705 return d->findByData(data, &accuracy);
709
710
711
712
713
714
715QMimeType QMimeDatabase::mimeTypeForData(QIODevice *device)
const
717 QMutexLocker locker(&d->mutex);
719 return d->mimeTypeForData(device);
723
724
725
726
727
728
729
730
731
732
733
734
735
736QMimeType QMimeDatabase::mimeTypeForUrl(
const QUrl &url)
const
738 if (url.isLocalFile())
739 return mimeTypeForFile(url.toLocalFile());
741 const QString scheme = url.scheme();
742 if (scheme.startsWith(
"http"_L1) || scheme ==
"mailto"_L1)
743 return mimeTypeForName(d->defaultMimeType());
745 return mimeTypeForFile(url.path(), MatchExtension);
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767QMimeType QMimeDatabase::mimeTypeForFileNameAndData(
const QString &fileName, QIODevice *device)
const
769 QMutexLocker locker(&d->mutex);
771 if (fileName.endsWith(u'/'))
772 return d->mimeTypeForName(directoryMimeType());
774 const QMimeType result = d->mimeTypeForFileNameAndData(fileName, device);
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794QMimeType QMimeDatabase::mimeTypeForFileNameAndData(
const QString &fileName,
const QByteArray &data)
const
796 QMutexLocker locker(&d->mutex);
798 if (fileName.endsWith(u'/'))
799 return d->mimeTypeForName(directoryMimeType());
801 QBuffer buffer(
const_cast<QByteArray *>(&data));
802 buffer.open(QIODevice::ReadOnly);
803 return d->mimeTypeForFileNameAndData(fileName, &buffer);
807
808
809
810
811
812
813QList<QMimeType> QMimeDatabase::allMimeTypes()
const
815 QMutexLocker locker(&d->mutex);
817 return d->allMimeTypes();
821
822
823
824
825
826
827
828
829
830
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()