34 #include <QTextStream>
44 #define LOC QString("PList: ")
46 #define MAGIC QByteArray("bplist")
47 #define VERSION QByteArray("00")
49 #define VERSION_SIZE 2
50 #define TRAILER_SIZE 26
51 #define MIN_SIZE (MAGIC_SIZE + VERSION_SIZE + TRAILER_SIZE)
52 #define TRAILER_OFFSIZE_INDEX 0
53 #define TRAILER_PARMSIZE_INDEX 1
54 #define TRAILER_NUMOBJ_INDEX 2
55 #define TRAILER_ROOTOBJ_INDEX 10
56 #define TRAILER_OFFTAB_INDEX 18
78 #if defined(HAVE_BIGENDIAN) && !defined (__VFP_FP__)
81 for (uint8_t i = 0; i < (s / 2); i++)
84 uint8_t j = ((s - 1) + 0) - i;
93 #if defined(HAVE_BIGENDIAN)
96 for (uint8_t i = 0; i < (s / 2); i++)
99 uint8_t j = ((s - 1) + 0) - i;
114 if (
m_result.type() != QVariant::Map)
118 for (
auto it = map.cbegin(); it != map.cend(); ++it)
128 buf.open(QBuffer::WriteOnly);
131 return QString(res.data());
136 QXmlStreamWriter xml(
Device);
137 xml.setAutoFormatting(
true);
138 xml.setAutoFormattingIndent(4);
139 xml.writeStartDocument();
140 xml.writeDTD(R
"(<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">)");
141 xml.writeStartElement("plist");
142 xml.writeAttribute(
"version",
"1.0");
144 xml.writeEndElement();
145 xml.writeEndDocument();
147 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Invalid result.");
161 case QVariant::Double:
162 Xml.writeTextElement(
"real", QString(
"%1").
arg(Data.toDouble(), 0,
'f', 6));
164 case QVariant::ByteArray:
165 Xml.writeTextElement(
"data", Data.toByteArray().toBase64().data());
167 case QVariant::ULongLong:
168 Xml.writeTextElement(
"integer", QString(
"%1").
arg(Data.toULongLong()));
170 case QVariant::String:
171 Xml.writeTextElement(
"string", Data.toString());
173 case QVariant::DateTime:
174 Xml.writeTextElement(
"date", Data.toDateTime().toString(
Qt::ISODate));
178 bool val = Data.toBool();
179 Xml.writeEmptyElement(val ?
"true" :
"false");
183 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Unknown type.");
191 Xml.writeStartElement(
"dict");
192 QVariantMap map = Data.toMap();
193 for (
auto it = map.cbegin(); it != map.cend(); ++it)
195 Xml.writeStartElement(
"key");
196 Xml.writeCharacters(it.key());
197 Xml.writeEndElement();
198 ToXML(it.value(), Xml);
200 Xml.writeEndElement();
205 Xml.writeStartElement(
"array");
206 auto list = Data.value<QSequentialIterable>();
207 for (
const auto & item : qAsConst(list))
209 Xml.writeEndElement();
218 auto size =
static_cast<quint32
>(Data.size());
222 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Binary: size %1, startswith '%2'")
223 .
arg(size).
arg(Data.left(8).data()));
228 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Unrecognised start sequence. Corrupt?");
232 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Parsing binary plist (%1 bytes)").
arg(size));
234 m_data =
reinterpret_cast<uint8_t*
>(
const_cast<char*
>(Data.data()));
243 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
244 QString(
"numObjs: %1 parmSize: %2 offsetSize: %3 rootObj: %4"
251 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Error parsing binary plist. Corrupt?");
257 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Parse complete.");
266 quint16
type = (*data) & 0xf0;
267 uint64_t size = (*data) & 0x0f;
287 default:
return QVariant();
299 if (Size == 1)
return static_cast<uint64_t
>(*Data);
300 if (Size == 2)
return static_cast<uint64_t
>(*(
reinterpret_cast<quint16*
>(
convert_int(Data, 2))));
301 if (Size == 4)
return static_cast<uint64_t
>(*(
reinterpret_cast<quint32*
>(
convert_int(Data, 4))));
302 if (Size == 8)
return (*(
reinterpret_cast<uint64_t*
>(
convert_int(Data, 8))));
305 #if defined(HAVE_BIGENDIAN)
306 return static_cast<uint64_t
>(((*Data) << 16) + (*(Data + 1) << 8) + (*(Data + 2)));
308 return static_cast<uint64_t
>((*Data) + (*(Data + 1) << 8) + ((*(Data + 2)) << 16));
322 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"GetBinaryObject num %1, offsize %2 offset %3")
334 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Dict: Size %1").
arg(count));
339 for (uint64_t i = 0; i < count; i++, Data +=
m_parmSize)
345 if (!key.canConvert<QString>())
347 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Invalid dictionary key type.");
350 result.insert(key.toString(), val);
357 QList<QVariant> result;
362 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Array: Size %1").
arg(count));
366 for (uint64_t i = 0; i < count; i++, Data +=
m_parmSize)
370 result.push_back(val);
379 return QVariant(
static_cast<quint64
>(result));
381 uint64_t size = 1 << ((**Data) & 0x0f);
386 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"UInt: %1").
arg(result));
387 return QVariant(
static_cast<quint64
>(result));
400 result = QString::fromLatin1(
reinterpret_cast<const char*
>(Data),
static_cast<int>(count));
401 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"ASCII String: %1").
arg(result));
402 return QVariant(result);
415 count = 1ULL << count;
416 if (count ==
sizeof(
float))
420 std::copy(Data, Data +
sizeof(
float),
reinterpret_cast<uint8_t*
>(&temp));
421 result =
static_cast<double>(temp);
423 else if (count ==
sizeof(
double))
426 std::copy(Data, Data +
sizeof(
double),
reinterpret_cast<uint8_t*
>(&result));
429 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Real: %1").
arg(result, 0,
'f', 6));
430 return QVariant(result);
444 auto temp =
static_cast<double>(NAN);
445 std::copy(Data, Data +
sizeof(
double),
reinterpret_cast<uint8_t*
>(&temp));
446 auto msec =
static_cast<uint64_t
>(temp * 1000.0);
447 result = QDateTime::fromMSecsSinceEpoch(
static_cast<qint64
>(msec), Qt::UTC);
449 return QVariant(result);
462 result = QByteArray(
reinterpret_cast<const char*
>(Data),
static_cast<int>(count));
463 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Data: Size %1 (count %2)")
464 .
arg(result.size()).arg(count));
465 return QVariant(result);
480 for (uint64_t i = 0; i < count; i++, Data += 2)
482 quint16 twobyte = *(
reinterpret_cast<quint16*
>(
convert_int(Data, 2)));
483 tmp.append(
static_cast<char>(twobyte & 0xff));
484 tmp.append(
static_cast<char>((twobyte >> 8) & 0xff));
486 result = QString::fromUtf16(
reinterpret_cast<const quint16*
>(
tmp.data()),
static_cast<int>(count));
487 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Unicode: %1").
arg(result));
488 return QVariant(result);
493 uint64_t count = (**Data) & 0x0f;
498 if (!newcount.canConvert<uint64_t>())
500 count = newcount.toULongLong();