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#ifndef Q_OS_WASM // 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 text/* types are subclasses of text/plain.
272 if (myGroup == "text"_L1 && mimeTypeName != plainTextMimeType())
273 return plainTextMimeType();
274 // All real-file mimetypes implicitly derive from application/octet-stream
275 if (myGroup != "inode"_L1 &&
276 // ignore non-file extensions
277 myGroup != "all"_L1 && myGroup != "fonts"_L1 && myGroup != "print"_L1 && myGroup != "uri"_L1
278 && mimeTypeName != defaultMimeType()) {
279 return defaultMimeType();
280 }
281 return QString();
282}
283
285{
286 QMutexLocker locker(&mutex);
287 return parents(mimeName);
288}
289
290QStringList QMimeDatabasePrivate::parents(const QString &mimeName)
291{
292 Q_ASSERT(!mutex.tryLock());
293 QStringList result;
294 for (const auto &provider : providers())
295 provider->addParents(mimeName, result);
296 if (result.isEmpty()) {
297 const QString parent = fallbackParent(mimeName);
298 if (!parent.isEmpty())
299 result.append(parent);
300 }
301 return result;
302}
303
305{
306 QMutexLocker locker(&mutex);
307 QStringList result;
308 for (const auto &provider : providers())
309 provider->addAliases(mimeName, result);
310 return result;
311}
312
313bool QMimeDatabasePrivate::mimeInherits(const QString &mime, const QString &parent)
314{
315 QMutexLocker locker(&mutex);
316 return inherits(mime, parent);
317}
318
319static inline bool isTextFile(const QByteArray &data)
320{
321 // UTF16 byte order marks
322 static const char bigEndianBOM[] = "\xFE\xFF";
323 static const char littleEndianBOM[] = "\xFF\xFE";
324 if (data.startsWith(bigEndianBOM) || data.startsWith(littleEndianBOM))
325 return true;
326
327 // Check the first 128 bytes (see shared-mime spec)
328 const char *p = data.constData();
329 const char *e = p + qMin(128, data.size());
330 for ( ; p < e; ++p) {
331 if (static_cast<unsigned char>(*p) < 32 && *p != 9 && *p !=10 && *p != 13)
332 return false;
333 }
334
335 return true;
336}
337
338QMimeType QMimeDatabasePrivate::findByData(const QByteArray &data, int *accuracyPtr)
339{
340 if (data.isEmpty()) {
341 *accuracyPtr = 100;
342 return mimeTypeForName(QStringLiteral("application/x-zerosize"));
343 }
344
345 QMimeMagicResult result;
346 for (const auto &provider : providers())
347 provider->findByMagic(data, result);
348
349 if (result.isValid()) {
350 *accuracyPtr = result.accuracy;
351 return QMimeType(QMimeTypePrivate(result.candidate));
352 }
353
354 if (isTextFile(data)) {
355 *accuracyPtr = 5;
356 return mimeTypeForName(plainTextMimeType());
357 }
358
359 return mimeTypeForName(defaultMimeType());
360}
361
362QMimeType QMimeDatabasePrivate::mimeTypeForFileNameAndData(const QString &fileName, QIODevice *device)
363{
364 // First, glob patterns are evaluated. If there is a match with max weight,
365 // this one is selected and we are done. Otherwise, the file contents are
366 // evaluated and the match with the highest value (either a magic priority or
367 // a glob pattern weight) is selected. Matching starts from max level (most
368 // specific) in both cases, even when there is already a suffix matching candidate.
369
370 // Pass 1) Try to match on the file name
371 QMimeGlobMatchResult candidatesByName = findByFileName(fileName);
372 if (candidatesByName.m_allMatchingMimeTypes.size() == 1) {
373 const QMimeType mime = mimeTypeForName(candidatesByName.m_matchingMimeTypes.at(0));
374 if (mime.isValid())
375 return mime;
376 candidatesByName = {};
377 }
378
379 // Extension is unknown, or matches multiple mimetypes.
380 // Pass 2) Match on content, if we can read the data
381 const auto matchOnContent = [this, &candidatesByName](QIODevice *device) {
382 const bool openedByUs = !device->isOpen() && device->open(QIODevice::ReadOnly);
383 if (device->isOpen()) {
384 // Read 16K in one go (QIODEVICE_BUFFERSIZE in qiodevice_p.h).
385 // This is much faster than seeking back and forth into QIODevice.
386 const QByteArray data = device->peek(16384);
387
388 if (openedByUs)
389 device->close();
390
391 int magicAccuracy = 0;
392 QMimeType candidateByData(findByData(data, &magicAccuracy));
393
394 // Disambiguate conflicting extensions (if magic matching found something)
395 if (candidateByData.isValid() && magicAccuracy > 0) {
396 const QString sniffedMime = candidateByData.name();
397 // If the sniffedMime matches a highest-weight glob match, use it
398 if (candidatesByName.m_matchingMimeTypes.contains(sniffedMime))
399 return candidateByData;
400
401 for (const QString &m : std::as_const(candidatesByName.m_allMatchingMimeTypes)) {
402 if (inherits(m, sniffedMime)) {
403 // We have magic + pattern pointing to this, so it's a pretty good match
404 return mimeTypeForName(m);
405 }
406 }
407 if (candidatesByName.m_allMatchingMimeTypes.isEmpty()) {
408 // No glob, use magic
409 return candidateByData;
410 }
411 }
412 }
413
414 if (candidatesByName.m_allMatchingMimeTypes.size() > 1) {
415 candidatesByName.m_matchingMimeTypes.sort(); // make it deterministic
416 const QMimeType mime = mimeTypeForName(candidatesByName.m_matchingMimeTypes.at(0));
417 if (mime.isValid())
418 return mime;
419 }
420
421 return mimeTypeForName(defaultMimeType());
422 };
423
424 if (device)
425 return matchOnContent(device);
426
427 QFile fallbackFile(fileName);
428 return matchOnContent(&fallbackFile);
429}
430
431QMimeType QMimeDatabasePrivate::mimeTypeForFileExtension(const QString &fileName)
432{
433 const QStringList matches = mimeTypeForFileName(fileName);
434 if (matches.isEmpty()) {
435 return mimeTypeForName(defaultMimeType());
436 } else {
437 // We have to pick one in case of multiple matches.
438 return mimeTypeForName(matches.first());
439 }
440}
441
442QMimeType QMimeDatabasePrivate::mimeTypeForData(QIODevice *device)
443{
444 int accuracy = 0;
445 const bool openedByUs = !device->isOpen() && device->open(QIODevice::ReadOnly);
446 if (device->isOpen()) {
447 // Read 16K in one go (QIODEVICE_BUFFERSIZE in qiodevice_p.h).
448 // This is much faster than seeking back and forth into QIODevice.
449 const QByteArray data = device->peek(16384);
450 QMimeType result = findByData(data, &accuracy);
451 if (openedByUs)
452 device->close();
453 return result;
454 }
455 return mimeTypeForName(defaultMimeType());
456}
457
458QMimeType QMimeDatabasePrivate::mimeTypeForFile(const QString &fileName,
459 const QFileInfo &fileInfo,
460 QMimeDatabase::MatchMode mode)
461{
462 if (false) {
463#ifdef Q_OS_UNIX
464 } else if (fileInfo.isNativePath()) {
465 // If this is a local file, we'll want to do a stat() ourselves so we can
466 // detect additional inode types. In addition we want to follow symlinks.
467 const QByteArray nativeFilePath = QFile::encodeName(fileName);
468 QT_STATBUF statBuffer;
469 if (QT_STAT(nativeFilePath.constData(), &statBuffer) == 0) {
470 if (S_ISDIR(statBuffer.st_mode))
471 return mimeTypeForName(directoryMimeType());
472 if (S_ISCHR(statBuffer.st_mode))
473 return mimeTypeForName(QStringLiteral("inode/chardevice"));
474 if (S_ISBLK(statBuffer.st_mode))
475 return mimeTypeForName(QStringLiteral("inode/blockdevice"));
476 if (S_ISFIFO(statBuffer.st_mode))
477 return mimeTypeForName(QStringLiteral("inode/fifo"));
478 if (S_ISSOCK(statBuffer.st_mode))
479 return mimeTypeForName(QStringLiteral("inode/socket"));
480 }
481#endif
482 } else if (fileInfo.isDir()) {
483 return mimeTypeForName(directoryMimeType());
484 }
485
486 switch (mode) {
487 case QMimeDatabase::MatchDefault:
488 break;
489 case QMimeDatabase::MatchExtension:
490 return mimeTypeForFileExtension(fileName);
491 case QMimeDatabase::MatchContent: {
492 QFile file(fileName);
493 return mimeTypeForData(&file);
494 }
495 }
496 // MatchDefault:
497 return mimeTypeForFileNameAndData(fileName, nullptr);
498}
499
501{
502 QList<QMimeType> result;
503 for (const auto &provider : providers())
504 provider->addAllMimeTypes(result);
505 return result;
506}
507
508bool QMimeDatabasePrivate::inherits(const QString &mime, const QString &parent)
509{
510 const QString resolvedParent = resolveAlias(parent);
511 QDuplicateTracker<QString> seen;
512 std::stack<QString, QStringList> toCheck;
513 toCheck.push(mime);
514 while (!toCheck.empty()) {
515 if (toCheck.top() == resolvedParent)
516 return true;
517 const QString mimeName = toCheck.top();
518 toCheck.pop();
519 const auto parentList = parents(mimeName);
520 for (const QString &par : parentList) {
521 const QString resolvedPar = resolveAlias(par);
522 if (!seen.hasSeen(resolvedPar))
523 toCheck.push(resolvedPar);
524 }
525 }
526 return false;
527}
528
529/*!
530 \class QMimeDatabase
531 \inmodule QtCore
532 \brief The QMimeDatabase class maintains a database of MIME types.
533
534 \since 5.0
535
536 The MIME type database is provided by the freedesktop.org shared-mime-info
537 project. If the MIME type database cannot be found on the system, as is the case
538 on most Windows, \macos, and iOS systems, Qt will use its own copy of it.
539
540 Applications which want to define custom MIME types need to install an
541 XML file into the locations searched for MIME definitions.
542 These locations can be queried with
543 \snippet code/src_corelib_mimetype_qmimedatabase.cpp 1
544 On a typical Unix system, this will be /usr/share/mime/packages/, but it is also
545 possible to extend the list of directories by setting the environment variable
546 \c XDG_DATA_DIRS. For instance adding /opt/myapp/share to \c XDG_DATA_DIRS will result
547 in /opt/myapp/share/mime/packages/ being searched for MIME definitions.
548
549 Here is an example of MIME XML:
550 \snippet code/src_corelib_mimetype_qmimedatabase.cpp 2
551
552 For more details about the syntax of XML MIME definitions, including defining
553 "magic" in order to detect MIME types based on data as well, read the
554 Shared Mime Info specification at
555 http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html
556
557 On Unix systems, a binary cache is used for more performance. This cache is generated
558 by the command "update-mime-database path", where path would be /opt/myapp/share/mime
559 in the above example. Make sure to run this command when installing the MIME type
560 definition file.
561
562 \threadsafe
563
564 \snippet code/src_corelib_mimetype_qmimedatabase.cpp 0
565
566 \sa QMimeType, {MIME Type Browser}
567 */
568
569/*!
570 \fn QMimeDatabase::QMimeDatabase();
571 Constructs a QMimeDatabase object.
572
573 It is perfectly OK to create an instance of QMimeDatabase every time you need to
574 perform a lookup.
575 The parsing of mimetypes is done on demand (when shared-mime-info is installed)
576 or when the very first instance is constructed (when parsing XML files directly).
577 */
578QMimeDatabase::QMimeDatabase() :
579 d(staticQMimeDatabase())
580{
581}
582
583/*!
584 \fn QMimeDatabase::~QMimeDatabase();
585 Destroys the QMimeDatabase object.
586 */
587QMimeDatabase::~QMimeDatabase()
588{
589 d = nullptr;
590}
591
592/*!
593 \fn QMimeType QMimeDatabase::mimeTypeForName(const QString &nameOrAlias) const;
594 Returns a MIME type for \a nameOrAlias or an invalid one if none found.
595 */
596QMimeType QMimeDatabase::mimeTypeForName(const QString &nameOrAlias) const
597{
598 QMutexLocker locker(&d->mutex);
599
600 return d->mimeTypeForName(nameOrAlias);
601}
602
603/*!
604 Returns a MIME type for \a fileInfo.
605
606 A valid MIME type is always returned.
607
608 The default matching algorithm looks at both the file name and the file
609 contents, if necessary. The file extension has priority over the contents,
610 but the contents will be used if the file extension is unknown, or
611 matches multiple MIME types.
612 If \a fileInfo is a Unix symbolic link, the file that it refers to
613 will be used instead.
614 If the file doesn't match any known pattern or data, the default MIME type
615 (application/octet-stream) is returned.
616
617 When \a mode is set to MatchExtension, only the file name is used, not
618 the file contents. The file doesn't even have to exist. If the file name
619 doesn't match any known pattern, the default MIME type (application/octet-stream)
620 is returned.
621 If multiple MIME types match this file, the first one (alphabetically) is returned.
622
623 When \a mode is set to MatchContent, and the file is readable, only the
624 file contents are used to determine the MIME type. This is equivalent to
625 calling mimeTypeForData with a QFile as input device.
626
627 \a fileInfo may refer to an absolute or relative path.
628
629 \sa QMimeType::isDefault(), mimeTypeForData()
630*/
631QMimeType QMimeDatabase::mimeTypeForFile(const QFileInfo &fileInfo, MatchMode mode) const
632{
633 QMutexLocker locker(&d->mutex);
634
635 return d->mimeTypeForFile(fileInfo.filePath(), fileInfo, mode);
636}
637
638/*!
639 Returns a MIME type for the file named \a fileName using \a mode.
640
641 \overload
642*/
643QMimeType QMimeDatabase::mimeTypeForFile(const QString &fileName, MatchMode mode) const
644{
645 QMutexLocker locker(&d->mutex);
646
647 if (mode == MatchExtension) {
648 return d->mimeTypeForFileExtension(fileName);
649 } else {
650 QFileInfo fileInfo(fileName);
651 return d->mimeTypeForFile(fileName, fileInfo, mode);
652 }
653}
654
655/*!
656 Returns the MIME types for the file name \a fileName.
657
658 If the file name doesn't match any known pattern, an empty list is returned.
659 If multiple MIME types match this file, they are all returned.
660
661 This function does not try to open the file. To also use the content
662 when determining the MIME type, use mimeTypeForFile() or
663 mimeTypeForFileNameAndData() instead.
664
665 \sa mimeTypeForFile()
666*/
667QList<QMimeType> QMimeDatabase::mimeTypesForFileName(const QString &fileName) const
668{
669 QMutexLocker locker(&d->mutex);
670
671 const QStringList matches = d->mimeTypeForFileName(fileName);
672 QList<QMimeType> mimes;
673 mimes.reserve(matches.size());
674 for (const QString &mime : matches)
675 mimes.append(d->mimeTypeForName(mime));
676 return mimes;
677}
678/*!
679 Returns the suffix for the file \a fileName, as known by the MIME database.
680
681 This allows to pre-select "tar.bz2" for foo.tar.bz2, but still only
682 "txt" for my.file.with.dots.txt.
683*/
684QString QMimeDatabase::suffixForFileName(const QString &fileName) const
685{
686 QMutexLocker locker(&d->mutex);
687 const qsizetype suffixLength = d->findByFileName(fileName).m_knownSuffixLength;
688 return fileName.right(suffixLength);
689}
690
691/*!
692 Returns a MIME type for \a data.
693
694 A valid MIME type is always returned. If \a data doesn't match any
695 known MIME type data, the default MIME type (application/octet-stream)
696 is returned.
697*/
698QMimeType QMimeDatabase::mimeTypeForData(const QByteArray &data) const
699{
700 QMutexLocker locker(&d->mutex);
701
702 int accuracy = 0;
703 return d->findByData(data, &accuracy);
704}
705
706/*!
707 Returns a MIME type for the data in \a device.
708
709 A valid MIME type is always returned. If the data in \a device doesn't match any
710 known MIME type data, the default MIME type (application/octet-stream)
711 is returned.
712*/
713QMimeType QMimeDatabase::mimeTypeForData(QIODevice *device) const
714{
715 QMutexLocker locker(&d->mutex);
716
717 return d->mimeTypeForData(device);
718}
719
720/*!
721 Returns a MIME type for \a url.
722
723 If the URL is a local file, this calls mimeTypeForFile.
724
725 Otherwise the matching is done based on the file name only,
726 except for schemes where file names don't mean much, like HTTP.
727 This method always returns the default mimetype for HTTP URLs,
728 use QNetworkAccessManager to handle HTTP URLs properly.
729
730 A valid MIME type is always returned. If \a url doesn't match any
731 known MIME type data, the default MIME type (application/octet-stream)
732 is returned.
733*/
734QMimeType QMimeDatabase::mimeTypeForUrl(const QUrl &url) const
735{
736 if (url.isLocalFile())
737 return mimeTypeForFile(url.toLocalFile());
738
739 const QString scheme = url.scheme();
740 if (scheme.startsWith("http"_L1) || scheme == "mailto"_L1)
741 return mimeTypeForName(d->defaultMimeType());
742
743 return mimeTypeForFile(url.path(), MatchExtension);
744}
745
746/*!
747 Returns a MIME type for the given \a fileName and \a device data.
748
749 This overload can be useful when the file is remote, and we started to
750 download some of its data in a device. This allows to do full MIME type
751 matching for remote files as well.
752
753 If the device is not open, it will be opened by this function, and closed
754 after the MIME type detection is completed.
755
756 A valid MIME type is always returned. If \a device data doesn't match any
757 known MIME type data, the default MIME type (application/octet-stream)
758 is returned.
759
760 This method looks at both the file name and the file contents,
761 if necessary. The file extension has priority over the contents,
762 but the contents will be used if the file extension is unknown, or
763 matches multiple MIME types.
764*/
765QMimeType QMimeDatabase::mimeTypeForFileNameAndData(const QString &fileName, QIODevice *device) const
766{
767 QMutexLocker locker(&d->mutex);
768
769 if (fileName.endsWith(u'/'))
770 return d->mimeTypeForName(directoryMimeType());
771
772 const QMimeType result = d->mimeTypeForFileNameAndData(fileName, device);
773 return result;
774}
775
776/*!
777 Returns a MIME type for the given \a fileName and device \a data.
778
779 This overload can be useful when the file is remote, and we started to
780 download some of its data. This allows to do full MIME type matching for
781 remote files as well.
782
783 A valid MIME type is always returned. If \a data doesn't match any
784 known MIME type data, the default MIME type (application/octet-stream)
785 is returned.
786
787 This method looks at both the file name and the file contents,
788 if necessary. The file extension has priority over the contents,
789 but the contents will be used if the file extension is unknown, or
790 matches multiple MIME types.
791*/
792QMimeType QMimeDatabase::mimeTypeForFileNameAndData(const QString &fileName, const QByteArray &data) const
793{
794 QMutexLocker locker(&d->mutex);
795
796 if (fileName.endsWith(u'/'))
797 return d->mimeTypeForName(directoryMimeType());
798
799 QBuffer buffer(const_cast<QByteArray *>(&data));
800 buffer.open(QIODevice::ReadOnly);
801 return d->mimeTypeForFileNameAndData(fileName, &buffer);
802}
803
804/*!
805 Returns the list of all available MIME types.
806
807 This can be useful for showing all MIME types to the user, for instance
808 in a MIME type editor. Do not use unless really necessary in other cases
809 though, prefer using the \l {mimeTypeForData()}{mimeTypeForXxx()} methods for performance reasons.
810*/
811QList<QMimeType> QMimeDatabase::allMimeTypes() const
812{
813 QMutexLocker locker(&d->mutex);
814
815 return d->allMimeTypes();
816}
817
818/*!
819 \enum QMimeDatabase::MatchMode
820
821 This enum specifies how matching a file to a MIME type is performed.
822
823 \value MatchDefault Both the file name and content are used to look for a match
824
825 \value MatchExtension Only the file name is used to look for a match
826
827 \value MatchContent The file content is used to look for a match
828*/
829
830QT_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