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