1 Star 0 Fork 0

张旋璇 / QtOpenCoreConfig

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
Plist.cpp 35.62 KB
一键复制 编辑 原始数据 按行查看 历史
ic005k 提交于 2021-03-25 09:58 . Add files via upload
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209
//
// PlistCpp Property List (plist) serialization and parsing library.
//
// https://github.com/animetrics/PlistCpp
//
// Copyright (c) 2011 Animetrics Inc. (marc@animetrics.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "Plist.hpp"
#include <boost/locale/encoding_utf.hpp>
#include <list>
#include <sstream>
#include "base64.hpp"
#include "pugixml.hpp"
namespace Plist {
struct PlistHelperData
{
public:
// binary helper data
std::vector<int32_t> _offsetTable;
std::vector<unsigned char> _objectTable;
int32_t _offsetByteSize;
int64_t _offsetTableOffset;
int32_t _objRefSize;
int32_t _refCount;
};
void writePlistBinary(
PlistHelperData& d,
const boost::any& message);
void writePlistXML(
pugi::xml_document& doc,
const boost::any& message);
// helper functions
// msvc <= 2005 doesn't have std::vector::data() method
template<typename T>
T* vecData(std::vector<T>& vec)
{
return (vec.size() > 0) ? &vec[0] : 0;
// if(vec.size() > 0)
// return &vec[0];
// else
// throw Error("vecData trying to get pointer to empty std::vector");
}
template<typename T>
const T* vecData(const std::vector<T>& vec)
{
return (vec.size() > 0) ? &vec[0] : 0;
// if(vec.size() > 0)
// return &vec[0];
// else
// throw Error("vecData trying to get pointer to empty std::vector");
}
// xml helper functions
template<typename T>
std::string stringFromValue(const T& value);
template<typename T>
void writeXMLSimpleNode(pugi::xml_node& node, const char* name, const boost::any& obj);
// xml parsing
dictionary_type parseDictionary(pugi::xml_node& node);
array_type parseArray(pugi::xml_node& node);
std::vector<char> base64Decode(const char* data);
void base64Encode(std::string& dataEncoded, const std::vector<char>& data);
Date parseDate(pugi::xml_node& node);
boost::any parse(pugi::xml_node& doc);
// xml writing
void writeXMLArray(pugi::xml_node& node, const array_type& array);
void writeXMLDictionary(pugi::xml_node& node, const dictionary_type& message);
void writeXMLNode(pugi::xml_node& node, const boost::any& obj);
// binary helper functions
template <typename IntegerType>
IntegerType bytesToInt(const unsigned char* bytes, bool littleEndian);
double bytesToDouble(const unsigned char* bytes, bool littleEndian);
std::vector<unsigned char> doubleToBytes(double val, bool littleEndian);
template<typename IntegerType>
std::vector<unsigned char> intToBytes(IntegerType val, bool littleEndian);
std::vector<unsigned char> getRange(const unsigned char* origBytes, int64_t index, int64_t size);
std::vector<unsigned char> getRange(const std::vector<unsigned char>& origBytes, int64_t index, int64_t size);
std::vector<char> getRange(const char* origBytes, int64_t index, int64_t size);
// binary parsing
boost::any parseBinary(const PlistHelperData& d, int objRef);
dictionary_type parseBinaryDictionary(const PlistHelperData& d, int objRef);
array_type parseBinaryArray(const PlistHelperData& d, int objRef);
std::vector<int32_t> getRefsForContainers(const PlistHelperData& d, int objRef);
int64_t parseBinaryInt(const PlistHelperData& d, int headerPosition, int& intByteCount);
double parseBinaryReal(const PlistHelperData& d, int headerPosition);
Date parseBinaryDate(const PlistHelperData& d, int headerPosition);
bool parseBinaryBool(const PlistHelperData& d, int headerPosition);
std::string parseBinaryString(const PlistHelperData& d, int objRef);
std::string parseBinaryUnicode(const PlistHelperData& d, int headerPosition);
data_type parseBinaryByteArray(const PlistHelperData& d, int headerPosition);
std::vector<unsigned char> regulateNullBytes(const std::vector<unsigned char>& origBytes, unsigned int minBytes);
void parseTrailer(PlistHelperData& d, const std::vector<unsigned char>& trailer);
void parseOffsetTable(PlistHelperData& d, const std::vector<unsigned char>& offsetTableBytes);
int32_t getCount(const PlistHelperData& d, int bytePosition, unsigned char headerByte, int& startOffset);
// binary writing
int countAny(const boost::any& object);
int countDictionary(const dictionary_type& dictionary);
int countArray(const array_type& array);
std::vector<unsigned char> writeBinaryDictionary(PlistHelperData& d, const dictionary_type& dictionary);
std::vector<unsigned char> writeBinaryArray(PlistHelperData& d, const array_type& array);
std::vector<unsigned char> writeBinaryByteArray(PlistHelperData& d, const data_type& byteArray);
std::vector<unsigned char> writeBinaryInteger(PlistHelperData& d, int64_t value, bool write);
std::vector<unsigned char> writeBinaryBool(PlistHelperData& d, bool value);
std::vector<unsigned char> writeBinaryDate(PlistHelperData& d, const Date& date);
std::vector<unsigned char> writeBinaryDouble(PlistHelperData& d, double value);
std::vector<unsigned char> writeBinary(PlistHelperData& d, const boost::any& obj);
std::vector<unsigned char> writeBinaryString(PlistHelperData& d, const std::string& value, bool head);
inline bool hostLittleEndian()
{
union { uint32_t x; uint8_t c[4]; } u;
u.x = 0xab0000cd;
return u.c[0] == 0xcd;
}
} // namespace Plist
namespace Plist {
template<typename T>
void writeXMLSimpleNode(pugi::xml_node& node, const char* name, const boost::any& obj)
{
pugi::xml_node newNode;
newNode = node.append_child(name);
newNode.append_child(pugi::node_pcdata).set_value(stringFromValue(boost::any_cast<const T&>(obj)).c_str());
}
void writeXMLNode(pugi::xml_node& node, const boost::any& obj)
{
using namespace std;
const std::type_info &objType = obj.type();
if(objType == typeid(int32_t))
writeXMLSimpleNode<int32_t>(node, "integer", obj);
else if(objType == typeid(int64_t))
writeXMLSimpleNode<int64_t>(node, "integer", obj);
else if(objType == typeid(long))
writeXMLSimpleNode<long>(node, "integer", obj);
else if(objType == typeid(short))
writeXMLSimpleNode<short>(node, "integer", obj);
else if(objType == typeid(dictionary_type))
writeXMLDictionary(node, boost::any_cast<const dictionary_type&>(obj));
else if(objType == typeid(string_type))
writeXMLSimpleNode<string_type>(node, "string", obj);
else if(objType == typeid(array_type))
writeXMLArray(node, boost::any_cast<const array_type&>(obj));
else if(objType == typeid(data_type))
{
string dataEncoded;
base64Encode(dataEncoded, boost::any_cast<const data_type&>(obj));
writeXMLSimpleNode<string>(node, "data", dataEncoded);
}
else if(objType == typeid(double))
writeXMLSimpleNode<double>(node, "real", obj);
else if(objType == typeid(float))
writeXMLSimpleNode<float>(node, "real", obj);
else if(objType == typeid(Date))
writeXMLSimpleNode<string>(node, "date", boost::any_cast<const Date&>(obj).timeAsXMLConvention());
else if(objType == typeid(bool))
{
bool value = boost::any_cast<const bool&>(obj);
node.append_child(value ? "true" : "false");
}
else
throw Error((string("Plist Error: Can't serialize type ") + objType.name()).c_str());
}
void writeXMLArray(
pugi::xml_node& node,
const array_type& array)
{
using namespace std;
pugi::xml_node newNode = node.append_child("array");
for(array_type::const_iterator it = array.begin();
it != array.end();
++it)
writeXMLNode(newNode, *it);
}
void writeXMLDictionary(
pugi::xml_node& node,
const dictionary_type& message)
{
using namespace std;
pugi::xml_node newNode = node.append_child("dict");
for(dictionary_type::const_iterator it = message.begin();
it != message.end();
++it)
{
pugi::xml_node keyNode = newNode.append_child("key");
keyNode.append_child(pugi::node_pcdata).set_value(it->first.c_str());
writeXMLNode(newNode, it->second);
}
}
void writePlistXML(
pugi::xml_document& doc,
const boost::any& message)
// const dictionary_type& message)
{
// declaration node
pugi::xml_node decNode = doc.append_child(pugi::node_declaration);
decNode.append_attribute("version") = "1.0";
decNode.append_attribute("encoding") = "UTF-8";
// doctype node
doc.append_child(pugi::node_doctype).set_value("plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"");
// root node
pugi::xml_node plistNode = doc.append_child("plist");
plistNode.append_attribute("version") = "1.0";
writeXMLNode(plistNode, message);
}
void writePlistBinary(
PlistHelperData& d,
const boost::any& message)
{
using namespace std;
//int totalRefs = countDictionary(message);
int totalRefs = countAny(message) - 1;
d._refCount = totalRefs;
d._objRefSize = regulateNullBytes(intToBytes<int32_t>(d._refCount, hostLittleEndian()), 1).size();
//writeBinaryDictionary(d, message);
writeBinary(d, message);
writeBinaryString(d, "bplist00", false);
d._offsetTableOffset = (int64_t) d._objectTable.size();
d._offsetTable.push_back(d._objectTable.size() - 8);
d._offsetByteSize = regulateNullBytes(intToBytes<int>(d._offsetTable.back(), hostLittleEndian()), 1).size();
vector<unsigned char> offsetBytes;
reverse(d._offsetTable.begin(), d._offsetTable.end());
for(unsigned int i = 0; i < d._offsetTable.size(); ++i)
{
d._offsetTable[i] = d._objectTable.size() - d._offsetTable[i];
vector<unsigned char> buffer = regulateNullBytes(intToBytes<int>(d._offsetTable[i], hostLittleEndian()), d._offsetByteSize);
//reverse(buffer.begin(), buffer.end());
offsetBytes.insert(offsetBytes.end(), buffer.rbegin(), buffer.rend());
}
d._objectTable.insert(d._objectTable.end(), offsetBytes.begin(), offsetBytes.end());
vector<unsigned char> dummy(6, 0);
d._objectTable.insert(d._objectTable.end(), dummy.begin(), dummy.end());
d._objectTable.push_back((unsigned char) (d._offsetByteSize));
d._objectTable.push_back((unsigned char) (d._objRefSize));
vector<unsigned char> temp = intToBytes<int64_t>((int64_t) totalRefs + 1, hostLittleEndian());
d._objectTable.insert(d._objectTable.end(), temp.rbegin(), temp.rend());
temp = intToBytes<int64_t>(0, hostLittleEndian());
d._objectTable.insert(d._objectTable.end(), temp.begin(), temp.end());
temp = intToBytes<int64_t>(d._offsetTableOffset, hostLittleEndian());
d._objectTable.insert(d._objectTable.end(), temp.rbegin(), temp.rend());
}
void writePlistBinary(std::vector<char>& plist, const boost::any& message)
{
PlistHelperData d;
writePlistBinary(d, message);
plist.resize(d._objectTable.size());
std::copy((const char*) vecData(d._objectTable), (const char*) vecData(d._objectTable) + d._objectTable.size(), plist.begin());
}
void writePlistBinary(
std::ostream& stream,
const boost::any& message)
{
PlistHelperData d;
writePlistBinary(d, message);
stream.write((const char*) vecData(d._objectTable), d._objectTable.size());
}
void writePlistBinary(
const char* filename,
const boost::any& message)
{
std::ofstream stream(filename, std::ios::binary);
writePlistBinary(stream, message);
stream.close();
}
#if defined(_MSC_VER)
void writePlistBinary(
const wchar_t* filename,
const boost::any& message)
{
std::ofstream stream(filename, std::ios::binary);
writePlistBinary(stream, message);
stream.close();
}
#endif
void writePlistXML(std::vector<char>& plist, const boost::any& message)
{
std::stringstream ss;
writePlistXML(ss, message);
std::istreambuf_iterator<char> beg(ss);
std::istreambuf_iterator<char> end;
plist.clear();
plist.insert(plist.begin(), beg, end);
}
void writePlistXML(
std::ostream& stream,
const boost::any& message)
{
pugi::xml_document doc;
writePlistXML(doc, message);
doc.save(stream);
}
void writePlistXML(
const char* filename,
const boost::any& message)
{
std::ofstream stream(filename, std::ios::binary);
writePlistXML(stream, message);
stream.close();
}
#if defined(_MSC_VER)
void writePlistXML(
const wchar_t* filename,
const boost::any& message)
{
std::ofstream stream(filename, std::ios::binary);
writePlistXML(stream, message);
stream.close();
}
#endif
int countAny(const boost::any& object)
{
using namespace std;
static boost::any dict = dictionary_type();
static boost::any array = array_type();
int count = 0;
if(object.type() == dict.type())
count += countDictionary(boost::any_cast<dictionary_type >(object)) + 1;
else if (object.type() == array.type())
count += countArray(boost::any_cast<array_type >(object)) + 1;
else
++count;
return count;
}
std::vector<unsigned char> writeBinary(PlistHelperData& d, const boost::any& obj)
{
using namespace std;
const std::type_info &objType = obj.type();
std::vector<unsigned char> value;
if(objType == typeid(int32_t))
value = writeBinaryInteger(d, boost::any_cast<const int32_t&>(obj), true);
else if(objType == typeid(int64_t))
value = writeBinaryInteger(d, boost::any_cast<const int64_t&>(obj), true);
else if(objType == typeid(long))
value = writeBinaryInteger(d, boost::any_cast<const long&>(obj), true);
else if(objType == typeid(short))
value = writeBinaryInteger(d, boost::any_cast<const short&>(obj), true);
else if(objType == typeid(dictionary_type))
value = writeBinaryDictionary(d, boost::any_cast<const dictionary_type& >(obj));
else if(objType == typeid(string))
value = writeBinaryString(d, boost::any_cast<const string&>(obj), true);
else if(objType == typeid(array_type))
value = writeBinaryArray(d, boost::any_cast<const array_type& >(obj));
else if(objType == typeid(data_type))
value = writeBinaryByteArray(d, boost::any_cast<const data_type& >(obj));
else if(objType == typeid(double))
value = writeBinaryDouble(d, boost::any_cast<const double&>(obj));
else if(objType == typeid(float))
value = writeBinaryDouble(d, boost::any_cast<const float&>(obj));
else if(objType == typeid(Date))
value = writeBinaryDate(d, boost::any_cast<const Date&>(obj));
else if(objType == typeid(bool))
value = writeBinaryBool(d, boost::any_cast<const bool&>(obj));
else
throw Error((string("Plist Error: Can't serialize type ") + objType.name()).c_str());
return value;
}
static uint32_t nextpow2(uint32_t x)
{
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return x + 1;
}
static uint32_t ilog2(uint32_t x)
{
uint32_t r = 0;
while (x >>= 1)
++r;
return r;
}
std::vector<unsigned char> writeBinaryByteArray(PlistHelperData& d, const data_type& byteArray)
{
using namespace std;
vector<unsigned char> header;
if(byteArray.size() < 15)
header.push_back(0x40 | ((unsigned char) byteArray.size()));
else
{
header.push_back(0x40 | 0xf);
vector<unsigned char> theSize = writeBinaryInteger(d, byteArray.size(), false);
header.insert(header.end(), theSize.begin(), theSize.end());
}
vector<unsigned char> buffer(header);
buffer.insert(buffer.end(), (unsigned char*) vecData(byteArray), (unsigned char*) vecData(byteArray) + byteArray.size());
d._objectTable.insert(d._objectTable.begin(), buffer.begin(), buffer.end());
return buffer;
}
std::vector<unsigned char> writeBinaryArray(PlistHelperData& d, const array_type& array)
{
using namespace std;
vector<int32_t> refs;
for(array_type::const_reverse_iterator it = array.rbegin();
it != array.rend();
++it)
{
writeBinary(d, *it);
d._offsetTable.push_back(d._objectTable.size());
refs.push_back(d._refCount);
d._refCount--;
}
vector<unsigned char> header;
if (array.size() < 15)
{
header.push_back(0xA0 | ((unsigned char) array.size()));
}
else
{
header.push_back(0xA0 | 0xf);
vector<unsigned char> theSize = writeBinaryInteger(d, array.size(), false);
header.insert(header.end(), theSize.begin(), theSize.end());
}
// try to do this more efficiently. Not good to insert at the begining of buffer.
vector<unsigned char> buffer;
for(vector<int32_t>::const_iterator it = refs.begin();
it != refs.end();
++it)
{
vector<unsigned char> refBuffer = regulateNullBytes(intToBytes<int32_t>(*it, hostLittleEndian()), d._objRefSize);
// reverse(refBuffer.begin(), refBuffer.end());
buffer.insert(buffer.begin(), refBuffer.rbegin(), refBuffer.rend());
}
buffer.insert(buffer.begin(), header.begin(), header.end());
d._objectTable.insert(d._objectTable.begin(), buffer.begin(), buffer.end());
return buffer;
}
std::vector<unsigned char> writeBinaryDictionary(PlistHelperData& d, const dictionary_type& dictionary)
{
using namespace std;
vector<int32_t> refs;
for(dictionary_type::const_reverse_iterator it = dictionary.rbegin();
it != dictionary.rend();
++it)
{
writeBinary(d, it->second);
d._offsetTable.push_back(d._objectTable.size());
refs.push_back(d._refCount);
d._refCount--;
}
for(dictionary_type::const_reverse_iterator it = dictionary.rbegin();
it != dictionary.rend();
++it)
{
writeBinary(d, it->first);
d._offsetTable.push_back(d._objectTable.size());
refs.push_back(d._refCount);
d._refCount--;
}
vector<unsigned char> header;
if (dictionary.size() < 15)
{
header.push_back(0xD0 | ((unsigned char) dictionary.size()));
}
else
{
header.push_back(0xD0 | 0xf);
vector<unsigned char> theSize = writeBinaryInteger(d, dictionary.size(), false);
header.insert(header.end(), theSize.begin(), theSize.end());
}
// try to do this more efficiently. Not good to insert at the begining of buffer.
vector<unsigned char> buffer;
for(vector<int32_t>::const_iterator it = refs.begin();
it != refs.end();
++it)
{
vector<unsigned char> refBuffer = regulateNullBytes(intToBytes<int32_t>(*it, hostLittleEndian()), d._objRefSize);
// reverse(refBuffer.begin(), refBuffer.end());
buffer.insert(buffer.begin(), refBuffer.rbegin(), refBuffer.rend());
}
buffer.insert(buffer.begin(), header.begin(), header.end());
d._objectTable.insert(d._objectTable.begin(), buffer.begin(), buffer.end());
return buffer;
}
std::vector<unsigned char> writeBinaryDouble(PlistHelperData& d, double value)
{
using namespace std;
vector<unsigned char> buffer = regulateNullBytes(doubleToBytes(value, hostLittleEndian()), 4);
buffer.resize(nextpow2(buffer.size()), 0);
unsigned char header = 0x20 | ilog2(buffer.size());
buffer.push_back(header);
reverse(buffer.begin(), buffer.end());
d._objectTable.insert(d._objectTable.begin(), buffer.begin(), buffer.end());
return buffer;
}
std::vector<unsigned char> writeBinaryBool(PlistHelperData& d, bool value)
{
std::vector<unsigned char> buffer;
if(value)
buffer.push_back(0x09);
else
buffer.push_back(0x08);
d._objectTable.insert(d._objectTable.begin(), buffer.begin(), buffer.end());
return buffer;
}
std::vector<unsigned char> writeBinaryDate(PlistHelperData& d, const Date& date)
{
std::vector<unsigned char> buffer;
// need to serialize as Apple epoch.
double macTime = date.timeAsAppleEpoch();
buffer = doubleToBytes(macTime, false);
buffer.insert(buffer.begin(), 0x33);
d._objectTable.insert(d._objectTable.begin(), buffer.begin(), buffer.end());
return buffer;
}
std::vector<unsigned char> writeBinaryInteger(PlistHelperData& d, int64_t value, bool write)
{
using namespace std;
// The integer is initially forced to be 64 bit because it must be serialized
// as 8 bytes if it is negative. If it is not negative, the
// regulateNullBytes step will reduce the representation down to the min
// power base 2 bytes needed to store it.
vector<unsigned char> buffer = intToBytes<int64_t>(value, hostLittleEndian());
buffer = regulateNullBytes(intToBytes<int64_t>(value, hostLittleEndian()), 1);
buffer.resize(nextpow2(buffer.size()), 0);
unsigned char header = 0x10 | ilog2(buffer.size());
buffer.push_back(header);
reverse(buffer.begin(), buffer.end());
if(write)
d._objectTable.insert(d._objectTable.begin(), buffer.begin(), buffer.end());
return buffer;
}
std::vector<unsigned char> writeBinaryString(PlistHelperData& d, const std::string& value, bool head)
{
using namespace std;
vector<unsigned char> buffer;
buffer.reserve(value.size());
for(std::string::const_iterator it = value.begin();
it != value.end();
++it)
buffer.push_back((unsigned char) *it);
if(head)
{
vector<unsigned char> header;
if (value.length() < 15)
header.push_back(0x50 | ((unsigned char) value.length()));
else
{
header.push_back(0x50 | 0xf);
vector<unsigned char> theSize = writeBinaryInteger(d, buffer.size(), false);
header.insert(header.end(), theSize.begin(), theSize.end());
}
buffer.insert(buffer.begin(), header.begin(), header.end());
}
d._objectTable.insert(d._objectTable.begin(), buffer.begin(), buffer.end());
return buffer;
}
int countDictionary(const dictionary_type& dictionary)
{
using namespace std;
int count = 0;
for(dictionary_type::const_iterator it = dictionary.begin();
it != dictionary.end();
++it)
{
++count;
count += countAny(it->second);
}
return count;
}
int countArray(const array_type& array)
{
using namespace std;
int count = 0;
for(array_type::const_iterator it = array.begin();
it != array.end();
++it)
count += countAny(*it);
return count;
}
void readPlist(std::istream& stream, boost::any& message)
{
int start = stream.tellg();
stream.seekg(0, std::ifstream::end);
int size = ((int) stream.tellg()) - start;
if(size > 0)
{
stream.seekg(0, std::ifstream::beg);
std::vector<char> buffer(size);
stream.read( (char *)&buffer[0], size );
readPlist(&buffer[0], size, message);
}
else
{
throw Error("Can't read zero length data");
}
}
void readPlist(const char* byteArrayTemp, int64_t size, boost::any& message)
{
using namespace std;
const unsigned char* byteArray = (const unsigned char*) byteArrayTemp;
if (!byteArray || (size == 0))
throw Error("Plist: Empty plist data");
// infer plist type from header. If it has the bplist00 header as first 8
// bytes, then it's a binary plist. Otherwise, assume it's XML
std::string magicHeader((const char*) byteArray, 8);
if(magicHeader == "bplist00")
{
PlistHelperData d;
parseTrailer(d, getRange(byteArray, size - 32, 32));
d._objectTable = getRange(byteArray, 0, d._offsetTableOffset);
std::vector<unsigned char> offsetTableBytes = getRange(byteArray, d._offsetTableOffset, size - d._offsetTableOffset - 32);
parseOffsetTable(d, offsetTableBytes);
message = parseBinary(d, 0);
}
else
{
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_buffer(byteArray, (size_t)size);
if(!result)
throw Error((string("Plist: XML parsed with error ") + result.description()).c_str());
pugi::xml_node rootNode = doc.child("plist").first_child();
message = parse(rootNode);
}
}
dictionary_type parseDictionary(pugi::xml_node& node)
{
using namespace std;
dictionary_type dict;
for(pugi::xml_node_iterator it = node.begin(); it != node.end(); ++it)
{
if(string("key") != it->name())
throw Error("Plist: XML dictionary key expected but not found");
string key(it->first_child().value());
++it;
if(it == node.end())
throw Error("Plist: XML dictionary value expected for key " + key + "but not found");
else if(string("key") == it->name())
throw Error("Plist: XML dictionary value expected for key " + key + "but found another key node");
dict[key] = parse(*it);
}
return dict;
}
array_type parseArray(pugi::xml_node& node)
{
using namespace std;
array_type array;
for(pugi::xml_node_iterator it = node.begin(); it != node.end(); ++it)
array.push_back(parse(*it));
return array;
}
Date parseDate(pugi::xml_node& node)
{
Date date;
date.setTimeFromXMLConvention(node.first_child().value());
return date;
}
std::vector<char> base64Decode(const char* encodedData)
{
using namespace std;
vector<char> data;
insert_iterator<vector<char> > ii(data, data.begin());
base64<char> b64;
int state = 0;
b64.get(encodedData, encodedData + strlen(encodedData), ii, state);
return data;
}
void base64Encode(std::string& dataEncoded, const std::vector<char>& data)
{
using namespace std;
dataEncoded.clear();
insert_iterator<string> ii(dataEncoded, dataEncoded.begin());
base64<char> b64;
int state = 0;
#if defined(_WIN32) || defined(_WIN64)
b64.put(data.begin(), data.end(), ii, state , base64<>::crlf());
#else
b64.put(data.begin(), data.end(), ii, state , base64<>::lf());
#endif
}
boost::any parse(pugi::xml_node& node)
{
using namespace std;
string nodeName = node.name();
boost::any result;
if("dict" == nodeName)
result = parseDictionary(node);
else if("array" == nodeName)
result = parseArray(node);
else if("string" == nodeName)
result = string(node.first_child().value());
else if("integer" == nodeName)
result = (int64_t) atoll(node.first_child().value());
else if("real" == nodeName)
result = atof(node.first_child().value());
else if("false" == nodeName)
result = bool(false);
else if("true" == nodeName)
result = bool(true);
else if("data" == nodeName)
result = base64Decode(node.first_child().value());
else if("date" == nodeName)
result = parseDate(node);
else
throw Error(string("Plist: XML unknown node type " + nodeName));
return result;
}
void parseOffsetTable(PlistHelperData& d, const std::vector<unsigned char>& offsetTableBytes)
{
for (unsigned int i = 0; i < offsetTableBytes.size(); i += d._offsetByteSize)
{
std::vector<unsigned char> temp = getRange(offsetTableBytes, i, d._offsetByteSize);
std::reverse(temp.begin(), temp.end());
d._offsetTable.push_back(
bytesToInt<int32_t>(
vecData(regulateNullBytes(temp, 4)), hostLittleEndian()));
}
}
void parseTrailer(PlistHelperData& d, const std::vector<unsigned char>& trailer)
{
d._offsetByteSize = bytesToInt<int32_t>(vecData(regulateNullBytes(getRange(trailer, 6, 1), 4)), hostLittleEndian());
d._objRefSize = bytesToInt<int32_t>(vecData(regulateNullBytes(getRange(trailer, 7, 1), 4)), hostLittleEndian());
std::vector<unsigned char> refCountBytes = getRange(trailer, 12, 4);
// std::reverse(refCountBytes.begin(), refCountBytes.end());
d._refCount = bytesToInt<int32_t>(vecData(refCountBytes), false);
std::vector<unsigned char> offsetTableOffsetBytes = getRange(trailer, 24, 8);
// std::reverse(offsetTableOffsetBytes.begin(), offsetTableOffsetBytes.end());
d._offsetTableOffset = bytesToInt<int64_t>(vecData(offsetTableOffsetBytes), false);
}
std::vector<unsigned char> regulateNullBytes(const std::vector<unsigned char>& origBytes, unsigned int minBytes)
{
std::vector<unsigned char> bytes(origBytes);
while((bytes.back() == 0) && (bytes.size() > minBytes))
bytes.pop_back();
while(bytes.size() < minBytes)
bytes.push_back(0);
return bytes;
}
boost::any parseBinary(const PlistHelperData& d, int objRef)
{
unsigned char header = d._objectTable[d._offsetTable[objRef]];
switch (header & 0xF0)
{
case 0x00:
{
return parseBinaryBool(d, d._offsetTable[objRef]);
}
case 0x10:
{
int intByteCount;
return parseBinaryInt(d, d._offsetTable[objRef], intByteCount);
}
case 0x20:
{
return parseBinaryReal(d, d._offsetTable[objRef]);
}
case 0x30:
{
return parseBinaryDate(d, d._offsetTable[objRef]);
}
case 0x40:
{
return parseBinaryByteArray(d, d._offsetTable[objRef]);
}
case 0x50:
{
return parseBinaryString(d, d._offsetTable[objRef]);
}
case 0x60:
{
return parseBinaryUnicode(d, d._offsetTable[objRef]);
}
case 0xD0:
{
return parseBinaryDictionary(d, objRef);
}
case 0xA0:
{
return parseBinaryArray(d, objRef);
}
}
throw Error("This type is not supported");
}
std::vector<int32_t> getRefsForContainers(const PlistHelperData& d, int objRef)
{
using namespace std;
int32_t refCount = 0;
int refStartPosition;
refCount = getCount(d, d._offsetTable[objRef], d._objectTable[d._offsetTable[objRef]], refStartPosition);
refStartPosition += d._offsetTable[objRef];
vector<int32_t> refs;
int mult = 1;
if((((unsigned char) d._objectTable[d._offsetTable[objRef]]) & 0xF0) == 0xD0)
mult = 2;
for (int i = refStartPosition; i < refStartPosition + refCount * mult * d._objRefSize; i += d._objRefSize)
{
std::vector<unsigned char> refBuffer = getRange(d._objectTable, i, d._objRefSize);
reverse(refBuffer.begin(), refBuffer.end());
refs.push_back(bytesToInt<int32_t>(vecData(regulateNullBytes(refBuffer, 4)), hostLittleEndian()));
}
return refs;
}
array_type parseBinaryArray(const PlistHelperData& d, int objRef)
{
using namespace std;
vector<int32_t> refs = getRefsForContainers(d, objRef);
int32_t refCount = refs.size();
array_type array;
for(int i = 0; i < refCount; ++i)
array.push_back(parseBinary(d, refs[i]));
return array;
}
dictionary_type parseBinaryDictionary(const PlistHelperData& d, int objRef)
{
using namespace std;
vector<int32_t> refs = getRefsForContainers(d, objRef);
int32_t refCount = refs.size() / 2;
dictionary_type dict;
for (int i = 0; i < refCount; i++)
{
boost::any keyAny = parseBinary(d, refs[i]);
try
{
std::string& key = boost::any_cast<std::string&>(keyAny);
dict[key] = parseBinary(d, refs[i + refCount]);
}
catch(boost::bad_any_cast& )
{
throw Error("Error parsing dictionary. Key can't be parsed as a string");
}
}
return dict;
}
std::string parseBinaryString(const PlistHelperData& d, int headerPosition)
{
unsigned char headerByte = d._objectTable[headerPosition];
int charStartPosition;
int32_t charCount = getCount(d, headerPosition, headerByte, charStartPosition);
charStartPosition += headerPosition;
std::vector<unsigned char> characterBytes = getRange(d._objectTable, charStartPosition, charCount);
std::string buffer = std::string((char*) vecData(characterBytes), characterBytes.size());
return buffer;
}
std::string parseBinaryUnicode(const PlistHelperData& d, int headerPosition)
{
unsigned char headerByte = d._objectTable[headerPosition];
int charStartPosition;
int32_t charCount = getCount(d, headerPosition, headerByte, charStartPosition);
charStartPosition += headerPosition;
std::vector<unsigned char> characterBytes = getRange(d._objectTable, charStartPosition, charCount * 2);
if (hostLittleEndian()) {
if (! characterBytes.empty()) {
for (std::size_t i = 0, n = characterBytes.size(); i < n - 1; i += 2)
std::swap(characterBytes[i], characterBytes[i + 1]);
}
}
int16_t *u16chars = (int16_t*) vecData(characterBytes);
std::size_t u16len = characterBytes.size() / 2;
std::string result = boost::locale::conv::utf_to_utf<char, int16_t>(u16chars, u16chars + u16len, boost::locale::conv::stop);
return result;
}
int64_t parseBinaryInt(const PlistHelperData& d, int headerPosition, int& intByteCount)
{
unsigned char header = d._objectTable[headerPosition];
intByteCount = 1 << (header & 0xf);
std::vector<unsigned char> buffer = getRange(d._objectTable, headerPosition + 1, intByteCount);
reverse(buffer.begin(), buffer.end());
return bytesToInt<int64_t>(vecData(regulateNullBytes(buffer, 8)), hostLittleEndian());
}
double parseBinaryReal(const PlistHelperData& d, int headerPosition)
{
unsigned char header = d._objectTable[headerPosition];
int byteCount = 1 << (header & 0xf);
std::vector<unsigned char> buffer = getRange(d._objectTable, headerPosition + 1, byteCount);
reverse(buffer.begin(), buffer.end());
return bytesToDouble(vecData(regulateNullBytes(buffer, 8)), hostLittleEndian());
}
bool parseBinaryBool(const PlistHelperData& d, int headerPosition)
{
unsigned char header = d._objectTable[headerPosition];
bool value;
if(header == 0x09)
value = true;
else if (header == 0x08)
value = false;
else if (header == 0x00)
{
// null byte, not sure yet what to do with this. It's in the spec but we
// have never encountered it.
throw Error("Plist: null byte encountered, unsure how to parse");
}
else if (header == 0x0F)
{
// fill byte, not sure yet what to do with this. It's in the spec but we
// have never encountered it.
throw Error("Plist: fill byte encountered, unsure how to parse");
}
else
{
std::stringstream ss;
ss<<"Plist: unknown header "<<header;
throw Error(ss.str().c_str());
}
return value;
}
Date parseBinaryDate(const PlistHelperData& d, int headerPosition)
{
// date always an 8 byte float starting after full byte header
std::vector<unsigned char> buffer = getRange(d._objectTable, headerPosition + 1, 8);
Date date;
// Date is stored as Apple Epoch and big endian.
date.setTimeFromAppleEpoch(bytesToDouble(vecData(buffer), false));
return date;
}
data_type parseBinaryByteArray(const PlistHelperData& d, int headerPosition)
{
unsigned char headerByte = d._objectTable[headerPosition];
int byteStartPosition;
int32_t byteCount = getCount(d, headerPosition, headerByte, byteStartPosition);
byteStartPosition += headerPosition;
return getRange((const char*) vecData(d._objectTable), byteStartPosition, byteCount);
}
int32_t getCount(const PlistHelperData& d, int bytePosition, unsigned char headerByte, int& startOffset)
{
unsigned char headerByteTrail = headerByte & 0xf;
if (headerByteTrail < 15)
{
startOffset = 1;
return headerByteTrail;
}
else
{
int32_t count = (int32_t)parseBinaryInt(d, bytePosition + 1, startOffset);
startOffset += 2;
return count;
}
}
template<typename T>
std::string stringFromValue(const T& value)
{
std::stringstream ss;
ss<<value;
return ss.str();
}
template <typename IntegerType>
IntegerType bytesToInt(const unsigned char* bytes, bool littleEndian)
{
IntegerType result = 0;
if (littleEndian)
for (int n = sizeof( result ) - 1; n >= 0; n--)
result = (result << 8) + bytes[n];
else
for (unsigned n = 0; n < sizeof( result ); n++)
result = (result << 8) + bytes[n];
return result;
}
double bytesToDouble(const unsigned char* bytes, bool littleEndian)
{
double result;
int numBytes = sizeof(double);
if(littleEndian)
memcpy( &result, bytes, numBytes);
else
{
std::vector<unsigned char> bytesReverse(numBytes);
std::reverse_copy(bytes, bytes + numBytes, bytesReverse.begin());
memcpy( &result, vecData(bytesReverse), numBytes);
}
return result;
}
std::vector<unsigned char> doubleToBytes(double val, bool littleEndian)
{
std::vector<unsigned char> result(sizeof(double));
memcpy(vecData(result), &val, sizeof(double));
if(!littleEndian)
std::reverse(result.begin(), result.end());
return result;
}
template<typename IntegerType>
std::vector<unsigned char> intToBytes(IntegerType val, bool littleEndian)
{
unsigned int numBytes = sizeof(val);
std::vector<unsigned char> bytes(numBytes);
for(unsigned n = 0; n < numBytes; ++n)
if(littleEndian)
bytes[n] = (val >> 8 * n) & 0xff;
else
bytes[numBytes - 1 - n] = (val >> 8 * n) & 0xff;
return bytes;
}
std::vector<unsigned char> getRange(const unsigned char* origBytes, int64_t index, int64_t size)
{
std::vector<unsigned char> result((std::vector<unsigned char>::size_type)size);
std::copy(origBytes + index, origBytes + index + size, result.begin());
return result;
}
std::vector<char> getRange(const char* origBytes, int64_t index, int64_t size)
{
std::vector<char> result((std::vector<char>::size_type)size);
std::copy(origBytes + index, origBytes + index + size, result.begin());
return result;
}
std::vector<unsigned char> getRange(const std::vector<unsigned char>& origBytes, int64_t index, int64_t size)
{
if((index + size) > (int64_t) origBytes.size())
throw Error("Out of bounds getRange");
return getRange(vecData(origBytes), index, size);
}
} // namespace Plist
1
https://gitee.com/linnasi/QtOpenCoreConfig.git
git@gitee.com:linnasi/QtOpenCoreConfig.git
linnasi
QtOpenCoreConfig
QtOpenCoreConfig
master

搜索帮助