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 m_mimes.reserve(s_types.size());
48 // cppcheck-suppress unassignedVariable
49 for (const auto & [name, suffix, magic, weight, inherits] : s_types)
50 m_mimes.push_back({name, suffix, magic, weight, inherits});
51 }
52
53 const MythMimeTypes& AllTypes() const
54 {
55 return m_mimes;
56 }
57
58 MythMimeType MimeTypeForName(const QString& Name) const
59 {
60 auto found = std::ranges::find_if(m_mimes,
61 [&Name](const auto & Mime) { return Name.compare(Mime.Name(), Qt::CaseInsensitive) == 0; });
62 if (found != m_mimes.end())
63 return *found;
64 return MythMimeType {};
65 }
66
67 MythMimeTypes MimeTypesForFileName(const QString &FileName) const
68 {
69 MythMimeTypes result;
70 auto name = FileName.trimmed().toLower();
71 for (const auto & mime : m_mimes)
72 if (name.endsWith(mime.m_suffix))
73 result.push_back(mime);
74 return result;
75 }
76
77 QString SuffixForFileName(const QString &FileName) const
78 {
79 auto name = FileName.trimmed().toLower();
80 for (const auto & mime : m_mimes)
81 if (name.endsWith(mime.m_suffix))
82 return mime.Suffix();
83 return ".";
84 }
85
86 static MythMimeType MagicSearch(const MythMimeTypes& Types, const QByteArray& Data)
87 {
88 MythMimeType result;
89 for (const auto & mime : Types)
90 {
91 if (const auto * bytes = std::get_if<QByteArray>(&mime.m_magic); bytes)
92 {
93 if (Data.contains(*bytes) && (mime.m_weight > result.m_weight))
94 result = mime;
95 }
96 else if (const auto * string = std::get_if<QString>(&mime.m_magic); string)
97 {
98 if (QString(Data.constData()).contains(*string, Qt::CaseInsensitive) && (mime.m_weight > result.m_weight))
99 result = mime;
100 }
101 }
102 return result;
103 }
104
105 MythMimeType MimeTypeForFileNameAndData(const QString& FileName, QIODevice* Device) const
106 {
107 // Try and match by extension
108 auto filtered = MimeTypesForFileName(FileName);
109
110 // If we have a single extension match, return it
111 if (filtered.size() == 1)
112 return filtered.front();
113
114 // If device is not opened, open it
115 bool wasopen = Device->isOpen();
116 if (!wasopen)
117 Device->open(QIODevice::ReadOnly);
118
119 // Peek at the contents
120 auto peek = Device->peek(PEEK_SIZE);
121
122 // Use matched types or fallback to all for magic search
123 auto result = MagicSearch(filtered.empty() ? AllTypes() : filtered, peek);
124
125 // Close again if necessary
126 if (!wasopen)
127 Device->close();
128
129 return result;
130 }
131
132 static MythMimeTypes ToMythMimeTypes(const QList<QMimeType>& Types)
133 {
134 MythMimeTypes result;
135 std::ranges::transform(std::as_const(Types), std::back_inserter(result),
136 [](const auto& Type) { return MythMimeType { Type }; });
137 return result;
138 }
139
140 private:
142};
143
144//NOLINTNEXTLINE(readability-redundant-member-init)
145Q_GLOBAL_STATIC(MythMimeDatabasePriv, s_mimeDB)
146
147
161 : m_priv(s_mimeDB)
162{
163}
164
168{
169 auto all = MythMimeDatabasePriv::ToMythMimeTypes(QMimeDatabase().allMimeTypes());
170 const auto & mythtv = s_mimeDB->AllTypes();
171 all.insert(all.cend(), mythtv.cbegin(), mythtv.cend());
172 return all;
173}
174
178{
179 auto result = MythMimeDatabasePriv::ToMythMimeTypes(QMimeDatabase().mimeTypesForFileName(FileName));
180 const auto mythtv = s_mimeDB->MimeTypesForFileName(FileName);
181 result.insert(result.cend(), mythtv.cbegin(), mythtv.cend());
182 return result;
183}
184
189QString MythMimeDatabase::SuffixForFileName(const QString &FileName)
190{
191 if (auto result = QMimeDatabase().suffixForFileName(FileName); !result.isEmpty())
192 return result;
193 return s_mimeDB->SuffixForFileName(FileName);
194}
195
204{
205 if (auto result = s_mimeDB->MimeTypeForName(Name); result.IsValid())
206 return result;
207 return QMimeDatabase().mimeTypeForName(Name);
208}
209
219MythMimeType MythMimeDatabase::MimeTypeForFileNameAndData(const QString& FileName, const QByteArray& Data)
220{
221 if (auto result = QMimeDatabase().mimeTypeForFileNameAndData(FileName, Data); result.isValid())
222 return result;
223 QBuffer buffer(const_cast<QByteArray*>(&Data));
224 return s_mimeDB->MimeTypeForFileNameAndData(FileName, &buffer);
225}
226
228{
229 if (auto result = QMimeDatabase().mimeTypeForFileNameAndData(FileName, Device); result.isValid())
230 return result;
231 return s_mimeDB->MimeTypeForFileNameAndData(FileName, Device);
232}
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