41 #include <QSequentialIterable>
42 #include <QTextStream>
49 #define LOC QString("PList: ")
51 static const QByteArray
MAGIC {
"bplist" };
53 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
95 #if (Q_BYTE_ORDER == Q_BIG_ENDIAN) && !defined (__VFP_FP__)
96 return *(
reinterpret_cast<const T *
>(
p));
98 static std::array<uint8_t,
sizeof(T)> temp;
99 for (
size_t i = 0; i < (
sizeof(T) / 2); i++)
101 size_t j =
sizeof(T) - 1 - i;
105 return *(
reinterpret_cast<const T *
>(temp.data()));
116 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
117 auto type =
static_cast<QMetaType::Type
>(
m_result.type());
122 if (
type != QMetaType::QVariantMap)
126 for (
auto it = map.cbegin(); it != map.cend(); ++it)
136 buf.open(QBuffer::WriteOnly);
144 QXmlStreamWriter xml(
Device);
145 xml.setAutoFormatting(
true);
146 xml.setAutoFormattingIndent(4);
147 xml.writeStartDocument();
148 xml.writeDTD(R
"(<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">)");
149 xml.writeStartElement("plist");
150 xml.writeAttribute(
"version",
"1.0");
152 xml.writeEndElement();
153 xml.writeEndDocument();
155 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Invalid result.");
161 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
162 auto type =
static_cast<QMetaType::Type
>(Data.type());
164 auto type = Data.typeId();
168 case QMetaType::QVariantMap:
171 case QMetaType::QVariantList:
174 case QMetaType::Double:
175 Xml.writeTextElement(
"real", QString(
"%1").arg(Data.toDouble(), 0,
'f', 6));
177 case QMetaType::QByteArray:
178 Xml.writeTextElement(
"data", Data.toByteArray().toBase64().data());
180 case QMetaType::ULongLong:
181 Xml.writeTextElement(
"integer", QString(
"%1").arg(Data.toULongLong()));
183 case QMetaType::QString:
184 Xml.writeTextElement(
"string", Data.toString());
186 case QMetaType::QDateTime:
187 Xml.writeTextElement(
"date", Data.toDateTime().toString(
Qt::ISODate));
189 case QMetaType::Bool:
191 bool val = Data.toBool();
192 Xml.writeEmptyElement(val ?
"true" :
"false");
196 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Unknown type.");
204 Xml.writeStartElement(
"dict");
205 QVariantMap map = Data.toMap();
206 for (
auto it = map.cbegin(); it != map.cend(); ++it)
208 Xml.writeStartElement(
"key");
209 Xml.writeCharacters(it.key());
210 Xml.writeEndElement();
211 ToXML(it.value(), Xml);
213 Xml.writeEndElement();
218 Xml.writeStartElement(
"array");
219 auto list = Data.value<QSequentialIterable>();
220 for (
const auto & item : qAsConst(list))
222 Xml.writeEndElement();
231 auto size = Data.size();
235 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Binary: size %1, startswith '%2'")
236 .arg(size).arg(Data.left(8).data()));
241 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unrecognised start sequence. Corrupt?");
245 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Parsing binary plist (%1 bytes)").arg(size));
247 m_data =
reinterpret_cast<uint8_t*
>(
const_cast<char*
>(Data.data()));
256 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
257 QString(
"numObjs: %1 parmSize: %2 offsetSize: %3 rootObj: %4"
264 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Error parsing binary plist. Corrupt?");
270 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Parse complete.");
279 quint16
type = (*data) & 0xf0;
280 uint64_t size = (*data) & 0x0f;
312 if (Size == 1)
return static_cast<uint64_t
>(*Data);
313 if (Size == 2)
return qFromBigEndian<quint16>(Data);
314 if (Size == 4)
return qFromBigEndian<quint32>(Data);
315 if (Size == 8)
return qFromBigEndian<quint64>(Data);
318 #if (Q_BYTE_ORDER == Q_BIG_ENDIAN)
319 return static_cast<uint64_t
>(((*Data) << 16) + (*(Data + 1) << 8) + (*(Data + 2)));
321 return static_cast<uint64_t
>((*Data) + (*(Data + 1) << 8) + ((*(Data + 2)) << 16));
335 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"GetBinaryObject num %1, offsize %2 offset %3")
347 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Dict: Size %1").arg(count));
352 for (uint64_t i = 0; i < count; i++, Data +=
m_parmSize)
358 if (!key.canConvert<QString>())
360 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Invalid dictionary key type.");
363 result.insert(key.toString(), val);
370 QList<QVariant> result;
375 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Array: Size %1").arg(count));
379 for (uint64_t i = 0; i < count; i++, Data +=
m_parmSize)
383 result.push_back(val);
392 return {
static_cast<quint64
>(result)};
394 uint64_t size = 1 << ((**Data) & 0x0f);
399 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"UInt: %1").arg(result));
400 return {
static_cast<quint64
>(result)};
413 result = QString::fromLatin1(
reinterpret_cast<const char*
>(Data),
static_cast<int>(count));
414 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"ASCII String: %1").arg(result));
428 count = 1ULL << count;
429 if (count ==
sizeof(
float))
431 result = convert_float<float>(Data);
433 else if (count ==
sizeof(
double))
435 result = convert_float<double>(Data);
438 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Real: %1").arg(result, 0,
'f', 6));
452 auto sec =
static_cast<uint64_t
>(convert_float<double>(Data));
455 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Date: %1").arg(result.toString(
Qt::ISODate)));
469 result = QByteArray(
reinterpret_cast<const char*
>(Data),
static_cast<int>(count));
470 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Data: Size %1 (count %2)")
471 .arg(result.size()).arg(count));
487 for (uint64_t i = 0; i < count; i++, Data += 2)
489 auto twobyte = qFromBigEndian<quint16>(Data);
490 tmp.append(
static_cast<char>(twobyte & 0xff));
491 tmp.append(
static_cast<char>((twobyte >> 8) & 0xff));
493 result = QString::fromUtf16(
reinterpret_cast<const char16_t*
>(
tmp.data()),
static_cast<int>(count));
494 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Unicode: %1").arg(result));
500 uint64_t count = (**Data) & 0x0f;
505 if (!newcount.canConvert<uint64_t>())
507 count = newcount.toULongLong();