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