41#include <QSequentialIterable>
50#define LOC QString("PList: ")
52static const QByteArray
MAGIC {
"bplist" };
54#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
96#if (Q_BYTE_ORDER == Q_BIG_ENDIAN) && !defined (__VFP_FP__)
97 return *(
reinterpret_cast<const T *
>(
p));
99 static std::array<uint8_t,
sizeof(T)> temp;
100 for (
size_t i = 0; i < (
sizeof(T) / 2); i++)
102 size_t j =
sizeof(T) - 1 - i;
106 return *(
reinterpret_cast<const T *
>(temp.data()));
117#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
118 auto type =
static_cast<QMetaType::Type
>(
m_result.type());
123 if (
type != QMetaType::QVariantMap)
127 for (
auto it = map.cbegin(); it != map.cend(); ++it)
137 buf.open(QBuffer::WriteOnly);
145 QXmlStreamWriter xml(
Device);
146 xml.setAutoFormatting(
true);
147 xml.setAutoFormattingIndent(4);
148 xml.writeStartDocument();
149 xml.writeDTD(R
"(<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">)");
150 xml.writeStartElement("plist");
151 xml.writeAttribute(
"version",
"1.0");
153 xml.writeEndElement();
154 xml.writeEndDocument();
156 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Invalid result.");
162#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
163 auto type =
static_cast<QMetaType::Type
>(Data.type());
165 auto type = Data.typeId();
169 case QMetaType::QVariantMap:
172 case QMetaType::QVariantList:
175 case QMetaType::Double:
176 Xml.writeTextElement(
"real", QString(
"%1").arg(Data.toDouble(), 0,
'f', 6));
178 case QMetaType::QByteArray:
179 Xml.writeTextElement(
"data", Data.toByteArray().toBase64().data());
181 case QMetaType::ULongLong:
182 Xml.writeTextElement(
"integer", QString(
"%1").arg(Data.toULongLong()));
184 case QMetaType::QString:
185 Xml.writeTextElement(
"string", Data.toString());
187 case QMetaType::QDateTime:
188 Xml.writeTextElement(
"date", Data.toDateTime().toString(
Qt::ISODate));
190 case QMetaType::Bool:
192 bool val = Data.toBool();
193 Xml.writeEmptyElement(val ?
"true" :
"false");
197 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Unknown type.");
205 Xml.writeStartElement(
"dict");
206 QVariantMap map = Data.toMap();
207 for (
auto it = map.cbegin(); it != map.cend(); ++it)
209 Xml.writeStartElement(
"key");
210 Xml.writeCharacters(it.key());
211 Xml.writeEndElement();
212 ToXML(it.value(), Xml);
214 Xml.writeEndElement();
219 Xml.writeStartElement(
"array");
220 auto list = Data.value<QSequentialIterable>();
221 for (
const auto & item : std::as_const(list))
223 Xml.writeEndElement();
232 auto size = Data.size();
236 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Binary: size %1, startswith '%2'")
237 .arg(size).arg(Data.left(8).data()));
242 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unrecognised start sequence. Corrupt?");
246 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Parsing binary plist (%1 bytes)").arg(size));
248 m_data =
reinterpret_cast<uint8_t*
>(
const_cast<char*
>(Data.data()));
257 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
258 QString(
"numObjs: %1 parmSize: %2 offsetSize: %3 rootObj: %4"
265 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Error parsing binary plist. Corrupt?");
271 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Parse complete.");
280 quint16
type = (*data) & 0xf0;
281 uint64_t size = (*data) & 0x0f;
313 if (Size == 1)
return static_cast<uint64_t
>(*Data);
314 if (Size == 2)
return qFromBigEndian<quint16>(Data);
315 if (Size == 4)
return qFromBigEndian<quint32>(Data);
316 if (Size == 8)
return qFromBigEndian<quint64>(Data);
319#if (Q_BYTE_ORDER == Q_BIG_ENDIAN)
320 return static_cast<uint64_t
>(((*Data) << 16) + (*(Data + 1) << 8) + (*(Data + 2)));
322 return static_cast<uint64_t
>((*Data) + (*(Data + 1) << 8) + ((*(Data + 2)) << 16));
336 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"GetBinaryObject num %1, offsize %2 offset %3")
348 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Dict: Size %1").arg(count));
353 for (uint64_t i = 0; i < count; i++, Data +=
m_parmSize)
359 if (!key.canConvert<QString>())
361 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Invalid dictionary key type.");
364 result.insert(key.toString(), val);
371 QList<QVariant> result;
376 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Array: Size %1").arg(count));
380 for (uint64_t i = 0; i < count; i++, Data +=
m_parmSize)
384 result.push_back(val);
393 return {
static_cast<quint64
>(result)};
395 uint64_t size = 1 << ((**Data) & 0x0f);
400 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"UInt: %1").arg(result));
401 return {
static_cast<quint64
>(result)};
414 result = QString::fromLatin1(
reinterpret_cast<const char*
>(Data),
static_cast<int>(count));
415 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"ASCII String: %1").arg(result));
429 count = 1ULL << count;
430 if (count ==
sizeof(
float))
432 result = convert_float<float>(Data);
434 else if (count ==
sizeof(
double))
436 result = convert_float<double>(Data);
439 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Real: %1").arg(result, 0,
'f', 6));
453 auto sec =
static_cast<uint64_t
>(convert_float<double>(Data));
454#if QT_VERSION < QT_VERSION_CHECK(6,5,0)
458 QTimeZone(QTimeZone::UTC));
461 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Date: %1").arg(result.toString(
Qt::ISODate)));
475 result = QByteArray(
reinterpret_cast<const char*
>(Data),
static_cast<int>(count));
476 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Data: Size %1 (count %2)")
477 .arg(result.size()).arg(count));
493 for (uint64_t i = 0; i < count; i++, Data += 2)
495 auto twobyte = qFromBigEndian<quint16>(Data);
496 tmp.append(
static_cast<char>(twobyte & 0xff));
497 tmp.append(
static_cast<char>((twobyte >> 8) & 0xff));
499 result = QString::fromUtf16(
reinterpret_cast<const char16_t*
>(
tmp.data()),
static_cast<int>(count));
500 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Unicode: %1").arg(result));
506 uint64_t count = (**Data) & 0x0f;
511 if (!newcount.canConvert<uint64_t>())
513 count = newcount.toULongLong();
A device containing images (ie. USB stick, CD, storage group etc)
QVariant GetValue(const QString &Key)
QVariantMap ParseBinaryDict(uint8_t *Data)
QList< QVariant > ParseBinaryArray(uint8_t *Data)
static QVariant ParseBinaryUnicode(uint8_t *Data)
QVariant ParseBinaryNode(uint64_t Num)
void ParseBinaryPList(const QByteArray &Data)
static QVariant ParseBinaryDate(uint8_t *Data)
static uint64_t GetBinaryUInt(uint8_t *Data, uint64_t Size)
static QVariant ParseBinaryData(uint8_t *Data)
static QVariant ParseBinaryString(uint8_t *Data)
uint8_t * GetBinaryObject(uint64_t Num)
static uint64_t GetBinaryCount(uint8_t **Data)
void ArrayToXML(const QVariant &Data, QXmlStreamWriter &Xml)
void DictToXML(const QVariant &Data, QXmlStreamWriter &Xml)
bool ToXML(QIODevice *Device)
MythBinaryPList(const QByteArray &Data)
static QVariant ParseBinaryReal(uint8_t *Data)
static QVariant ParseBinaryUInt(uint8_t **Data)
static constexpr ssize_t MIN_SIZE
static constexpr uint8_t TRAILER_ROOTOBJ_INDEX
static T convert_float(const uint8_t *p)
static constexpr ssize_t MAGIC_SIZE
static constexpr uint8_t TRAILER_PARMSIZE_INDEX
static const QByteArray MAGIC
static constexpr ssize_t VERSION_SIZE
static constexpr uint8_t TRAILER_OFFSIZE_INDEX
static constexpr uint8_t TRAILER_OFFTAB_INDEX
static constexpr ssize_t TRAILER_SIZE
static const QByteArray VERSION
static constexpr uint64_t CORE_DATA_EPOCH
static constexpr uint8_t TRAILER_NUMOBJ_INDEX
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
MBASE_PUBLIC QDateTime fromSecsSinceEpoch(int64_t seconds)
This function takes the number of seconds since the start of the epoch and returns a QDateTime with t...