23 #include <QTextStream> 32 #define MAGIC QByteArray("bplist") 33 #define VERSION QByteArray("00") 35 #define VERSION_SIZE 2 36 #define TRAILER_SIZE 26 37 #define MIN_SIZE (MAGIC_SIZE + VERSION_SIZE + TRAILER_SIZE) 38 #define TRAILER_OFFSIZE_INDEX 0 39 #define TRAILER_PARMSIZE_INDEX 1 40 #define TRAILER_NUMOBJ_INDEX 2 41 #define TRAILER_ROOTOBJ_INDEX 10 42 #define TRAILER_OFFTAB_INDEX 18 47 #if Q_BYTE_ORDER == Q_BIG_ENDIAN && !defined (__VFP_FP__) 50 for (quint8 i = 0; i < (s / 2); i++)
53 quint8 j = ((s - 1) + 0) - i;
69 m_offsetTable(nullptr),
74 m_codec(QTextCodec::codecForName(
"UTF-16BE"))
76 ParseBinaryPList(Data);
82 if (m_result.type() != QVariant::Map)
85 QVariantMap map = m_result.toMap();
86 QMapIterator<QString,QVariant> it(map);
101 buf.open(QBuffer::WriteOnly);
102 if (!this->
ToXML(&buf))
103 return QStringLiteral(
"");
104 return QString::fromUtf8(res.data());
110 QXmlStreamWriter XML(Device);
111 XML.setAutoFormatting(
true);
112 XML.setAutoFormattingIndent(4);
113 XML.writeStartDocument();
114 XML.writeDTD(QStringLiteral(
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"));
115 XML.writeStartElement(QStringLiteral(
"plist"));
116 XML.writeAttribute(QStringLiteral(
"version"), QStringLiteral(
"1.0"));
117 bool success =
ToXML(m_result, XML);
118 XML.writeEndElement();
119 XML.writeEndDocument();
121 LOG(VB_GENERAL, LOG_WARNING, QStringLiteral(
"Invalid result."));
128 switch (static_cast<QMetaType::Type>(Data.type()))
130 case QMetaType::QVariantMap:
131 DictToXML(Data, XML);
133 case QMetaType::QVariantList:
134 ArrayToXML(Data, XML);
137 case QMetaType::Short:
138 case QMetaType::Long:
139 case QMetaType::LongLong:
140 case QMetaType::Float:
141 case QMetaType::Double:
142 XML.writeTextElement(QStringLiteral(
"real"), QStringLiteral(
"%1").arg(Data.toDouble(), 0,
'f', 6));
144 case QMetaType::QUuid:
145 XML.writeTextElement(QStringLiteral(
"uid"), Data.toByteArray().toHex().data());
147 case QMetaType::QByteArray:
148 XML.writeTextElement(QStringLiteral(
"data"), Data.toByteArray().toBase64().data());
150 case QMetaType::UInt:
151 case QMetaType::UShort:
152 case QMetaType::ULong:
153 case QMetaType::ULongLong:
154 XML.writeTextElement(QStringLiteral(
"integer"), QStringLiteral(
"%1").arg(Data.toULongLong()));
156 case QMetaType::QString: XML.writeTextElement(QStringLiteral(
"string"), Data.toString());
158 case QMetaType::QDateTime:
159 XML.writeTextElement(QStringLiteral(
"date"), Data.toDateTime().toString(Qt::ISODate));
161 case QMetaType::Bool:
163 bool val = Data.toBool();
164 XML.writeEmptyElement(val ? QStringLiteral(
"true") : QStringLiteral(
"false"));
167 case QMetaType::Char:
168 XML.writeEmptyElement(QStringLiteral(
"fill"));
171 LOG(VB_GENERAL, LOG_WARNING, QStringLiteral(
"Unknown type."));
178 void TorcPList::DictToXML(
const QVariant &Data, QXmlStreamWriter &XML)
180 XML.writeStartElement(QStringLiteral(
"dict"));
182 QVariantMap map = Data.toMap();
183 QMapIterator<QString,QVariant> it(map);
187 XML.writeTextElement(QStringLiteral(
"key"), it.key());
188 ToXML(it.value(), XML);
191 XML.writeEndElement();
195 void TorcPList::ArrayToXML(
const QVariant &Data, QXmlStreamWriter &XML)
197 XML.writeStartElement(QStringLiteral(
"array"));
199 QList<QVariant> list = Data.toList();
200 foreach (
const QVariant &item, list)
203 XML.writeEndElement();
207 void TorcPList::ParseBinaryPList(
const QByteArray &Data)
210 m_result = QVariant();
213 quint32 size = Data.size();
217 LOG(VB_GENERAL, LOG_DEBUG, QStringLiteral(
"Binary: size %1, startswith '%2'")
218 .arg(size).arg(Data.left(8).data()));
221 if ((Data.left(6) !=
MAGIC) ||
224 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Unrecognised start sequence. Corrupt?"));
228 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Parsing binary plist (%1 bytes)")
231 m_data = (quint8*)Data.data();
238 m_offsetTable = m_data + offset_tindex;
240 LOG(VB_GENERAL, LOG_DEBUG,
241 QStringLiteral(
"numObjs: %1 parmSize: %2 offsetSize: %3 rootObj: %4 offsetindex: %5")
242 .arg(m_numObjs).arg(m_parmSize).arg(m_offsetSize).arg(m_rootObj).arg(offset_tindex));
245 if (!m_numObjs || !m_parmSize || !m_offsetSize)
247 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Error parsing binary plist. Corrupt?"));
252 m_result = ParseBinaryNode(m_rootObj);
254 LOG(VB_GENERAL, LOG_INFO, QStringLiteral(
"Parse complete."));
257 QVariant TorcPList::ParseBinaryNode(quint64 Num)
259 quint8* data = GetBinaryObject(Num);
293 quint64 TorcPList::GetBinaryUInt(quint8 *Data, quint64 Size)
295 if (Size == 1)
return (quint64)(*(Data));
296 if (Size == 2)
return (quint64)(qToBigEndian(*((quint16*)Data)));
297 if (Size == 4)
return (quint64)(qToBigEndian(*((quint32*)Data)));
298 if (Size == 8)
return (quint64)(qToBigEndian(*((quint64*)Data)));
302 #if Q_BYTE_ORDER == Q_BIG_ENDIAN 303 return (quint64)(((*Data) << 16) + (*(Data + 1) << 8) + (*(Data + 2)));
305 return (quint64)((*Data) + (*(Data + 1) << 8) + ((*(Data + 2)) << 16));
312 quint8* TorcPList::GetBinaryObject(quint64 Num)
317 quint8* p = m_offsetTable + (Num * m_offsetSize);
318 quint64 offset = GetBinaryUInt(p, m_offsetSize);
319 LOG(VB_GENERAL, LOG_DEBUG, QStringLiteral(
"GetBinaryObject Num %1, offsize %2 offset %3")
320 .arg(Num).arg(m_offsetSize).arg(offset));
322 return m_data + offset;
325 QVariantMap TorcPList::ParseBinaryDict(quint8 *Data)
331 quint64 count = GetBinaryCount(&Data);
333 LOG(VB_GENERAL, LOG_DEBUG, QStringLiteral(
"Dict: Size %1").arg(count));
338 quint64 off = m_parmSize * count;
339 for (quint64 i = 0; i < count; i++, Data += m_parmSize)
341 quint64 keyobj = GetBinaryUInt(Data, m_parmSize);
342 quint64 valobj = GetBinaryUInt(Data + off, m_parmSize);
343 QVariant key = ParseBinaryNode(keyobj);
344 QVariant val = ParseBinaryNode(valobj);
345 if (!key.canConvert<QString>())
347 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Invalid dictionary key type '%1' (key %2)")
348 .arg(key.type()).arg(keyobj));
352 result.insertMulti(key.toString(), val);
358 QList<QVariant> TorcPList::ParseBinaryArray(quint8 *Data)
360 QList<QVariant> result;
364 quint64 count = GetBinaryCount(&Data);
366 LOG(VB_GENERAL, LOG_DEBUG, QStringLiteral(
"Array: Size %1").arg(count));
371 result.reserve(count);
372 for (quint64 i = 0; i < count; i++, Data += m_parmSize)
374 quint64 obj = GetBinaryUInt(Data, m_parmSize);
375 QVariant val = ParseBinaryNode(obj);
376 result.push_back(val);
381 QVariant TorcPList::ParseBinaryUInt(quint8 **Data)
385 return QVariant(result);
389 result = GetBinaryUInt(*Data, size);
392 LOG(VB_GENERAL, LOG_DEBUG, QStringLiteral(
"UInt: %1").arg(result));
393 return QVariant(result);
396 QVariant TorcPList::ParseBinaryUID(quint8 *Data)
405 quint64 uid = GetBinaryUInt(Data, count);
407 ushort b1 = (uid & 0xff00000000000000) >> 56;
408 ushort b2 = (uid & 0x00ff000000000000) >> 48;
409 ushort b3 = (uid & 0x0000ff0000000000) >> 40;
410 ushort b4 = (uid & 0x000000ff00000000) >> 32;
411 ushort b5 = (uid & 0x00000000ff000000) >> 24;
412 ushort b6 = (uid & 0x0000000000ff0000) >> 16;
413 ushort b7 = (uid & 0x000000000000ff00) >> 8;
414 ushort b8 = (uid & 0x00000000000000ff) >> 0;
415 return QVariant(QUuid(0, 0, 0, b1, b2, b3, b4, b5, b6, b7, b8));
418 QVariant TorcPList::ParseBinaryString(quint8 *Data)
424 quint64 count = GetBinaryCount(&Data);
428 result = QString::fromLatin1((
const char*)Data, count);
429 LOG(VB_GENERAL, LOG_DEBUG, QStringLiteral(
"ASCII String: %1").arg(result));
430 return QVariant(result);
433 QVariant TorcPList::ParseBinaryReal(quint8 *Data)
439 quint64 count = GetBinaryCount(&Data);
443 count = (quint64)((quint64)1 << count);
444 if (count ==
sizeof(
float))
447 result = (double)(*((
float*)Data));
449 else if (count ==
sizeof(
double))
452 result = *((
double*)Data);
455 LOG(VB_GENERAL, LOG_DEBUG, QStringLiteral(
"Real: %1").arg(result, 0,
'f', 6));
456 return QVariant(result);
459 QVariant TorcPList::ParseBinaryDate(quint8 *Data)
465 quint64 count = GetBinaryCount(&Data);
470 result = QDateTime::fromTime_t((quint64)(*((
double*)Data)));
471 LOG(VB_GENERAL, LOG_DEBUG, QStringLiteral(
"Date: %1").arg(result.toString(Qt::ISODate)));
472 return QVariant(result);
475 QVariant TorcPList::ParseBinaryData(quint8 *Data)
481 quint64 count = GetBinaryCount(&Data);
485 result = QByteArray((
const char*)Data, count);
486 LOG(VB_GENERAL, LOG_DEBUG, QStringLiteral(
"Data: Size %1 (count %2)")
487 .arg(result.size()).arg(count));
488 return QVariant(result);
491 QVariant TorcPList::ParseBinaryUnicode(quint8 *Data)
497 quint64 count = GetBinaryCount(&Data);
501 return QVariant(m_codec->toUnicode((
char*)Data, count << 1));
504 quint64 TorcPList::GetBinaryCount(quint8 **Data)
510 QVariant newcount = ParseBinaryUInt(Data);
511 if (!newcount.canConvert<quint64>())
513 count = newcount.toULongLong();
bool ToXML(QIODevice *Device)
brief Convert the parsed plist to XML.
#define TRAILER_PARMSIZE_INDEX
QString ToString(void)
brief Return the complete plist in formatted XML.
#define TRAILER_NUMOBJ_INDEX
#define TRAILER_OFFTAB_INDEX
TorcPList(const QByteArray &Data)
#define TRAILER_OFFSIZE_INDEX
#define LOG(_MASK_, _LEVEL_, _STRING_)
#define TRAILER_ROOTOBJ_INDEX
QVariant GetValue(const QString &Key)
brief Return the value for the given Key.
static void convert_float(quint8 *p, quint8 s)