6#include "plistreader_p.h"
7#include "plistdata_p.h"
12#include <QStringDecoder>
19PListArray::PListArray() =
default;
20PListArray::PListArray(std::string_view data,
const PListReader *reader) : m_data(data), m_reader(reader) {}
21PListArray::~PListArray() =
default;
23uint64_t PListArray::size()
const
25 return m_reader ? (m_data.size() / m_reader->trailer()->objectRefSize) : 0;
28uint64_t PListArray::value(uint64_t index)
const
30 return m_reader ? m_reader->readObjectRef(m_data, index) : 0;
33PListObjectType PListArray::objectType(uint64_t index)
const
35 return m_reader ? m_reader->objectType(value(index)) : PListObjectType::Unused;
37PListObjectType PListArray::objectType(PListUid uid)
const {
return objectType(uid.value); }
39QVariant PListArray::object(uint64_t index)
const
41 return m_reader ? m_reader->object(value(index)) :
QVariant();
43QVariant PListArray::object(PListUid uid)
const {
return object(uid.value); }
46PListDict::PListDict() =
default;
47PListDict::PListDict(std::string_view data,
const PListReader *reader) : m_data(data), m_reader(reader) {}
48PListDict::~PListDict() =
default;
50uint64_t PListDict::size()
const
52 return m_reader ? (m_data.size() / (m_reader->trailer()->objectRefSize * 2)) : 0;
55uint64_t PListDict::key(uint64_t index)
const
57 return m_reader ? m_reader->readObjectRef(m_data, index) : 0;
60uint64_t PListDict::value(uint64_t index)
const
62 return m_reader ? m_reader->readObjectRef(m_data, size() + index) : 0;
70 for (uint64_t i = 0; i < size(); ++i) {
71 const auto n = m_reader->object(key(i)).toString();
81 const auto v = value(keyName);
82 return v && m_reader ? m_reader->object(*v) :
QVariant();
85PListReader::PListReader(
const QByteArray &data)
87 if (!maybePList(data)) {
94PListReader::~PListReader() =
default;
96bool PListReader::isValid()
const
101uint64_t PListReader::objectCount()
const
103 return trailer()->numObjects;
106uint64_t PListReader::rootObjectIndex()
const
108 return trailer()->rootObjectIndex;
111uint64_t PListReader::objectOffset(uint64_t index)
const
113 const auto t = trailer();
114 if (!t || index >= t->numObjects) {
119 for (uint64_t i = 0; i < t->offsetIntSize; ++i) {
121 offset |= (uint8_t)m_data.at(t->offsetTableOffset + index * t->offsetIntSize + i);
129 PListObjectType type;
131static constexpr const marker_map[] = {
132 { 0b0000'0000, 0b1111'1111, PListObjectType::Null },
133 { 0b0000'1000, 0b1111'1110, PListObjectType::Bool },
134 { 0b0000'1100, 0b1111'1110, PListObjectType::Url },
135 { 0b0000'1110, 0b1111'1111, PListObjectType::Uuid },
136 { 0b0000'1111, 0b1111'1111, PListObjectType::Fill },
137 { 0b0001'0000, 0b1111'1000, PListObjectType::Int },
138 { 0b0010'0000, 0b1111'1000, PListObjectType::Real },
139 { 0b0011'0011, 0b1111'1111, PListObjectType::Date },
140 { 0b0100'0000, PListContainerTypeMask, PListObjectType::Data },
141 { 0b0101'0000, PListContainerTypeMask, PListObjectType::String },
142 { 0b0110'0000, 0b1110'0000, PListObjectType::String },
143 { 0b1000'0000, 0b1111'0000, PListObjectType::Uid },
144 { 0b1010'0000, PListContainerTypeMask, PListObjectType::Array },
145 { 0b1011'0000, PListContainerTypeMask, PListObjectType::Ordset },
146 { 0b1100'0000, PListContainerTypeMask, PListObjectType::Set },
147 { 0b1101'0000, PListContainerTypeMask, PListObjectType::Dict },
150static PListObjectType objectTypeFromMarker(uint8_t b)
152 for (
const auto &m : marker_map) {
153 if ((b & m.mask) == m.marker) {
157 return PListObjectType::Unused;
160PListObjectType PListReader::objectType(uint64_t index)
const
162 const auto offset = objectOffset(index);
163 if (offset >= (uint64_t)m_data.size()) {
164 return PListObjectType::Unused;
167 return objectTypeFromMarker(m_data.at(offset));
170QVariant PListReader::object(uint64_t index)
const
172 auto offset = objectOffset(index);
173 if (offset >= (uint64_t)m_data.size()) {
177 const uint8_t b = m_data.at(offset++);
178 const auto type = objectTypeFromMarker(b);
180 case PListObjectType::Null:
181 case PListObjectType::Fill:
182 case PListObjectType::Unused:
184 case PListObjectType::Bool:
185 return b == PListTrue;
186 case PListObjectType::Int:
188 case PListObjectType::Data:
189 case PListObjectType::String:
191 if ((b & PListContainerTypeMask) == 0b0110'0000) {
192 const auto size = readContainerSize(offset, b) * 2;
193 const auto v = view(offset, size);
198 const auto size = readContainerSize(offset, b);
199 const auto v = view(offset, size);
200 if ((b & PListContainerTypeMask) == 0b0101'0000) {
203 if ((b & PListContainerTypeMask) == 0b0111'0000) {
208 case PListObjectType::Uid:
210 case PListObjectType::Array:
212 const auto size = readContainerSize(offset, b) * trailer()->objectRefSize;
215 case PListObjectType::Dict:
217 const auto size = readContainerSize(offset, b) * trailer()->objectRefSize * 2;
221 case PListObjectType::Real:
222 case PListObjectType::Date:
226 case PListObjectType::Url:
227 case PListObjectType::Uuid:
228 case PListObjectType::Ordset:
229 case PListObjectType::Set:
230 qDebug() <<
"unsupposed plist object type:" << (int)type << (
int)b;
236const PListTrailer* PListReader::trailer()
const
238 return isValid() ?
reinterpret_cast<const PListTrailer*
>(m_data.constData() + m_data.size() -
sizeof(PListTrailer)) :
nullptr;
241uint64_t PListReader::readBigEndianNumber(uint64_t offset,
int size)
const
244 qDebug() <<
"oversized int not supported" << offset << size;
247 if ((uint64_t)m_data.size() <= offset + size) {
248 qDebug() <<
"attempting to read number beyond input data" << offset << size;
253 for (
auto i = 0; i < size; ++i) {
255 v |= (uint8_t)m_data.at(offset + i);
260uint64_t PListReader::readBigEndianInteger(uint64_t& offset)
const
262 assert(offset < (uint64_t)m_data.size());
263 const auto b = m_data.at(offset++);
264 const auto size = 1 << (b & 0b0000'0111);
265 const auto v = readBigEndianNumber(offset, size);
270uint64_t PListReader::readContainerSize(uint64_t &offset, uint8_t marker)
const
272 uint64_t size = (marker & PListContainerSizeMask);
273 if (offset + size >= (uint64_t)m_data.size()) {
274 qDebug() <<
"attempt to read data beyond bounds";
278 if (size == PListContainerSizeMask) {
279 size = readBigEndianInteger(offset);
284std::string_view PListReader::view(uint64_t offset, uint64_t size)
const
286 return offset + size < (uint64_t)m_data.size() ? std::string_view(m_data.constData() + offset, size) : std::string_view();
289uint64_t PListReader::readObjectRef(std::string_view data, uint64_t index)
const
291 if ((index + 1) * trailer()->objectRefSize > data.size()) {
292 qDebug() <<
"object reference read beyond data size";
297 for (
auto i = 0; i < trailer()->objectRefSize; ++i) {
299 ref |= (uint8_t)data[index * trailer()->objectRefSize + i];
304QJsonValue PListReader::unpackKeyedArchive()
const
307 const auto root = object(rootObjectIndex()).value<PListDict>();
310 qDebug() <<
"not NSKeyedArchiver data"
319 return unpackKeyedArchiveRecursive(uid, objects);
322QJsonValue PListReader::unpackKeyedArchiveRecursive(PListUid uid,
const PListArray &objects)
const
324 const auto type = objects.objectType(uid);
325 const auto v = objects.object(uid);
327 case PListObjectType::Dict:
329 const auto obj = v.value<PListDict>();
330 const auto classObj =
335 const auto classNames =
337 .value<PListArray>();
338 for (uint64_t j = 0; j < classNames.size(); ++j) {
339 const auto className = classNames.object(j).toString();
343 .
value<PListArray>();
345 .value<PListArray>();
346 for (uint64_t i = 0; i < std::min(keys.size(), vals.size());
349 objects.object(keys.object(i).value<PListUid>())
351 const auto valUid = vals.object(i).value<PListUid>();
353 unpackKeyedArchiveRecursive(valUid, objects));
360 .
value<PListArray>();
361 for (uint64_t i = 0; i < elems.size(); ++i) {
362 const auto elemUid = elems.object(i).value<PListUid>();
364 unpackKeyedArchiveRecursive(elemUid, objects));
369 qDebug() <<
"unhandled dict object" << uid.value;
372 case PListObjectType::Int:
374 case PListObjectType::String:
377 qDebug() <<
"unhandled class" << (int)type;
384bool PListReader::maybePList(
const QByteArray &data)
386 if ((std::size_t)data.
size() <=
sizeof(PListHeader) +
sizeof(PListReader)) {
390 const auto header =
reinterpret_cast<const PListHeader*
>(data.
constData());
391 if (std::memcmp(header->magic, PListMagic, PListMagicSize) != 0) {
394 qDebug() <<
"found plist version:" << header->version[0] << header->version[1];
397 const auto t =
reinterpret_cast<const PListTrailer*
>(data.
constData() + data.
size() -
sizeof(PListTrailer));
398 if (t->offsetIntSize == 0 || t->offsetIntSize > 8 || t->objectRefSize == 0 || t->objectRefSize > 8) {
402 return t->offsetTableOffset + t->numObjects * t->offsetIntSize < (uint64_t)data.
size();
char * toString(const EngineQuery &query)
Classes for reservation/travel data models, data extraction and data augmentation.
bool isValid(QStringView ifopt)
const char * constData() const const
bool isEmpty() const const
qsizetype size() const const
void push_back(const QJsonValue &value)
iterator insert(QLatin1StringView key, const QJsonValue &value)
QJsonValue value(QLatin1StringView key) const const
bool isEmpty() const const
QString fromLatin1(QByteArrayView str)
QString fromUtf8(QByteArrayView str)
QVariant fromValue(T &&value)