MythTV master
mythmimedatabase.cpp
Go to the documentation of this file.
1// Qt
2#include <QBuffer>
3#include <QIODevice>
4#include <QGlobalStatic>
5#include <QMimeDatabase>
6#include <QStandardPaths>
7#include <algorithm>
8
9// MythTV
10#include "mythlogging.h"
12
13#define LOC QString("MimeDB: ")
14static constexpr qint64 PEEK_SIZE { 100 };
15
22{
23 using MimeDesc = std::tuple<QString,QString,MimeMagic,uint,QStringList>;
24
25 public:
27 {
28 auto paths =
29 QStandardPaths::locateAll(QStandardPaths::GenericDataLocation,
30 QLatin1String("mime/packages"),
31 QStandardPaths::LocateDirectory);
32 LOG(VB_GENERAL, LOG_DEBUG, LOC +
33 QString("Standard paths: %1").arg(paths.join(", ")));
34
35 static const std::vector<MimeDesc> s_types =
36 {
37 { "application/cbor", ".cbor", { std::monostate() }, 90, {}},
38 { "application/x-www-form-urlencoded", ".json", { std::monostate() }, 10, { "text/plain" }},
39 { "application/x-plist", ".plist", { QByteArrayLiteral("bplist00") }, 50, {}},
40 { "application/x-apple-binary-plist", ".plist", { QByteArrayLiteral("bplist00") }, 50, {}},
41 { "text/x-apple-plist+xml", ".plist", { QStringLiteral("http://www.apple.com/DTDs/PropertyList-1.0.dtd") },
42 50, { "text/plain", "application/xml"}}
43 };
44
45 LOG(VB_GENERAL, LOG_DEBUG, LOC +
46 QString("Custom entries: %1").arg(s_types.size()));
47 // cppcheck-suppress unassignedVariable
48 for (const auto & [name, suffix, magic, weight, inherits] : s_types)
49 m_mimes.push_back({name, suffix, magic, weight, inherits});
50 }
51
52 const MythMimeTypes& AllTypes() const
53 {
54 return m_mimes;
55 }
56
57 MythMimeType MimeTypeForName(const QString& Name) const
58 {
59 auto found = std::ranges::find_if(m_mimes,
60 [&Name](const auto & Mime) { return Name.compare(Mime.Name(), Qt::CaseInsensitive) == 0; });
61 if (found != m_mimes.end())
62 return *found;
63 return MythMimeType {};
64 }
65
66 MythMimeTypes MimeTypesForFileName(const QString &FileName) const
67 {
68 MythMimeTypes result;
69 auto name = FileName.trimmed().toLower();
70 for (const auto & mime : m_mimes)
71 if (name.endsWith(mime.m_suffix))
72 result.push_back(mime);
73 return result;
74 }
75
76 QString SuffixForFileName(const QString &FileName) const
77 {
78 auto name = FileName.trimmed().toLower();
79 for (const auto & mime : m_mimes)
80 if (name.endsWith(mime.m_suffix))
81 return mime.Suffix();
82 return ".";
83 }
84
85 static MythMimeType MagicSearch(const MythMimeTypes& Types, const QByteArray& Data)
86 {
87 MythMimeType result;
88 for (const auto & mime : Types)
89 {
90 if (const auto * bytes = std::get_if<QByteArray>(&mime.m_magic); bytes)
91 {
92 if (Data.contains(*bytes) && (mime.m_weight > result.m_weight))
93 result = mime;
94 }
95 else if (const auto * string = std::get_if<QString>(&mime.m_magic); string)
96 {
97 if (QString(Data.constData()).contains(*string, Qt::CaseInsensitive) && (mime.m_weight > result.m_weight))
98 result = mime;
99 }
100 }
101 return result;
102 }
103
104 MythMimeType MimeTypeForFileNameAndData(const QString& FileName, QIODevice* Device) const
105 {
106 // Try and match by extension
107 auto filtered = MimeTypesForFileName(FileName);
108
109 // If we have a single extension match, return it
110 if (filtered.size() == 1)
111 return filtered.front();
112
113 // If device is not opened, open it
114 bool wasopen = Device->isOpen();
115 if (!wasopen)
116 Device->open(QIODevice::ReadOnly);
117
118 // Peek at the contents
119 auto peek = Device->peek(PEEK_SIZE);
120
121 // Use matched types or fallback to all for magic search
122 auto result = MagicSearch(filtered.empty() ? AllTypes() : filtered, peek);
123
124 // Close again if necessary
125 if (!wasopen)
126 Device->close();
127
128 return result;
129 }
130
131 static MythMimeTypes ToMythMimeTypes(const QList<QMimeType>& Types)
132 {
133 MythMimeTypes result;
134 std::ranges::transform(std::as_const(Types), std::back_inserter(result),
135 [](const auto& Type) { return MythMimeType { Type }; });
136 return result;
137 }
138
139 private:
141};
142
143//NOLINTNEXTLINE(readability-redundant-member-init)
144Q_GLOBAL_STATIC(MythMimeDatabasePriv, s_mimeDB)
145
146
160 : m_priv(s_mimeDB)
161{
162}
163
167{
168 auto all = MythMimeDatabasePriv::ToMythMimeTypes(QMimeDatabase().allMimeTypes());
169 const auto & mythtv = s_mimeDB->AllTypes();
170 all.insert(all.cend(), mythtv.cbegin(), mythtv.cend());
171 return all;
172}
173
177{
178 auto result = MythMimeDatabasePriv::ToMythMimeTypes(QMimeDatabase().mimeTypesForFileName(FileName));
179 const auto mythtv = s_mimeDB->MimeTypesForFileName(FileName);
180 result.insert(result.cend(), mythtv.cbegin(), mythtv.cend());
181 return result;
182}
183
188QString MythMimeDatabase::SuffixForFileName(const QString &FileName)
189{
190 if (auto result = QMimeDatabase().suffixForFileName(FileName); !result.isEmpty())
191 return result;
192 return s_mimeDB->SuffixForFileName(FileName);
193}
194
203{
204 if (auto result = s_mimeDB->MimeTypeForName(Name); result.IsValid())
205 return result;
206 return QMimeDatabase().mimeTypeForName(Name);
207}
208
218MythMimeType MythMimeDatabase::MimeTypeForFileNameAndData(const QString& FileName, const QByteArray& Data)
219{
220 if (auto result = QMimeDatabase().mimeTypeForFileNameAndData(FileName, Data); result.isValid())
221 return result;
222 QBuffer buffer(const_cast<QByteArray*>(&Data));
223 return s_mimeDB->MimeTypeForFileNameAndData(FileName, &buffer);
224}
225
227{
228 if (auto result = QMimeDatabase().mimeTypeForFileNameAndData(FileName, Device); result.isValid())
229 return result;
230 return s_mimeDB->MimeTypeForFileNameAndData(FileName, Device);
231}
A device containing images (ie. USB stick, CD, storage group etc)
A private, internal class that holds custom mime types.
const MythMimeTypes & AllTypes() const
static MythMimeType MagicSearch(const MythMimeTypes &Types, const QByteArray &Data)
QString SuffixForFileName(const QString &FileName) const
MythMimeType MimeTypeForName(const QString &Name) const
static MythMimeTypes ToMythMimeTypes(const QList< QMimeType > &Types)
MythMimeTypes MimeTypesForFileName(const QString &FileName) const
std::tuple< QString, QString, MimeMagic, uint, QStringList > MimeDesc
MythMimeType MimeTypeForFileNameAndData(const QString &FileName, QIODevice *Device) const
A wrapper around QMimeDatabase that supports additional mime types.
static MythMimeTypes MimeTypesForFileName(const QString &FileName)
Return a vector of mime types that match the given filename.
static QString SuffixForFileName(const QString &FileName)
Return the preferred suffix for the given filename.
static MythMimeType MimeTypeForName(const QString &Name)
Return a mime type that matches the given name.
static MythMimeTypes AllTypes()
Return a vector containing all of the known types (both Qt and MythTV)
static MythMimeType MimeTypeForFileNameAndData(const QString &FileName, const QByteArray &Data)
Return a mime type for the given FileName and data.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
#define LOC
static constexpr qint64 PEEK_SIZE
std::vector< MythMimeType > MythMimeTypes
Definition: mythmimetype.h:13