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