1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2015 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include "qmimetype.h"
42
43#include "qmimetype_p.h"
44#include "qmimedatabase_p.h"
45#include "qmimeprovider_p.h"
46
47#include "qmimeglobpattern_p.h"
48
49#include <QtCore/QDebug>
50#include <QtCore/QLocale>
51#include <QtCore/QHashFunctions>
52
53#include <memory>
54
55QT_BEGIN_NAMESPACE
56
57QMimeTypePrivate::QMimeTypePrivate()
58 : loaded(false), fromCache(false)
59{}
60
61QMimeTypePrivate::QMimeTypePrivate(const QMimeType &other)
62 : loaded(other.d->loaded),
63 name(other.d->name),
64 localeComments(other.d->localeComments),
65 genericIconName(other.d->genericIconName),
66 iconName(other.d->iconName),
67 globPatterns(other.d->globPatterns)
68{}
69
70void QMimeTypePrivate::clear()
71{
72 name.clear();
73 localeComments.clear();
74 genericIconName.clear();
75 iconName.clear();
76 globPatterns.clear();
77}
78
79void QMimeTypePrivate::addGlobPattern(const QString &pattern)
80{
81 globPatterns.append(t: pattern);
82}
83
84/*!
85 \class QMimeType
86 \inmodule QtCore
87 \ingroup shared
88 \brief The QMimeType class describes types of file or data, represented by a MIME type string.
89
90 \since 5.0
91
92 For instance a file named "readme.txt" has the MIME type "text/plain".
93 The MIME type can be determined from the file name, or from the file
94 contents, or from both. MIME type determination can also be done on
95 buffers of data not coming from files.
96
97 Determining the MIME type of a file can be useful to make sure your
98 application supports it. It is also useful in file-manager-like applications
99 or widgets, in order to display an appropriate \l {QMimeType::iconName}{icon} for the file, or even
100 the descriptive \l {QMimeType::comment()}{comment} in detailed views.
101
102 To check if a file has the expected MIME type, you should use inherits()
103 rather than a simple string comparison based on the name(). This is because
104 MIME types can inherit from each other: for instance a C source file is
105 a specific type of plain text file, so text/x-csrc inherits text/plain.
106
107 \sa QMimeDatabase, {MIME Type Browser Example}
108 */
109
110/*!
111 \fn QMimeType &QMimeType::operator=(QMimeType &&other)
112
113 Move-assigns \a other to this QMimeType instance.
114
115 \since 5.2
116*/
117
118/*!
119 \fn QMimeType::QMimeType();
120 Constructs this QMimeType object initialized with default property values that indicate an invalid MIME type.
121 */
122QMimeType::QMimeType() :
123 d(new QMimeTypePrivate())
124{
125}
126
127/*!
128 \fn QMimeType::QMimeType(const QMimeType &other);
129 Constructs this QMimeType object as a copy of \a other.
130 */
131QMimeType::QMimeType(const QMimeType &other) :
132 d(other.d)
133{
134}
135
136/*!
137 \fn QMimeType &QMimeType::operator=(const QMimeType &other);
138 Assigns the data of \a other to this QMimeType object, and returns a reference to this object.
139 */
140QMimeType &QMimeType::operator=(const QMimeType &other)
141{
142 if (d != other.d)
143 d = other.d;
144 return *this;
145}
146
147/*!
148 \fn QMimeType::QMimeType(const QMimeTypePrivate &dd);
149 Assigns the data of the QMimeTypePrivate \a dd to this QMimeType object, and returns a reference to this object.
150 \internal
151 */
152QMimeType::QMimeType(const QMimeTypePrivate &dd) :
153 d(new QMimeTypePrivate(dd))
154{
155}
156
157/*!
158 \fn void QMimeType::swap(QMimeType &other);
159 Swaps QMimeType \a other with this QMimeType object.
160
161 This operation is very fast and never fails.
162
163 The swap() method helps with the implementation of assignment
164 operators in an exception-safe way. For more information consult
165 \l {http://en.wikibooks.org/wiki/More_C++_Idioms/Copy-and-swap}
166 {More C++ Idioms - Copy-and-swap}.
167 */
168
169/*!
170 \fn QMimeType::~QMimeType();
171 Destroys the QMimeType object, and releases the d pointer.
172 */
173QMimeType::~QMimeType()
174{
175}
176
177/*!
178 \fn bool QMimeType::operator==(const QMimeType &other) const;
179 Returns \c true if \a other equals this QMimeType object, otherwise returns \c false.
180 The name is the unique identifier for a mimetype, so two mimetypes with
181 the same name, are equal.
182 */
183bool QMimeType::operator==(const QMimeType &other) const
184{
185 return d == other.d || d->name == other.d->name;
186}
187
188/*!
189 \since 5.6
190 \relates QMimeType
191
192 Returns the hash value for \a key, using
193 \a seed to seed the calculation.
194 */
195uint qHash(const QMimeType &key, uint seed) noexcept
196{
197 return qHash(key: key.d->name, seed);
198}
199
200/*!
201 \fn bool QMimeType::operator!=(const QMimeType &other) const;
202 Returns \c true if \a other does not equal this QMimeType object, otherwise returns \c false.
203 */
204
205/*!
206 \property QMimeType::valid
207 \brief \c true if the QMimeType object contains valid data, \c false otherwise
208
209 A valid MIME type has a non-empty name().
210 The invalid MIME type is the default-constructed QMimeType.
211
212 While this property was introduced in 5.10, the
213 corresponding accessor method has always been there.
214 */
215bool QMimeType::isValid() const
216{
217 return !d->name.isEmpty();
218}
219
220/*!
221 \property QMimeType::isDefault
222 \brief \c true if this MIME type is the default MIME type which
223 applies to all files: application/octet-stream.
224
225 While this property was introduced in 5.10, the
226 corresponding accessor method has always been there.
227 */
228bool QMimeType::isDefault() const
229{
230 return d->name == QMimeDatabasePrivate::instance()->defaultMimeType();
231}
232
233/*!
234 \property QMimeType::name
235 \brief the name of the MIME type
236
237 While this property was introduced in 5.10, the
238 corresponding accessor method has always been there.
239 */
240QString QMimeType::name() const
241{
242 return d->name;
243}
244
245/*!
246 \property QMimeType::comment
247 \brief the description of the MIME type to be displayed on user interfaces
248
249 The default language (QLocale().name()) is used to select the appropriate translation.
250
251 While this property was introduced in 5.10, the
252 corresponding accessor method has always been there.
253 */
254QString QMimeType::comment() const
255{
256 QMimeDatabasePrivate::instance()->loadMimeTypePrivate(mimePrivate&: const_cast<QMimeTypePrivate&>(*d));
257
258 QStringList languageList;
259 languageList << QLocale().name();
260 languageList << QLocale().uiLanguages();
261 languageList << QLatin1String("default"); // use the default locale if possible.
262 for (const QString &language : qAsConst(t&: languageList)) {
263 const QString lang = language == QLatin1String("C") ? QLatin1String("en_US") : language;
264 const QString comm = d->localeComments.value(akey: lang);
265 if (!comm.isEmpty())
266 return comm;
267 const int pos = lang.indexOf(c: QLatin1Char('_'));
268 if (pos != -1) {
269 // "pt_BR" not found? try just "pt"
270 const QString shortLang = lang.left(n: pos);
271 const QString commShort = d->localeComments.value(akey: shortLang);
272 if (!commShort.isEmpty())
273 return commShort;
274 }
275 }
276
277 // Use the mimetype name as fallback
278 return d->name;
279}
280
281/*!
282 \property QMimeType::genericIconName
283 \brief the file name of a generic icon that represents the MIME type
284
285 This should be used if the icon returned by iconName() cannot be found on
286 the system. It is used for categories of similar types (like spreadsheets
287 or archives) that can use a common icon.
288 The freedesktop.org Icon Naming Specification lists a set of such icon names.
289
290 The icon name can be given to QIcon::fromTheme() in order to load the icon.
291
292 While this property was introduced in 5.10, the
293 corresponding accessor method has always been there.
294 */
295QString QMimeType::genericIconName() const
296{
297 QMimeDatabasePrivate::instance()->loadGenericIcon(mimePrivate&: const_cast<QMimeTypePrivate&>(*d));
298 if (d->genericIconName.isEmpty()) {
299 // From the spec:
300 // If the generic icon name is empty (not specified by the mimetype definition)
301 // then the mimetype is used to generate the generic icon by using the top-level
302 // media type (e.g. "video" in "video/ogg") and appending "-x-generic"
303 // (i.e. "video-x-generic" in the previous example).
304 const QString group = name();
305 QStringRef groupRef(&group);
306 const int slashindex = groupRef.indexOf(ch: QLatin1Char('/'));
307 if (slashindex != -1)
308 groupRef = groupRef.left(n: slashindex);
309 return groupRef + QLatin1String("-x-generic");
310 }
311 return d->genericIconName;
312}
313
314static QString make_default_icon_name_from_mimetype_name(QString iconName)
315{
316 const int slashindex = iconName.indexOf(c: QLatin1Char('/'));
317 if (slashindex != -1)
318 iconName[slashindex] = QLatin1Char('-');
319 return iconName;
320}
321
322/*!
323 \property QMimeType::iconName
324 \brief the file name of an icon image that represents the MIME type
325
326 The icon name can be given to QIcon::fromTheme() in order to load the icon.
327
328 While this property was introduced in 5.10, the
329 corresponding accessor method has always been there.
330 */
331QString QMimeType::iconName() const
332{
333 QMimeDatabasePrivate::instance()->loadIcon(mimePrivate&: const_cast<QMimeTypePrivate&>(*d));
334 if (d->iconName.isEmpty()) {
335 return make_default_icon_name_from_mimetype_name(iconName: name());
336 }
337 return d->iconName;
338}
339
340/*!
341 \property QMimeType::globPatterns
342 \brief the list of glob matching patterns
343
344 While this property was introduced in 5.10, the
345 corresponding accessor method has always been there.
346 */
347QStringList QMimeType::globPatterns() const
348{
349 QMimeDatabasePrivate::instance()->loadMimeTypePrivate(mimePrivate&: const_cast<QMimeTypePrivate&>(*d));
350 return d->globPatterns;
351}
352
353/*!
354 \property QMimeType::parentMimeTypes
355 \brief the names of parent MIME types
356
357 A type is a subclass of another type if any instance of the first type is
358 also an instance of the second. For example, all image/svg+xml files are also
359 text/xml, text/plain and application/octet-stream files. Subclassing is about
360 the format, rather than the category of the data (for example, there is no
361 'generic spreadsheet' class that all spreadsheets inherit from).
362 Conversely, the parent mimetype of image/svg+xml is text/xml.
363
364 A mimetype can have multiple parents. For instance application/x-perl
365 has two parents: application/x-executable and text/plain. This makes
366 it possible to both execute perl scripts, and to open them in text editors.
367
368 While this property was introduced in 5.10, the
369 corresponding accessor method has always been there.
370*/
371QStringList QMimeType::parentMimeTypes() const
372{
373 return QMimeDatabasePrivate::instance()->mimeParents(mimeName: d->name);
374}
375
376static void collectParentMimeTypes(const QString &mime, QStringList &allParents)
377{
378 const QStringList parents = QMimeDatabasePrivate::instance()->mimeParents(mimeName: mime);
379 for (const QString &parent : parents) {
380 // I would use QSet, but since order matters I better not
381 if (!allParents.contains(str: parent))
382 allParents.append(t: parent);
383 }
384 // We want a breadth-first search, so that the least-specific parent (octet-stream) is last
385 // This means iterating twice, unfortunately.
386 for (const QString &parent : parents)
387 collectParentMimeTypes(mime: parent, allParents);
388}
389
390/*!
391 \property QMimeType::allAncestors
392 \brief the names of direct and indirect parent MIME types
393
394 Return all the parent mimetypes of this mimetype, direct and indirect.
395 This includes the parent(s) of its parent(s), etc.
396
397 For instance, for image/svg+xml the list would be:
398 application/xml, text/plain, application/octet-stream.
399
400 Note that application/octet-stream is the ultimate parent for all types
401 of files (but not directories).
402
403 While this property was introduced in 5.10, the
404 corresponding accessor method has always been there.
405*/
406QStringList QMimeType::allAncestors() const
407{
408 QStringList allParents;
409 collectParentMimeTypes(mime: d->name, allParents);
410 return allParents;
411}
412
413/*!
414 \property QMimeType::aliases
415 \brief the list of aliases of this mimetype
416
417 For instance, for text/csv, the returned list would be:
418 text/x-csv, text/x-comma-separated-values.
419
420 Note that all QMimeType instances refer to proper mimetypes,
421 never to aliases directly.
422
423 The order of the aliases in the list is undefined.
424
425 While this property was introduced in 5.10, the
426 corresponding accessor method has always been there.
427*/
428QStringList QMimeType::aliases() const
429{
430 return QMimeDatabasePrivate::instance()->listAliases(mimeName: d->name);
431}
432
433/*!
434 \property QMimeType::suffixes
435 \brief the known suffixes for the MIME type
436
437 No leading dot is included, so for instance this would return "jpg", "jpeg" for image/jpeg.
438
439 While this property was introduced in 5.10, the
440 corresponding accessor method has always been there.
441 */
442QStringList QMimeType::suffixes() const
443{
444 QMimeDatabasePrivate::instance()->loadMimeTypePrivate(mimePrivate&: const_cast<QMimeTypePrivate&>(*d));
445
446 QStringList result;
447 for (const QString &pattern : qAsConst(t&: d->globPatterns)) {
448 // Not a simple suffix if it looks like: README or *. or *.* or *.JP*G or *.JP?
449 if (pattern.startsWith(s: QLatin1String("*.")) &&
450 pattern.length() > 2 &&
451 pattern.indexOf(c: QLatin1Char('*'), from: 2) < 0 && pattern.indexOf(c: QLatin1Char('?'), from: 2) < 0) {
452 const QString suffix = pattern.mid(position: 2);
453 result.append(t: suffix);
454 }
455 }
456
457 return result;
458}
459
460/*!
461 \property QMimeType::preferredSuffix
462 \brief the preferred suffix for the MIME type
463
464 No leading dot is included, so for instance this would return "pdf" for application/pdf.
465 The return value can be empty, for mime types which do not have any suffixes associated.
466
467 While this property was introduced in 5.10, the
468 corresponding accessor method has always been there.
469 */
470QString QMimeType::preferredSuffix() const
471{
472 if (isDefault()) // workaround for unwanted *.bin suffix for octet-stream, https://bugs.freedesktop.org/show_bug.cgi?id=101667, fixed upstream in 1.10
473 return QString();
474 const QStringList suffixList = suffixes();
475 return suffixList.isEmpty() ? QString() : suffixList.at(i: 0);
476}
477
478/*!
479 \property QMimeType::filterString
480 \brief a filter string usable for a file dialog
481
482 While this property was introduced in 5.10, the
483 corresponding accessor method has always been there.
484*/
485QString QMimeType::filterString() const
486{
487 QMimeDatabasePrivate::instance()->loadMimeTypePrivate(mimePrivate&: const_cast<QMimeTypePrivate&>(*d));
488 QString filter;
489
490 if (!d->globPatterns.empty()) {
491 filter += comment() + QLatin1String(" (");
492 for (int i = 0; i < d->globPatterns.size(); ++i) {
493 if (i != 0)
494 filter += QLatin1Char(' ');
495 filter += d->globPatterns.at(i);
496 }
497 filter += QLatin1Char(')');
498 }
499
500 return filter;
501}
502
503/*!
504 \fn bool QMimeType::inherits(const QString &mimeTypeName) const;
505 Returns \c true if this mimetype is \a mimeTypeName,
506 or inherits \a mimeTypeName (see parentMimeTypes()),
507 or \a mimeTypeName is an alias for this mimetype.
508
509 This method has been made invokable from QML since 5.10.
510 */
511bool QMimeType::inherits(const QString &mimeTypeName) const
512{
513 if (d->name == mimeTypeName)
514 return true;
515 return QMimeDatabasePrivate::instance()->mimeInherits(mime: d->name, parent: mimeTypeName);
516}
517
518#ifndef QT_NO_DEBUG_STREAM
519QDebug operator<<(QDebug debug, const QMimeType &mime)
520{
521 QDebugStateSaver saver(debug);
522 if (!mime.isValid()) {
523 debug.nospace() << "QMimeType(invalid)";
524 } else {
525 debug.nospace() << "QMimeType(" << mime.name() << ")";
526 }
527 return debug;
528}
529#endif
530
531QT_END_NAMESPACE
532
533#include "moc_qmimetype.cpp"
534

source code of qtbase/src/corelib/mimetypes/qmimetype.cpp