Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qmimedatabase.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2015 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:critical reason:data-parser
5
6#include <qplatformdefs.h> // always first
7
10
12#include "qmimetype_p.h"
13
14#include <private/qduplicatetracker_p.h>
15#include <private/qfilesystementry_p.h>
16
17#include <QtCore/QFile>
18#include <QtCore/QFileInfo>
19#include <QtCore/QStandardPaths>
20#include <QtCore/QBuffer>
21#include <QtCore/QUrl>
22#include <QtCore/QDebug>
23
24#include <algorithm>
25#include <functional>
26#include <stack>
27
28QT_BEGIN_NAMESPACE
29
30using namespace Qt::StringLiterals;
31
33{
34 return QStringLiteral("inode/directory");
35}
37{
38 return QStringLiteral("text/plain");
39}
40
41Q_GLOBAL_STATIC(QMimeDatabasePrivate, staticQMimeDatabase)
42
44{
45 return staticQMimeDatabase();
46}
47
48QMimeDatabasePrivate::QMimeDatabasePrivate()
49 : m_defaultMimeType(QStringLiteral("application/octet-stream"))
50{
51}
52
56
58#ifdef QT_BUILD_INTERNAL
60#else
61static const
62#endif
64
65bool QMimeDatabasePrivate::shouldCheck()
66{
67 if (m_lastCheck.isValid() && m_lastCheck.elapsed() < qmime_secondsBetweenChecks * 1000)
68 return false;
69 m_lastCheck.start();
70 return true;
71}
72
74{
75 QStringList dirs =
76 QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("mime"),
77 QStandardPaths::LocateDirectory);
78 dirs.append(u":/qt-project.org/qmime"_s);
79 return dirs;
80}
81
82#if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY)
83# define QT_USE_MMAP
84#endif
85
86void QMimeDatabasePrivate::loadProviders()
87{
88 // We use QStandardPaths every time to check if new files appeared
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); }
92 );
93 const bool needInternalDB = QMimeXMLProvider::InternalDatabaseAvailable && fdoIterator == mimeDirs.constEnd();
94 //qDebug() << "mime dirs:" << mimeDirs;
95
96 Providers currentProviders;
97 std::swap(m_providers, currentProviders);
98
99 m_providers.reserve(mimeDirs.size() + (needInternalDB ? 1 : 0));
100
101 for (const QString &mimeDir : mimeDirs) {
102 const QString cacheFile = mimeDir + "/mime.cache"_L1;
103 // Check if we already have a provider for this dir
104 const auto predicate = [mimeDir](const std::unique_ptr<QMimeProviderBase> &prov)
105 {
106 return prov && prov->directory() == mimeDir;
107 };
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));
114 //qDebug() << "Created binary provider for" << mimeDir;
115 if (!provider->isValid()) {
116 provider.reset();
117 }
118 }
119#endif
120 if (!provider) {
121 provider.reset(new QMimeXMLProvider(this, mimeDir));
122 //qDebug() << "Created XML provider for" << mimeDir;
123 }
124 m_providers.push_back(std::move(provider));
125 } else {
126 auto provider = std::move(*it); // take provider out of the vector
127 provider->ensureLoaded();
128 if (!provider->isValid()) {
129 provider.reset(new QMimeXMLProvider(this, mimeDir));
130 //qDebug() << "Created XML provider to replace binary provider for" << mimeDir;
131 }
132 m_providers.push_back(std::move(provider));
133 }
134 }
135 // mimeDirs is sorted "most local first, most global last"
136 // so the internal XML DB goes at the end
137 if (needInternalDB) {
138 // Check if we already have a provider for the InternalDatabase
139 const auto isInternal = [](const std::unique_ptr<QMimeProviderBase> &prov)
140 {
141 return prov && prov->isInternalDatabase();
142 };
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)));
146 } else {
147 m_providers.push_back(std::move(*it));
148 }
149 }
150
151 auto it = m_providers.begin();
152 (*it)->setOverrideProvider(nullptr);
153 ++it;
154 const auto end = m_providers.end();
155 for (; it != end; ++it)
156 (*it)->setOverrideProvider((it - 1)->get());
157}
158
159const QMimeDatabasePrivate::Providers &QMimeDatabasePrivate::providers()
160{
161#if QT_CONFIG(thread) // stub implementation always returns true
162 Q_ASSERT(!mutex.tryLock()); // caller should have locked mutex
163#endif
164 if (m_providers.empty()) {
165 loadProviders();
166 m_lastCheck.start();
167 } else {
168 if (shouldCheck())
169 loadProviders();
170 }
171 return m_providers;
172}
173
174QString QMimeDatabasePrivate::resolveAlias(const QString &nameOrAlias)
175{
176 for (const auto &provider : providers()) {
177 const QString ret = provider->resolveAlias(nameOrAlias);
178 if (!ret.isEmpty())
179 return ret;
180 }
181 return nameOrAlias;
182}
183
184/*!
185 \internal
186 Returns a MIME type or an invalid one if none found
187 */
188QMimeType QMimeDatabasePrivate::mimeTypeForName(const QString &nameOrAlias)
189{
190 const QString mimeName = resolveAlias(nameOrAlias);
191 for (const auto &provider : providers()) {
192 if (provider->knowsMimeType(mimeName))
193 return QMimeType(QMimeTypePrivate(mimeName));
194 }
195 return {};
196}
197
199{
200 if (fileName.endsWith(u'/'))
201 return { directoryMimeType() };
202
203 const QMimeGlobMatchResult result = findByFileName(fileName);
204 QStringList matchingMimeTypes = result.m_matchingMimeTypes;
205 matchingMimeTypes.sort(); // make it deterministic
206 return matchingMimeTypes;
207}
208
209QMimeGlobMatchResult QMimeDatabasePrivate::findByFileName(const QString &fileName)
210{
211 QMimeGlobMatchResult result;
212 const QString fileNameExcludingPath = QFileSystemEntry(fileName).fileName();
213 for (const auto &provider : providers())
214 provider->addFileNameMatches(fileNameExcludingPath, result);
215 return result;
216}
217
219{
220 QMutexLocker locker(&mutex);
221 for (const auto &provider : providers()) {
222 auto comments = provider->localeComments(name);
223 if (!comments.isEmpty())
224 return comments; // maybe we want to merge in comments from more global providers, in
225 // case of more translations?
226 }
227 return {};
228}
229
231{
232 QMutexLocker locker(&mutex);
233 QStringList patterns;
234 const auto &providerList = providers();
235 // reverse iteration because we start from most global, add up, clear if delete-all, and add up
236 // again.
237 for (auto rit = providerList.rbegin(); rit != providerList.rend(); ++rit) {
238 auto *provider = rit->get();
239 if (provider->hasGlobDeleteAll(name))
240 patterns.clear();
241 patterns += provider->globPatterns(name);
242 }
243 return patterns;
244}
245
247{
248 QMutexLocker locker(&mutex);
249 for (const auto &provider : providers()) {
250 QString genericIconName = provider->genericIcon(name);
251 if (!genericIconName.isEmpty())
252 return genericIconName;
253 }
254 return {};
255}
256
257QString QMimeDatabasePrivate::icon(const QString &name)
258{
259 QMutexLocker locker(&mutex);
260 for (const auto &provider : providers()) {
261 QString iconName = provider->icon(name);
262 if (!iconName.isEmpty())
263 return iconName;
264 }
265 return {};
266}
267
268QString QMimeDatabasePrivate::fallbackParent(const QString &mimeTypeName) const
269{
270 const QStringView myGroup = QStringView{mimeTypeName}.left(mimeTypeName.indexOf(u'/'));
271 // All real-file mimetypes implicitly derive from application/octet-stream
272 if (myGroup != "inode"_L1 &&
273 // ignore non-file extensions
274 myGroup != "all"_L1 && myGroup != "fonts"_L1 && myGroup != "print"_L1 && myGroup != "uri"_L1
275 && mimeTypeName != defaultMimeType()) {
276 return defaultMimeType();
277 }
278 return QString();
279}
280
282{
283 QMutexLocker locker(&mutex);
284 return parents(mimeName);
285}
286
287QStringList QMimeDatabasePrivate::parents(const QString &mimeName)
288{
289#if QT_CONFIG(thread) // stub implementation always returns true
290 Q_ASSERT(!mutex.tryLock());
291#endif
292 QStringList result;
293 for (const auto &provider : providers())
294 provider->addParents(mimeName, result);
295
296 // Implicit rule from the spec: all text/* types are subclasses of text/plain. It holds even
297 // for types that declare other parents, and shared-mime-info >= 2.5 relies on that rather
298 // than listing text/plain (e.g. text/x-shellscript only declares application/x-executable).
299 if (mimeName.startsWith("text/"_L1) && mimeName != plainTextMimeType()
300 && !result.contains(plainTextMimeType())) {
301 result.append(plainTextMimeType());
302 }
303
304 if (result.isEmpty()) {
305 const QString parent = fallbackParent(mimeName);
306 if (!parent.isEmpty())
307 result.append(parent);
308 }
309 return result;
310}
311
313{
314 QMutexLocker locker(&mutex);
315 QStringList result;
316 for (const auto &provider : providers())
317 provider->addAliases(mimeName, result);
318 return result;
319}
320
321bool QMimeDatabasePrivate::mimeInherits(const QString &mime, const QString &parent)
322{
323 QMutexLocker locker(&mutex);
324 return inherits(mime, parent);
325}
326
327static inline bool isTextFile(const QByteArray &data)
328{
329 // UTF16 byte order marks
330 static const char bigEndianBOM[] = "\xFE\xFF";
331 static const char littleEndianBOM[] = "\xFF\xFE";
332 if (data.startsWith(bigEndianBOM) || data.startsWith(littleEndianBOM))
333 return true;
334
335 // Check the first 128 bytes (see shared-mime spec)
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)
340 return false;
341 }
342
343 return true;
344}
345
346QMimeType QMimeDatabasePrivate::findByData(const QByteArray &data, int *accuracyPtr)
347{
348 if (data.isEmpty()) {
349 *accuracyPtr = 100;
350 return mimeTypeForName(QStringLiteral("application/x-zerosize"));
351 }
352
353 QMimeMagicResult result;
354 for (const auto &provider : providers())
355 provider->findByMagic(data, result);
356
357 if (result.isValid()) {
358 *accuracyPtr = result.accuracy;
359 return QMimeType(QMimeTypePrivate(result.candidate));
360 }
361
362 if (isTextFile(data)) {
363 *accuracyPtr = 5;
364 return mimeTypeForName(plainTextMimeType());
365 }
366
367 return mimeTypeForName(defaultMimeType());
368}
369
370QMimeType QMimeDatabasePrivate::mimeTypeForFileNameAndData(const QString &fileName, QIODevice *device)
371{
372 // First, glob patterns are evaluated. If there is a match with max weight,
373 // this one is selected and we are done. Otherwise, the file contents are
374 // evaluated and the match with the highest value (either a magic priority or
375 // a glob pattern weight) is selected. Matching starts from max level (most
376 // specific) in both cases, even when there is already a suffix matching candidate.
377
378 // Pass 1) Try to match on the file name
379 QMimeGlobMatchResult candidatesByName = findByFileName(fileName);
380 if (candidatesByName.m_allMatchingMimeTypes.size() == 1) {
381 const QMimeType mime = mimeTypeForName(candidatesByName.m_matchingMimeTypes.at(0));
382 if (mime.isValid())
383 return mime;
384 candidatesByName = {};
385 }
386
387 // Extension is unknown, or matches multiple mimetypes.
388 // Pass 2) Match on content, if we can read the data
389 const auto matchOnContent = [this, &candidatesByName](QIODevice *device) {
390 const bool openedByUs = !device->isOpen() && device->open(QIODevice::ReadOnly);
391 if (device->isOpen()) {
392 // Read 16K in one go (QIODEVICE_BUFFERSIZE in qiodevice_p.h).
393 // This is much faster than seeking back and forth into QIODevice.
394 const QByteArray data = device->peek(16384);
395
396 if (openedByUs)
397 device->close();
398
399 int magicAccuracy = 0;
400 QMimeType candidateByData(findByData(data, &magicAccuracy));
401
402 // Disambiguate conflicting extensions (if magic matching found something)
403 if (candidateByData.isValid() && magicAccuracy > 0) {
404 const QString sniffedMime = candidateByData.name();
405 // If the sniffedMime matches a highest-weight glob match, use it
406 if (candidatesByName.m_matchingMimeTypes.contains(sniffedMime))
407 return candidateByData;
408
409 for (const QString &m : std::as_const(candidatesByName.m_allMatchingMimeTypes)) {
410 if (inherits(m, sniffedMime)) {
411 // We have magic + pattern pointing to this, so it's a pretty good match
412 return mimeTypeForName(m);
413 }
414 }
415 if (candidatesByName.m_allMatchingMimeTypes.isEmpty()) {
416 // No glob, use magic
417 return candidateByData;
418 }
419 }
420 }
421
422 if (candidatesByName.m_allMatchingMimeTypes.size() > 1) {
423 candidatesByName.m_matchingMimeTypes.sort(); // make it deterministic
424 const QMimeType mime = mimeTypeForName(candidatesByName.m_matchingMimeTypes.at(0));
425 if (mime.isValid())
426 return mime;
427 }
428
429 return mimeTypeForName(defaultMimeType());
430 };
431
432 if (device)
433 return matchOnContent(device);
434
435 QFile fallbackFile(fileName);
436 return matchOnContent(&fallbackFile);
437}
438
439QMimeType QMimeDatabasePrivate::mimeTypeForFileExtension(const QString &fileName)
440{
441 const QStringList matches = mimeTypeForFileName(fileName);
442 if (matches.isEmpty()) {
443 return mimeTypeForName(defaultMimeType());
444 } else {
445 // We have to pick one in case of multiple matches.
446 return mimeTypeForName(matches.first());
447 }
448}
449
450QMimeType QMimeDatabasePrivate::mimeTypeForData(QIODevice *device)
451{
452 int accuracy = 0;
453 const bool openedByUs = !device->isOpen() && device->open(QIODevice::ReadOnly);
454 if (device->isOpen()) {
455 // Read 16K in one go (QIODEVICE_BUFFERSIZE in qiodevice_p.h).
456 // This is much faster than seeking back and forth into QIODevice.
457 const QByteArray data = device->peek(16384);
458 QMimeType result = findByData(data, &accuracy);
459 if (openedByUs)
460 device->close();
461 return result;
462 }
463 return mimeTypeForName(defaultMimeType());
464}
465
466QMimeType QMimeDatabasePrivate::mimeTypeForFile(const QString &fileName,
467 const QFileInfo &fileInfo,
468 QMimeDatabase::MatchMode mode)
469{
470 if (false) {
471#ifdef Q_OS_UNIX
472 } else if (fileInfo.isNativePath()) {
473 // If this is a local file, we'll want to do a stat() ourselves so we can
474 // detect additional inode types. In addition we want to follow symlinks.
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"));
488 }
489#endif
490 } else if (fileInfo.isDir()) {
491 return mimeTypeForName(directoryMimeType());
492 }
493
494 switch (mode) {
495 case QMimeDatabase::MatchDefault:
496 break;
497 case QMimeDatabase::MatchExtension:
498 return mimeTypeForFileExtension(fileName);
499 case QMimeDatabase::MatchContent: {
500 QFile file(fileName);
501 return mimeTypeForData(&file);
502 }
503 }
504 // MatchDefault:
505 return mimeTypeForFileNameAndData(fileName, nullptr);
506}
507
509{
510 QList<QMimeType> result;
511 for (const auto &provider : providers())
512 provider->addAllMimeTypes(result);
513 return result;
514}
515
516bool QMimeDatabasePrivate::inherits(const QString &mime, const QString &parent)
517{
518 const QString resolvedParent = resolveAlias(parent);
519 QDuplicateTracker<QString> seen;
520 std::stack<QString, QStringList> toCheck;
521 toCheck.push(mime);
522 while (!toCheck.empty()) {
523 if (toCheck.top() == resolvedParent)
524 return true;
525 const QString mimeName = toCheck.top();
526 toCheck.pop();
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);
532 }
533 }
534 return false;
535}
536
537/*!
538 \class QMimeDatabase
539 \inmodule QtCore
540 \brief The QMimeDatabase class maintains a database of MIME types.
541
542 \since 5.0
543
544 The MIME type database is provided by the freedesktop.org shared-mime-info
545 project. If the MIME type database cannot be found on the system, as is the case
546 on most Windows, \macos, and iOS systems, Qt will use its own copy of it.
547
548 Applications which want to define custom MIME types need to install an
549 XML file into the locations searched for MIME definitions.
550 These locations can be queried with
551 \snippet code/src_corelib_mimetype_qmimedatabase.cpp 1
552 On a typical Unix system, this will be /usr/share/mime/packages/, but it is also
553 possible to extend the list of directories by setting the environment variable
554 \c XDG_DATA_DIRS. For instance adding /opt/myapp/share to \c XDG_DATA_DIRS will result
555 in /opt/myapp/share/mime/packages/ being searched for MIME definitions.
556
557 Here is an example of MIME XML:
558 \snippet code/src_corelib_mimetype_qmimedatabase.cpp 2
559
560 For more details about the syntax of XML MIME definitions, including defining
561 "magic" in order to detect MIME types based on data as well, read the
562 Shared Mime Info specification at
563 http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html
564
565 On Unix systems, a binary cache is used for more performance. This cache is generated
566 by the command "update-mime-database path", where path would be /opt/myapp/share/mime
567 in the above example. Make sure to run this command when installing the MIME type
568 definition file.
569
570 \threadsafe
571
572 \snippet code/src_corelib_mimetype_qmimedatabase.cpp 0
573
574 \sa QMimeType, {MIME Type Browser}
575 */
576
577/*!
578 \fn QMimeDatabase::QMimeDatabase();
579 Constructs a QMimeDatabase object.
580
581 It is perfectly OK to create an instance of QMimeDatabase every time you need to
582 perform a lookup.
583 The parsing of mimetypes is done on demand (when shared-mime-info is installed)
584 or when the very first instance is constructed (when parsing XML files directly).
585 */
586QMimeDatabase::QMimeDatabase() :
587 d(staticQMimeDatabase())
588{
589}
590
591/*!
592 \fn QMimeDatabase::~QMimeDatabase();
593 Destroys the QMimeDatabase object.
594 */
595QMimeDatabase::~QMimeDatabase()
596{
597 d = nullptr;
598}
599
600/*!
601 \fn QMimeType QMimeDatabase::mimeTypeForName(const QString &nameOrAlias) const;
602 Returns a MIME type for \a nameOrAlias or an invalid one if none found.
603 */
604QMimeType QMimeDatabase::mimeTypeForName(const QString &nameOrAlias) const
605{
606 QMutexLocker locker(&d->mutex);
607
608 return d->mimeTypeForName(nameOrAlias);
609}
610
611/*!
612 Returns a MIME type for \a fileInfo.
613
614 A valid MIME type is always returned.
615
616 The default matching algorithm looks at both the file name and the file
617 contents, if necessary. The file extension has priority over the contents,
618 but the contents will be used if the file extension is unknown, or
619 matches multiple MIME types.
620 If \a fileInfo is a Unix symbolic link, the file that it refers to
621 will be used instead.
622 If the file doesn't match any known pattern or data, the default MIME type
623 (application/octet-stream) is returned.
624
625 When \a mode is set to MatchExtension, only the file name is used, not
626 the file contents. The file doesn't even have to exist. If the file name
627 doesn't match any known pattern, the default MIME type (application/octet-stream)
628 is returned.
629 If multiple MIME types match this file, the first one (alphabetically) is returned.
630
631 When \a mode is set to MatchContent, and the file is readable, only the
632 file contents are used to determine the MIME type. This is equivalent to
633 calling mimeTypeForData with a QFile as input device.
634
635 \a fileInfo may refer to an absolute or relative path.
636
637 \sa QMimeType::isDefault(), mimeTypeForData()
638*/
639QMimeType QMimeDatabase::mimeTypeForFile(const QFileInfo &fileInfo, MatchMode mode) const
640{
641 QMutexLocker locker(&d->mutex);
642
643 return d->mimeTypeForFile(fileInfo.filePath(), fileInfo, mode);
644}
645
646/*!
647 Returns a MIME type for the file named \a fileName using \a mode.
648
649 \overload
650*/
651QMimeType QMimeDatabase::mimeTypeForFile(const QString &fileName, MatchMode mode) const
652{
653 QMutexLocker locker(&d->mutex);
654
655 if (mode == MatchExtension) {
656 return d->mimeTypeForFileExtension(fileName);
657 } else {
658 QFileInfo fileInfo(fileName);
659 return d->mimeTypeForFile(fileName, fileInfo, mode);
660 }
661}
662
663/*!
664 Returns the MIME types for the file name \a fileName.
665
666 If the file name doesn't match any known pattern, an empty list is returned.
667 If multiple MIME types match this file, they are all returned.
668
669 This function does not try to open the file. To also use the content
670 when determining the MIME type, use mimeTypeForFile() or
671 mimeTypeForFileNameAndData() instead.
672
673 \sa mimeTypeForFile()
674*/
675QList<QMimeType> QMimeDatabase::mimeTypesForFileName(const QString &fileName) const
676{
677 QMutexLocker locker(&d->mutex);
678
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));
684 return mimes;
685}
686/*!
687 Returns the suffix for the file \a fileName, as known by the MIME database.
688
689 This allows to pre-select "tar.bz2" for foo.tar.bz2, but still only
690 "txt" for my.file.with.dots.txt.
691*/
692QString QMimeDatabase::suffixForFileName(const QString &fileName) const
693{
694 QMutexLocker locker(&d->mutex);
695 const qsizetype suffixLength = d->findByFileName(fileName).m_knownSuffixLength;
696 return fileName.right(suffixLength);
697}
698
699/*!
700 Returns a MIME type for \a data.
701
702 A valid MIME type is always returned. If \a data doesn't match any
703 known MIME type data, the default MIME type (application/octet-stream)
704 is returned.
705*/
706QMimeType QMimeDatabase::mimeTypeForData(const QByteArray &data) const
707{
708 QMutexLocker locker(&d->mutex);
709
710 int accuracy = 0;
711 return d->findByData(data, &accuracy);
712}
713
714/*!
715 Returns a MIME type for the data in \a device.
716
717 A valid MIME type is always returned. If the data in \a device doesn't match any
718 known MIME type data, the default MIME type (application/octet-stream)
719 is returned.
720*/
721QMimeType QMimeDatabase::mimeTypeForData(QIODevice *device) const
722{
723 QMutexLocker locker(&d->mutex);
724
725 return d->mimeTypeForData(device);
726}
727
728/*!
729 Returns a MIME type for \a url.
730
731 If the URL is a local file, this calls mimeTypeForFile.
732
733 Otherwise the matching is done based on the file name only,
734 except for schemes where file names don't mean much, like HTTP.
735 This method always returns the default mimetype for HTTP URLs,
736 use QNetworkAccessManager to handle HTTP URLs properly.
737
738 A valid MIME type is always returned. If \a url doesn't match any
739 known MIME type data, the default MIME type (application/octet-stream)
740 is returned.
741*/
742QMimeType QMimeDatabase::mimeTypeForUrl(const QUrl &url) const
743{
744 if (url.isLocalFile())
745 return mimeTypeForFile(url.toLocalFile());
746
747 const QString scheme = url.scheme();
748 if (scheme.startsWith("http"_L1) || scheme == "mailto"_L1)
749 return mimeTypeForName(d->defaultMimeType());
750
751 return mimeTypeForFile(url.path(), MatchExtension);
752}
753
754/*!
755 Returns a MIME type for the given \a fileName and \a device data.
756
757 This overload can be useful when the file is remote, and we started to
758 download some of its data in a device. This allows to do full MIME type
759 matching for remote files as well.
760
761 If the device is not open, it will be opened by this function, and closed
762 after the MIME type detection is completed.
763
764 A valid MIME type is always returned. If \a device data doesn't match any
765 known MIME type data, the default MIME type (application/octet-stream)
766 is returned.
767
768 This method looks at both the file name and the file contents,
769 if necessary. The file extension has priority over the contents,
770 but the contents will be used if the file extension is unknown, or
771 matches multiple MIME types.
772*/
773QMimeType QMimeDatabase::mimeTypeForFileNameAndData(const QString &fileName, QIODevice *device) const
774{
775 QMutexLocker locker(&d->mutex);
776
777 if (fileName.endsWith(u'/'))
778 return d->mimeTypeForName(directoryMimeType());
779
780 const QMimeType result = d->mimeTypeForFileNameAndData(fileName, device);
781 return result;
782}
783
784/*!
785 Returns a MIME type for the given \a fileName and device \a data.
786
787 This overload can be useful when the file is remote, and we started to
788 download some of its data. This allows to do full MIME type matching for
789 remote files as well.
790
791 A valid MIME type is always returned. If \a data doesn't match any
792 known MIME type data, the default MIME type (application/octet-stream)
793 is returned.
794
795 This method looks at both the file name and the file contents,
796 if necessary. The file extension has priority over the contents,
797 but the contents will be used if the file extension is unknown, or
798 matches multiple MIME types.
799*/
800QMimeType QMimeDatabase::mimeTypeForFileNameAndData(const QString &fileName, const QByteArray &data) const
801{
802 QMutexLocker locker(&d->mutex);
803
804 if (fileName.endsWith(u'/'))
805 return d->mimeTypeForName(directoryMimeType());
806
807 QBuffer buffer(const_cast<QByteArray *>(&data));
808 buffer.open(QIODevice::ReadOnly);
809 return d->mimeTypeForFileNameAndData(fileName, &buffer);
810}
811
812/*!
813 Returns the list of all available MIME types.
814
815 This can be useful for showing all MIME types to the user, for instance
816 in a MIME type editor. Do not use unless really necessary in other cases
817 though, prefer using the \l {mimeTypeForData()}{mimeTypeForXxx()} methods for performance reasons.
818*/
819QList<QMimeType> QMimeDatabase::allMimeTypes() const
820{
821 QMutexLocker locker(&d->mutex);
822
823 return d->allMimeTypes();
824}
825
826/*!
827 \enum QMimeDatabase::MatchMode
828
829 This enum specifies how matching a file to a MIME type is performed.
830
831 \value MatchDefault Both the file name and content are used to look for a match
832
833 \value MatchExtension Only the file name is used to look for a match
834
835 \value MatchContent The file content is used to look for a match
836*/
837
838QT_END_NAMESPACE
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)
static bool isTextFile(const QByteArray &data)
static Q_CONSTINIT const int qmime_secondsBetweenChecks
static QStringList locateMimeDirectories()
static QString directoryMimeType()
static QString plainTextMimeType()
bool isValid() const