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
qmimetype.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:significant reason:default
5
6#include "qmimetype.h"
7
8#include "qmimetype_p.h"
10
11#include <QtCore/QCoreApplication>
12#include <QtCore/QDebug>
13#include <QtCore/QLocale>
14#include <QtCore/QHashFunctions>
15
16#include <memory>
17
19
20using namespace Qt::StringLiterals;
21
22/*!
23 \class QMimeType
24 \inmodule QtCore
25 \ingroup shared
26 \brief The QMimeType class describes types of file or data, represented by a MIME type string.
27
28 \since 5.0
29 \compares equality
30
31 For instance a file named "readme.txt" has the MIME type "text/plain".
32 The MIME type can be determined from the file name, or from the file
33 contents, or from both. MIME type determination can also be done on
34 buffers of data not coming from files.
35
36 Determining the MIME type of a file can be useful to make sure your
37 application supports it. It is also useful in file-manager-like applications
38 or widgets, in order to display an appropriate \l {QMimeType::iconName}{icon} for the file, or even
39 the descriptive \l {QMimeType::comment()}{comment} in detailed views.
40
41 To check if a file has the expected MIME type, you should use inherits()
42 rather than a simple string comparison based on the name(). This is because
43 MIME types can inherit from each other: for instance a C source file is
44 a specific type of plain text file, so text/x-csrc inherits text/plain.
45
46 \sa QMimeDatabase, {MIME Type Browser}
47 */
48
49/*!
50 \fn QMimeType &QMimeType::operator=(QMimeType &&other)
51
52 Move-assigns \a other to this QMimeType instance.
53
54 \since 5.2
55*/
56
57/*!
58 \fn QMimeType::QMimeType();
59 Constructs this QMimeType object initialized with default property values that indicate an invalid MIME type.
60 */
61QMimeType::QMimeType() :
62 d(new QMimeTypePrivate())
63{
64}
65
66/*!
67 \fn QMimeType::QMimeType(const QMimeType &other);
68 Constructs this QMimeType object as a copy of \a other.
69 */
70QMimeType::QMimeType(const QMimeType &other) :
71 d(other.d)
72{
73}
74
75/*!
76 \fn QMimeType &QMimeType::operator=(const QMimeType &other);
77 Assigns the data of \a other to this QMimeType object, and returns a reference to this object.
78 */
79QMimeType &QMimeType::operator=(const QMimeType &other)
80{
81 if (d != other.d)
82 d = other.d;
83 return *this;
84}
85
86/*!
87 \fn QMimeType::QMimeType(const QMimeTypePrivate &dd);
88 Assigns the data of the QMimeTypePrivate \a dd to this QMimeType object, and returns a reference to this object.
89 \internal
90 */
91QMimeType::QMimeType(const QMimeTypePrivate &dd) :
92 d(new QMimeTypePrivate(dd))
93{
94}
95
96/*!
97 \fn void QMimeType::swap(QMimeType &other);
98 \memberswap{mime type}
99
100 The swap() method helps with the implementation of assignment
101 operators in an exception-safe way. For more information consult
102 \l {http://en.wikibooks.org/wiki/More_C++_Idioms/Copy-and-swap}
103 {More C++ Idioms - Copy-and-swap}.
104 */
105
106/*!
107 \fn QMimeType::~QMimeType();
108 Destroys the QMimeType object, and releases the d pointer.
109 */
110QMimeType::~QMimeType()
111{
112}
113
114/*!
115 \fn bool QMimeType::operator==(const QMimeType &lhs, const QMimeType &rhs);
116 Returns \c true if \a lhs equals to the \a rhs QMimeType object, otherwise
117 returns \c false.
118 The name is the unique identifier for a mimetype, so two mimetypes with
119 the same name, are equal.
120 */
121bool comparesEqual(const QMimeType &lhs, const QMimeType &rhs) noexcept
122{
123 return lhs.d == rhs.d || lhs.d->name == rhs.d->name;
124}
125
126/*!
127 \since 5.6
128 \qhashold{QMimeType}
129 */
130size_t qHash(const QMimeType &key, size_t seed) noexcept
131{
132 return qHash(key.d->name, seed);
133}
134
135/*!
136 \fn bool QMimeType::operator!=(const QMimeType &lhs, const QMimeType &rhs);
137 Returns \c true if QMimeType \a lhs is not equal to QMimeType \a rhs,
138 otherwise returns \c false.
139 */
140
141/*!
142 \property QMimeType::valid
143 \brief \c true if the QMimeType object contains valid data, \c false otherwise
144
145 A valid MIME type has a non-empty name().
146 The invalid MIME type is the default-constructed QMimeType.
147
148 While this property was introduced in 5.10, the
149 corresponding accessor method has always been there.
150 */
151bool QMimeType::isValid() const
152{
153 return !d->name.isEmpty();
154}
155
156/*!
157 \property QMimeType::isDefault
158 \brief \c true if this MIME type is the default MIME type which
159 applies to all files: application/octet-stream.
160
161 While this property was introduced in 5.10, the
162 corresponding accessor method has always been there.
163 */
164bool QMimeType::isDefault() const
165{
166 return d->name == QMimeDatabasePrivate::instance()->defaultMimeType();
167}
168
169/*!
170 \property QMimeType::name
171 \brief the name of the MIME type
172
173 While this property was introduced in 5.10, the
174 corresponding accessor method has always been there.
175 */
176QString QMimeType::name() const
177{
178 return d->name;
179}
180
181/*!
182 \property QMimeType::comment
183 \brief the description of the MIME type to be displayed on user interfaces
184
185 Returns a description for a MIME type, localized to the user's
186 current language settings.
187
188 While this property was introduced in 5.10, the
189 corresponding accessor method has always been there.
190 */
191QString QMimeType::comment() const
192{
193 const auto isEnUs = [](QStringView lang) {
194 // All synonyms of en_US, according to CLDR likely subtag rules:
195 static constexpr QLatin1StringView usaIsh[] =
196 { "en_Latn_US"_L1, "en_US"_L1, "en_Latn"_L1, "en"_L1 };
197 return std::find(std::begin(usaIsh), std::end(usaIsh), lang) != std::end(usaIsh);
198 };
199 const auto localeComments = QMimeDatabasePrivate::instance()->localeComments(d->name);
200 const QStringList languageList = QLocale().uiLanguages(QLocale::TagSeparator::Underscore);
201 QString comment = localeComments.value(u"default"_s);
202
203 for (const QString &language : std::as_const(languageList)) {
204 const QString lang = language == "C"_L1 ? u"en_US"_s : language;
205 QString translated = localeComments.value(lang);
206 if (!translated.isEmpty())
207 return translated;
208 if (!comment.isEmpty() && isEnUs(lang))
209 return comment; // The default entry is assumed to be in en-US
210 }
211 QString translated =
212 QCoreApplication::translate("QMimeType", comment.toUtf8().constData());
213 if (!translated.isEmpty())
214 return translated;
215
216 // Use the mimetype name as fallback
217 return d->name;
218}
219
220/*!
221 \property QMimeType::genericIconName
222 \brief the file name of a generic icon that represents the MIME type
223
224 This should be used if the icon returned by iconName() cannot be found on
225 the system. It is used for categories of similar types (like spreadsheets
226 or archives) that can use a common icon.
227 The freedesktop.org Icon Naming Specification lists a set of such icon names.
228
229 The icon name can be given to QIcon::fromTheme() in order to load the icon.
230
231 While this property was introduced in 5.10, the
232 corresponding accessor method has always been there.
233 */
234QString QMimeType::genericIconName() const
235{
236 QString genericIconName = QMimeDatabasePrivate::instance()->genericIcon(d->name);
237 if (genericIconName.isEmpty()) {
238 // From the spec:
239 // If the generic icon name is empty (not specified by the mimetype definition)
240 // then the mimetype is used to generate the generic icon by using the top-level
241 // media type (e.g. "video" in "video/ogg") and appending "-x-generic"
242 // (i.e. "video-x-generic" in the previous example).
243 const QString group = name();
244 QStringView groupRef(group);
245 const qsizetype slashindex = groupRef.indexOf(u'/');
246 if (slashindex != -1)
247 groupRef = groupRef.left(slashindex);
248 return groupRef + "-x-generic"_L1;
249 }
250 return genericIconName;
251}
252
254{
255 const qsizetype slashindex = iconName.indexOf(u'/');
256 if (slashindex != -1)
257 iconName[slashindex] = u'-';
258 return iconName;
259}
260
261/*!
262 \property QMimeType::iconName
263 \brief the file name of an icon image that represents the MIME type
264
265 The icon name can be given to QIcon::fromTheme() in order to load the icon.
266
267 While this property was introduced in 5.10, the
268 corresponding accessor method has always been there.
269 */
270QString QMimeType::iconName() const
271{
272 QString iconName = QMimeDatabasePrivate::instance()->icon(d->name);
273 if (iconName.isEmpty()) {
274 return make_default_icon_name_from_mimetype_name(name());
275 }
276 return iconName;
277}
278
279/*!
280 \property QMimeType::globPatterns
281 \brief the list of glob matching patterns
282
283 While this property was introduced in 5.10, the
284 corresponding accessor method has always been there.
285 */
286QStringList QMimeType::globPatterns() const
287{
288 return QMimeDatabasePrivate::instance()->globPatterns(d->name);
289}
290
291/*!
292 \property QMimeType::parentMimeTypes
293 \brief the names of parent MIME types
294
295 A type is a subclass of another type if any instance of the first type is
296 also an instance of the second. For example, all image/svg+xml files are also
297 text/xml, text/plain and application/octet-stream files. Subclassing is about
298 the format, rather than the category of the data (for example, there is no
299 'generic spreadsheet' class that all spreadsheets inherit from).
300 Conversely, the parent mimetype of image/svg+xml is text/xml.
301
302 A mimetype can have multiple parents. For instance application/x-perl
303 has two parents: application/x-executable and text/plain. This makes
304 it possible to both execute perl scripts, and to open them in text editors.
305
306 While this property was introduced in 5.10, the
307 corresponding accessor method has always been there.
308*/
309QStringList QMimeType::parentMimeTypes() const
310{
311 return QMimeDatabasePrivate::instance()->mimeParents(d->name);
312}
313
314static void collectParentMimeTypes(const QString &mime, QStringList &allParents)
315{
316 const QStringList parents = QMimeDatabasePrivate::instance()->mimeParents(mime);
317 QStringList newParents;
318 for (const QString &parent : parents) {
319 // I would use QSet, but since order matters I better not
320 if (!allParents.contains(parent)) {
321 allParents.append(parent);
322 newParents.append(parent);
323 }
324 }
325 // We want a breadth-first search, so that the least-specific parent (octet-stream) is last
326 // This means iterating twice, unfortunately.
327 for (const QString &parent : newParents)
328 collectParentMimeTypes(parent, allParents);
329}
330
331/*!
332 \property QMimeType::allAncestors
333 \brief the names of direct and indirect parent MIME types
334
335 Return all the parent mimetypes of this mimetype, direct and indirect.
336 This includes the parent(s) of its parent(s), etc.
337
338 For instance, for image/svg+xml the list would be:
339 application/xml, text/plain, application/octet-stream.
340
341 Note that application/octet-stream is the ultimate parent for all types
342 of files (but not directories).
343
344 While this property was introduced in 5.10, the
345 corresponding accessor method has always been there.
346*/
347QStringList QMimeType::allAncestors() const
348{
349 QStringList allParents;
350 collectParentMimeTypes(d->name, allParents);
351 return allParents;
352}
353
354/*!
355 \property QMimeType::aliases
356 \brief the list of aliases of this mimetype
357
358 For instance, for text/csv, the returned list would be:
359 text/x-csv, text/x-comma-separated-values.
360
361 Note that all QMimeType instances refer to proper mimetypes,
362 never to aliases directly.
363
364 The order of the aliases in the list is undefined.
365
366 While this property was introduced in 5.10, the
367 corresponding accessor method has always been there.
368*/
369QStringList QMimeType::aliases() const
370{
371 return QMimeDatabasePrivate::instance()->listAliases(d->name);
372}
373
374/*!
375 \property QMimeType::suffixes
376 \brief the known suffixes for the MIME type
377
378 No leading dot is included, so for instance this would return "jpg", "jpeg" for image/jpeg.
379
380 While this property was introduced in 5.10, the
381 corresponding accessor method has always been there.
382 */
383QStringList QMimeType::suffixes() const
384{
385 const QStringList patterns = globPatterns();
386
387 QStringList result;
388 result.reserve(patterns.size());
389 for (const QString &pattern : patterns) {
390 // Not a simple suffix if it looks like: README or *. or *.* or *.JP*G or *.JP?
391 if (pattern.startsWith("*."_L1) &&
392 pattern.size() > 2 &&
393 pattern.indexOf(u'*', 2) < 0 && pattern.indexOf(u'?', 2) < 0) {
394 const QString suffix = pattern.mid(2);
395 result.append(suffix);
396 }
397 }
398
399 return result;
400}
401
402/*!
403 \property QMimeType::preferredSuffix
404 \brief the preferred suffix for the MIME type
405
406 No leading dot is included, so for instance this would return "pdf" for application/pdf.
407 The return value can be empty, for mime types which do not have any suffixes associated.
408
409 While this property was introduced in 5.10, the
410 corresponding accessor method has always been there.
411 */
412QString QMimeType::preferredSuffix() const
413{
414 if (isDefault()) // workaround for unwanted *.bin suffix for octet-stream, https://bugs.freedesktop.org/show_bug.cgi?id=101667, fixed upstream in 1.10
415 return QString();
416 const QStringList suffixList = suffixes();
417 return suffixList.isEmpty() ? QString() : suffixList.at(0);
418}
419
420/*!
421 \property QMimeType::filterString
422 \brief a filter string usable for a file dialog
423
424 While this property was introduced in 5.10, the
425 corresponding accessor method has always been there.
426*/
427QString QMimeType::filterString() const
428{
429 const QStringList patterns = globPatterns();
430 QString filter;
431
432 if (!patterns.isEmpty()) {
433 filter = comment() + " ("_L1 + patterns.join(u' ') + u')';
434 }
435
436 return filter;
437}
438
439/*!
440 \fn bool QMimeType::inherits(const QString &mimeTypeName) const;
441 Returns \c true if this mimetype is \a mimeTypeName,
442 or inherits \a mimeTypeName (see parentMimeTypes()),
443 or \a mimeTypeName is an alias for this mimetype.
444
445 This method has been made invokable from QML since 5.10.
446 */
447bool QMimeType::inherits(const QString &mimeTypeName) const
448{
449 if (d->name == mimeTypeName)
450 return true;
451 return QMimeDatabasePrivate::instance()->mimeInherits(d->name, mimeTypeName);
452}
453
454#ifndef QT_NO_DEBUG_STREAM
455QDebug operator<<(QDebug debug, const QMimeType &mime)
456{
457 QDebugStateSaver saver(debug);
458 if (!mime.isValid()) {
459 debug.nospace() << "QMimeType(invalid)";
460 } else {
461 debug.nospace() << "QMimeType(" << mime.name() << ")";
462 }
463 return debug;
464}
465#endif
466
467QT_END_NAMESPACE
468
469#include "moc_qmimetype.cpp"
static QMimeDatabasePrivate * instance()
Combined button and popup list for selecting options.
static QString make_default_icon_name_from_mimetype_name(QString iconName)
bool comparesEqual(const QMimeType &lhs, const QMimeType &rhs) noexcept
size_t qHash(const QMimeType &key, size_t seed) noexcept
static void collectParentMimeTypes(const QString &mime, QStringList &allParents)