plist.cpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209
  1. //
  2. // PlistCpp Property List (plist) serialization and parsing library.
  3. //
  4. // https://github.com/animetrics/PlistCpp
  5. //
  6. // Copyright (c) 2011 Animetrics Inc. (marc@animetrics.com)
  7. //
  8. // Permission is hereby granted, free of charge, to any person obtaining a copy
  9. // of this software and associated documentation files (the "Software"), to deal
  10. // in the Software without restriction, including without limitation the rights
  11. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. // copies of the Software, and to permit persons to whom the Software is
  13. // furnished to do so, subject to the following conditions:
  14. //
  15. // The above copyright notice and this permission notice shall be included in
  16. // all copies or substantial portions of the Software.
  17. //
  18. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. // THE SOFTWARE.
  25. #include "plisthpp/Plist.hpp"
  26. #include <boost/locale/encoding_utf.hpp>
  27. #include <list>
  28. #include <sstream>
  29. #include "plisthpp/base64.hpp"
  30. #include "plisthpp/pugixml.hpp"
  31. namespace Plist {
  32. struct PlistHelperData
  33. {
  34. public:
  35. // binary helper data
  36. std::vector<int32_t> _offsetTable;
  37. std::vector<unsigned char> _objectTable;
  38. int32_t _offsetByteSize;
  39. int64_t _offsetTableOffset;
  40. int32_t _objRefSize;
  41. int32_t _refCount;
  42. };
  43. void writePlistBinary(
  44. PlistHelperData& d,
  45. const boost::any& message);
  46. void writePlistXML(
  47. pugi::xml_document& doc,
  48. const boost::any& message);
  49. // helper functions
  50. // msvc <= 2005 doesn't have std::vector::data() method
  51. template<typename T>
  52. T* vecData(std::vector<T>& vec)
  53. {
  54. return (vec.size() > 0) ? &vec[0] : 0;
  55. // if(vec.size() > 0)
  56. // return &vec[0];
  57. // else
  58. // throw Error("vecData trying to get pointer to empty std::vector");
  59. }
  60. template<typename T>
  61. const T* vecData(const std::vector<T>& vec)
  62. {
  63. return (vec.size() > 0) ? &vec[0] : 0;
  64. // if(vec.size() > 0)
  65. // return &vec[0];
  66. // else
  67. // throw Error("vecData trying to get pointer to empty std::vector");
  68. }
  69. // xml helper functions
  70. template<typename T>
  71. std::string stringFromValue(const T& value);
  72. template<typename T>
  73. void writeXMLSimpleNode(pugi::xml_node& node, const char* name, const boost::any& obj);
  74. // xml parsing
  75. dictionary_type parseDictionary(pugi::xml_node& node);
  76. array_type parseArray(pugi::xml_node& node);
  77. std::vector<char> base64Decode(const char* data);
  78. void base64Encode(std::string& dataEncoded, const std::vector<char>& data);
  79. Date parseDate(pugi::xml_node& node);
  80. boost::any parse(pugi::xml_node& doc);
  81. // xml writing
  82. void writeXMLArray(pugi::xml_node& node, const array_type& array);
  83. void writeXMLDictionary(pugi::xml_node& node, const dictionary_type& message);
  84. void writeXMLNode(pugi::xml_node& node, const boost::any& obj);
  85. // binary helper functions
  86. template <typename IntegerType>
  87. IntegerType bytesToInt(const unsigned char* bytes, bool littleEndian);
  88. double bytesToDouble(const unsigned char* bytes, bool littleEndian);
  89. std::vector<unsigned char> doubleToBytes(double val, bool littleEndian);
  90. template<typename IntegerType>
  91. std::vector<unsigned char> intToBytes(IntegerType val, bool littleEndian);
  92. std::vector<unsigned char> getRange(const unsigned char* origBytes, int64_t index, int64_t size);
  93. std::vector<unsigned char> getRange(const std::vector<unsigned char>& origBytes, int64_t index, int64_t size);
  94. std::vector<char> getRange(const char* origBytes, int64_t index, int64_t size);
  95. // binary parsing
  96. boost::any parseBinary(const PlistHelperData& d, int objRef);
  97. dictionary_type parseBinaryDictionary(const PlistHelperData& d, int objRef);
  98. array_type parseBinaryArray(const PlistHelperData& d, int objRef);
  99. std::vector<int32_t> getRefsForContainers(const PlistHelperData& d, int objRef);
  100. int64_t parseBinaryInt(const PlistHelperData& d, int headerPosition, int& intByteCount);
  101. double parseBinaryReal(const PlistHelperData& d, int headerPosition);
  102. Date parseBinaryDate(const PlistHelperData& d, int headerPosition);
  103. bool parseBinaryBool(const PlistHelperData& d, int headerPosition);
  104. std::string parseBinaryString(const PlistHelperData& d, int objRef);
  105. std::string parseBinaryUnicode(const PlistHelperData& d, int headerPosition);
  106. data_type parseBinaryByteArray(const PlistHelperData& d, int headerPosition);
  107. std::vector<unsigned char> regulateNullBytes(const std::vector<unsigned char>& origBytes, unsigned int minBytes);
  108. void parseTrailer(PlistHelperData& d, const std::vector<unsigned char>& trailer);
  109. void parseOffsetTable(PlistHelperData& d, const std::vector<unsigned char>& offsetTableBytes);
  110. int32_t getCount(const PlistHelperData& d, int bytePosition, unsigned char headerByte, int& startOffset);
  111. // binary writing
  112. int countAny(const boost::any& object);
  113. int countDictionary(const dictionary_type& dictionary);
  114. int countArray(const array_type& array);
  115. std::vector<unsigned char> writeBinaryDictionary(PlistHelperData& d, const dictionary_type& dictionary);
  116. std::vector<unsigned char> writeBinaryArray(PlistHelperData& d, const array_type& array);
  117. std::vector<unsigned char> writeBinaryByteArray(PlistHelperData& d, const data_type& byteArray);
  118. std::vector<unsigned char> writeBinaryInteger(PlistHelperData& d, int64_t value, bool write);
  119. std::vector<unsigned char> writeBinaryBool(PlistHelperData& d, bool value);
  120. std::vector<unsigned char> writeBinaryDate(PlistHelperData& d, const Date& date);
  121. std::vector<unsigned char> writeBinaryDouble(PlistHelperData& d, double value);
  122. std::vector<unsigned char> writeBinary(PlistHelperData& d, const boost::any& obj);
  123. std::vector<unsigned char> writeBinaryString(PlistHelperData& d, const std::string& value, bool head);
  124. inline bool hostLittleEndian()
  125. {
  126. union { uint32_t x; uint8_t c[4]; } u;
  127. u.x = 0xab0000cd;
  128. return u.c[0] == 0xcd;
  129. }
  130. } // namespace Plist
  131. namespace Plist {
  132. template<typename T>
  133. void writeXMLSimpleNode(pugi::xml_node& node, const char* name, const boost::any& obj)
  134. {
  135. pugi::xml_node newNode;
  136. newNode = node.append_child(name);
  137. newNode.append_child(pugi::node_pcdata).set_value(stringFromValue(boost::any_cast<const T&>(obj)).c_str());
  138. }
  139. void writeXMLNode(pugi::xml_node& node, const boost::any& obj)
  140. {
  141. using namespace std;
  142. const std::type_info &objType = obj.type();
  143. if(objType == typeid(int32_t))
  144. writeXMLSimpleNode<int32_t>(node, "integer", obj);
  145. else if(objType == typeid(int64_t))
  146. writeXMLSimpleNode<int64_t>(node, "integer", obj);
  147. else if(objType == typeid(long))
  148. writeXMLSimpleNode<long>(node, "integer", obj);
  149. else if(objType == typeid(short))
  150. writeXMLSimpleNode<short>(node, "integer", obj);
  151. else if(objType == typeid(dictionary_type))
  152. writeXMLDictionary(node, boost::any_cast<const dictionary_type&>(obj));
  153. else if(objType == typeid(string_type))
  154. writeXMLSimpleNode<string_type>(node, "string", obj);
  155. else if(objType == typeid(array_type))
  156. writeXMLArray(node, boost::any_cast<const array_type&>(obj));
  157. else if(objType == typeid(data_type))
  158. {
  159. string dataEncoded;
  160. base64Encode(dataEncoded, boost::any_cast<const data_type&>(obj));
  161. writeXMLSimpleNode<string>(node, "data", dataEncoded);
  162. }
  163. else if(objType == typeid(double))
  164. writeXMLSimpleNode<double>(node, "real", obj);
  165. else if(objType == typeid(float))
  166. writeXMLSimpleNode<float>(node, "real", obj);
  167. else if(objType == typeid(Date))
  168. writeXMLSimpleNode<string>(node, "date", boost::any_cast<const Date&>(obj).timeAsXMLConvention());
  169. else if(objType == typeid(bool))
  170. {
  171. bool value = boost::any_cast<const bool&>(obj);
  172. node.append_child(value ? "true" : "false");
  173. }
  174. else
  175. throw Error((string("Plist Error: Can't serialize type ") + objType.name()).c_str());
  176. }
  177. void writeXMLArray(
  178. pugi::xml_node& node,
  179. const array_type& array)
  180. {
  181. using namespace std;
  182. pugi::xml_node newNode = node.append_child("array");
  183. for(array_type::const_iterator it = array.begin();
  184. it != array.end();
  185. ++it)
  186. writeXMLNode(newNode, *it);
  187. }
  188. void writeXMLDictionary(
  189. pugi::xml_node& node,
  190. const dictionary_type& message)
  191. {
  192. using namespace std;
  193. pugi::xml_node newNode = node.append_child("dict");
  194. for(dictionary_type::const_iterator it = message.begin();
  195. it != message.end();
  196. ++it)
  197. {
  198. pugi::xml_node keyNode = newNode.append_child("key");
  199. keyNode.append_child(pugi::node_pcdata).set_value(it->first.c_str());
  200. writeXMLNode(newNode, it->second);
  201. }
  202. }
  203. void writePlistXML(
  204. pugi::xml_document& doc,
  205. const boost::any& message)
  206. // const dictionary_type& message)
  207. {
  208. // declaration node
  209. pugi::xml_node decNode = doc.append_child(pugi::node_declaration);
  210. decNode.append_attribute("version") = "1.0";
  211. decNode.append_attribute("encoding") = "UTF-8";
  212. // doctype node
  213. 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\"");
  214. // root node
  215. pugi::xml_node plistNode = doc.append_child("plist");
  216. plistNode.append_attribute("version") = "1.0";
  217. writeXMLNode(plistNode, message);
  218. }
  219. void writePlistBinary(
  220. PlistHelperData& d,
  221. const boost::any& message)
  222. {
  223. using namespace std;
  224. //int totalRefs = countDictionary(message);
  225. int totalRefs = countAny(message) - 1;
  226. d._refCount = totalRefs;
  227. d._objRefSize = regulateNullBytes(intToBytes<int32_t>(d._refCount, hostLittleEndian()), 1).size();
  228. //writeBinaryDictionary(d, message);
  229. writeBinary(d, message);
  230. writeBinaryString(d, "bplist00", false);
  231. d._offsetTableOffset = (int64_t) d._objectTable.size();
  232. d._offsetTable.push_back(d._objectTable.size() - 8);
  233. d._offsetByteSize = regulateNullBytes(intToBytes<int>(d._offsetTable.back(), hostLittleEndian()), 1).size();
  234. vector<unsigned char> offsetBytes;
  235. reverse(d._offsetTable.begin(), d._offsetTable.end());
  236. for(unsigned int i = 0; i < d._offsetTable.size(); ++i)
  237. {
  238. d._offsetTable[i] = d._objectTable.size() - d._offsetTable[i];
  239. vector<unsigned char> buffer = regulateNullBytes(intToBytes<int>(d._offsetTable[i], hostLittleEndian()), d._offsetByteSize);
  240. //reverse(buffer.begin(), buffer.end());
  241. offsetBytes.insert(offsetBytes.end(), buffer.rbegin(), buffer.rend());
  242. }
  243. d._objectTable.insert(d._objectTable.end(), offsetBytes.begin(), offsetBytes.end());
  244. vector<unsigned char> dummy(6, 0);
  245. d._objectTable.insert(d._objectTable.end(), dummy.begin(), dummy.end());
  246. d._objectTable.push_back((unsigned char) (d._offsetByteSize));
  247. d._objectTable.push_back((unsigned char) (d._objRefSize));
  248. vector<unsigned char> temp = intToBytes<int64_t>((int64_t) totalRefs + 1, hostLittleEndian());
  249. d._objectTable.insert(d._objectTable.end(), temp.rbegin(), temp.rend());
  250. temp = intToBytes<int64_t>(0, hostLittleEndian());
  251. d._objectTable.insert(d._objectTable.end(), temp.begin(), temp.end());
  252. temp = intToBytes<int64_t>(d._offsetTableOffset, hostLittleEndian());
  253. d._objectTable.insert(d._objectTable.end(), temp.rbegin(), temp.rend());
  254. }
  255. void writePlistBinary(std::vector<char>& plist, const boost::any& message)
  256. {
  257. PlistHelperData d;
  258. writePlistBinary(d, message);
  259. plist.resize(d._objectTable.size());
  260. std::copy((const char*) vecData(d._objectTable), (const char*) vecData(d._objectTable) + d._objectTable.size(), plist.begin());
  261. }
  262. void writePlistBinary(
  263. std::ostream& stream,
  264. const boost::any& message)
  265. {
  266. PlistHelperData d;
  267. writePlistBinary(d, message);
  268. stream.write((const char*) vecData(d._objectTable), d._objectTable.size());
  269. }
  270. void writePlistBinary(
  271. const char* filename,
  272. const boost::any& message)
  273. {
  274. std::ofstream stream(filename, std::ios::binary);
  275. writePlistBinary(stream, message);
  276. stream.close();
  277. }
  278. #if defined(_MSC_VER)
  279. void writePlistBinary(
  280. const wchar_t* filename,
  281. const boost::any& message)
  282. {
  283. std::ofstream stream(filename, std::ios::binary);
  284. writePlistBinary(stream, message);
  285. stream.close();
  286. }
  287. #endif
  288. void writePlistXML(std::vector<char>& plist, const boost::any& message)
  289. {
  290. std::stringstream ss;
  291. writePlistXML(ss, message);
  292. std::istreambuf_iterator<char> beg(ss);
  293. std::istreambuf_iterator<char> end;
  294. plist.clear();
  295. plist.insert(plist.begin(), beg, end);
  296. }
  297. void writePlistXML(
  298. std::ostream& stream,
  299. const boost::any& message)
  300. {
  301. pugi::xml_document doc;
  302. writePlistXML(doc, message);
  303. doc.save(stream);
  304. }
  305. void writePlistXML(
  306. const char* filename,
  307. const boost::any& message)
  308. {
  309. std::ofstream stream(filename, std::ios::binary);
  310. writePlistXML(stream, message);
  311. stream.close();
  312. }
  313. #if defined(_MSC_VER)
  314. void writePlistXML(
  315. const wchar_t* filename,
  316. const boost::any& message)
  317. {
  318. std::ofstream stream(filename, std::ios::binary);
  319. writePlistXML(stream, message);
  320. stream.close();
  321. }
  322. #endif
  323. int countAny(const boost::any& object)
  324. {
  325. using namespace std;
  326. static boost::any dict = dictionary_type();
  327. static boost::any array = array_type();
  328. int count = 0;
  329. if(object.type() == dict.type())
  330. count += countDictionary(boost::any_cast<dictionary_type >(object)) + 1;
  331. else if (object.type() == array.type())
  332. count += countArray(boost::any_cast<array_type >(object)) + 1;
  333. else
  334. ++count;
  335. return count;
  336. }
  337. std::vector<unsigned char> writeBinary(PlistHelperData& d, const boost::any& obj)
  338. {
  339. using namespace std;
  340. const std::type_info &objType = obj.type();
  341. std::vector<unsigned char> value;
  342. if(objType == typeid(int32_t))
  343. value = writeBinaryInteger(d, boost::any_cast<const int32_t&>(obj), true);
  344. else if(objType == typeid(int64_t))
  345. value = writeBinaryInteger(d, boost::any_cast<const int64_t&>(obj), true);
  346. else if(objType == typeid(long))
  347. value = writeBinaryInteger(d, boost::any_cast<const long&>(obj), true);
  348. else if(objType == typeid(short))
  349. value = writeBinaryInteger(d, boost::any_cast<const short&>(obj), true);
  350. else if(objType == typeid(dictionary_type))
  351. value = writeBinaryDictionary(d, boost::any_cast<const dictionary_type& >(obj));
  352. else if(objType == typeid(string))
  353. value = writeBinaryString(d, boost::any_cast<const string&>(obj), true);
  354. else if(objType == typeid(array_type))
  355. value = writeBinaryArray(d, boost::any_cast<const array_type& >(obj));
  356. else if(objType == typeid(data_type))
  357. value = writeBinaryByteArray(d, boost::any_cast<const data_type& >(obj));
  358. else if(objType == typeid(double))
  359. value = writeBinaryDouble(d, boost::any_cast<const double&>(obj));
  360. else if(objType == typeid(float))
  361. value = writeBinaryDouble(d, boost::any_cast<const float&>(obj));
  362. else if(objType == typeid(Date))
  363. value = writeBinaryDate(d, boost::any_cast<const Date&>(obj));
  364. else if(objType == typeid(bool))
  365. value = writeBinaryBool(d, boost::any_cast<const bool&>(obj));
  366. else
  367. throw Error((string("Plist Error: Can't serialize type ") + objType.name()).c_str());
  368. return value;
  369. }
  370. static uint32_t nextpow2(uint32_t x)
  371. {
  372. --x;
  373. x |= x >> 1;
  374. x |= x >> 2;
  375. x |= x >> 4;
  376. x |= x >> 8;
  377. x |= x >> 16;
  378. return x + 1;
  379. }
  380. static uint32_t ilog2(uint32_t x)
  381. {
  382. uint32_t r = 0;
  383. while (x >>= 1)
  384. ++r;
  385. return r;
  386. }
  387. std::vector<unsigned char> writeBinaryByteArray(PlistHelperData& d, const data_type& byteArray)
  388. {
  389. using namespace std;
  390. vector<unsigned char> header;
  391. if(byteArray.size() < 15)
  392. header.push_back(0x40 | ((unsigned char) byteArray.size()));
  393. else
  394. {
  395. header.push_back(0x40 | 0xf);
  396. vector<unsigned char> theSize = writeBinaryInteger(d, byteArray.size(), false);
  397. header.insert(header.end(), theSize.begin(), theSize.end());
  398. }
  399. vector<unsigned char> buffer(header);
  400. buffer.insert(buffer.end(), (unsigned char*) vecData(byteArray), (unsigned char*) vecData(byteArray) + byteArray.size());
  401. d._objectTable.insert(d._objectTable.begin(), buffer.begin(), buffer.end());
  402. return buffer;
  403. }
  404. std::vector<unsigned char> writeBinaryArray(PlistHelperData& d, const array_type& array)
  405. {
  406. using namespace std;
  407. vector<int32_t> refs;
  408. for(array_type::const_reverse_iterator it = array.rbegin();
  409. it != array.rend();
  410. ++it)
  411. {
  412. writeBinary(d, *it);
  413. d._offsetTable.push_back(d._objectTable.size());
  414. refs.push_back(d._refCount);
  415. d._refCount--;
  416. }
  417. vector<unsigned char> header;
  418. if (array.size() < 15)
  419. {
  420. header.push_back(0xA0 | ((unsigned char) array.size()));
  421. }
  422. else
  423. {
  424. header.push_back(0xA0 | 0xf);
  425. vector<unsigned char> theSize = writeBinaryInteger(d, array.size(), false);
  426. header.insert(header.end(), theSize.begin(), theSize.end());
  427. }
  428. // try to do this more efficiently. Not good to insert at the begining of buffer.
  429. vector<unsigned char> buffer;
  430. for(vector<int32_t>::const_iterator it = refs.begin();
  431. it != refs.end();
  432. ++it)
  433. {
  434. vector<unsigned char> refBuffer = regulateNullBytes(intToBytes<int32_t>(*it, hostLittleEndian()), d._objRefSize);
  435. // reverse(refBuffer.begin(), refBuffer.end());
  436. buffer.insert(buffer.begin(), refBuffer.rbegin(), refBuffer.rend());
  437. }
  438. buffer.insert(buffer.begin(), header.begin(), header.end());
  439. d._objectTable.insert(d._objectTable.begin(), buffer.begin(), buffer.end());
  440. return buffer;
  441. }
  442. std::vector<unsigned char> writeBinaryDictionary(PlistHelperData& d, const dictionary_type& dictionary)
  443. {
  444. using namespace std;
  445. vector<int32_t> refs;
  446. for(dictionary_type::const_reverse_iterator it = dictionary.rbegin();
  447. it != dictionary.rend();
  448. ++it)
  449. {
  450. writeBinary(d, it->second);
  451. d._offsetTable.push_back(d._objectTable.size());
  452. refs.push_back(d._refCount);
  453. d._refCount--;
  454. }
  455. for(dictionary_type::const_reverse_iterator it = dictionary.rbegin();
  456. it != dictionary.rend();
  457. ++it)
  458. {
  459. writeBinary(d, it->first);
  460. d._offsetTable.push_back(d._objectTable.size());
  461. refs.push_back(d._refCount);
  462. d._refCount--;
  463. }
  464. vector<unsigned char> header;
  465. if (dictionary.size() < 15)
  466. {
  467. header.push_back(0xD0 | ((unsigned char) dictionary.size()));
  468. }
  469. else
  470. {
  471. header.push_back(0xD0 | 0xf);
  472. vector<unsigned char> theSize = writeBinaryInteger(d, dictionary.size(), false);
  473. header.insert(header.end(), theSize.begin(), theSize.end());
  474. }
  475. // try to do this more efficiently. Not good to insert at the begining of buffer.
  476. vector<unsigned char> buffer;
  477. for(vector<int32_t>::const_iterator it = refs.begin();
  478. it != refs.end();
  479. ++it)
  480. {
  481. vector<unsigned char> refBuffer = regulateNullBytes(intToBytes<int32_t>(*it, hostLittleEndian()), d._objRefSize);
  482. // reverse(refBuffer.begin(), refBuffer.end());
  483. buffer.insert(buffer.begin(), refBuffer.rbegin(), refBuffer.rend());
  484. }
  485. buffer.insert(buffer.begin(), header.begin(), header.end());
  486. d._objectTable.insert(d._objectTable.begin(), buffer.begin(), buffer.end());
  487. return buffer;
  488. }
  489. std::vector<unsigned char> writeBinaryDouble(PlistHelperData& d, double value)
  490. {
  491. using namespace std;
  492. vector<unsigned char> buffer = regulateNullBytes(doubleToBytes(value, hostLittleEndian()), 4);
  493. buffer.resize(nextpow2(buffer.size()), 0);
  494. unsigned char header = 0x20 | ilog2(buffer.size());
  495. buffer.push_back(header);
  496. reverse(buffer.begin(), buffer.end());
  497. d._objectTable.insert(d._objectTable.begin(), buffer.begin(), buffer.end());
  498. return buffer;
  499. }
  500. std::vector<unsigned char> writeBinaryBool(PlistHelperData& d, bool value)
  501. {
  502. std::vector<unsigned char> buffer;
  503. if(value)
  504. buffer.push_back(0x09);
  505. else
  506. buffer.push_back(0x08);
  507. d._objectTable.insert(d._objectTable.begin(), buffer.begin(), buffer.end());
  508. return buffer;
  509. }
  510. std::vector<unsigned char> writeBinaryDate(PlistHelperData& d, const Date& date)
  511. {
  512. std::vector<unsigned char> buffer;
  513. // need to serialize as Apple epoch.
  514. double macTime = date.timeAsAppleEpoch();
  515. buffer = doubleToBytes(macTime, false);
  516. buffer.insert(buffer.begin(), 0x33);
  517. d._objectTable.insert(d._objectTable.begin(), buffer.begin(), buffer.end());
  518. return buffer;
  519. }
  520. std::vector<unsigned char> writeBinaryInteger(PlistHelperData& d, int64_t value, bool write)
  521. {
  522. using namespace std;
  523. // The integer is initially forced to be 64 bit because it must be serialized
  524. // as 8 bytes if it is negative. If it is not negative, the
  525. // regulateNullBytes step will reduce the representation down to the min
  526. // power base 2 bytes needed to store it.
  527. vector<unsigned char> buffer = intToBytes<int64_t>(value, hostLittleEndian());
  528. buffer = regulateNullBytes(intToBytes<int64_t>(value, hostLittleEndian()), 1);
  529. buffer.resize(nextpow2(buffer.size()), 0);
  530. unsigned char header = 0x10 | ilog2(buffer.size());
  531. buffer.push_back(header);
  532. reverse(buffer.begin(), buffer.end());
  533. if(write)
  534. d._objectTable.insert(d._objectTable.begin(), buffer.begin(), buffer.end());
  535. return buffer;
  536. }
  537. std::vector<unsigned char> writeBinaryString(PlistHelperData& d, const std::string& value, bool head)
  538. {
  539. using namespace std;
  540. vector<unsigned char> buffer;
  541. buffer.reserve(value.size());
  542. for(std::string::const_iterator it = value.begin();
  543. it != value.end();
  544. ++it)
  545. buffer.push_back((unsigned char) *it);
  546. if(head)
  547. {
  548. vector<unsigned char> header;
  549. if (value.length() < 15)
  550. header.push_back(0x50 | ((unsigned char) value.length()));
  551. else
  552. {
  553. header.push_back(0x50 | 0xf);
  554. vector<unsigned char> theSize = writeBinaryInteger(d, buffer.size(), false);
  555. header.insert(header.end(), theSize.begin(), theSize.end());
  556. }
  557. buffer.insert(buffer.begin(), header.begin(), header.end());
  558. }
  559. d._objectTable.insert(d._objectTable.begin(), buffer.begin(), buffer.end());
  560. return buffer;
  561. }
  562. int countDictionary(const dictionary_type& dictionary)
  563. {
  564. using namespace std;
  565. int count = 0;
  566. for(dictionary_type::const_iterator it = dictionary.begin();
  567. it != dictionary.end();
  568. ++it)
  569. {
  570. ++count;
  571. count += countAny(it->second);
  572. }
  573. return count;
  574. }
  575. int countArray(const array_type& array)
  576. {
  577. using namespace std;
  578. int count = 0;
  579. for(array_type::const_iterator it = array.begin();
  580. it != array.end();
  581. ++it)
  582. count += countAny(*it);
  583. return count;
  584. }
  585. void readPlist(std::istream& stream, boost::any& message)
  586. {
  587. int start = stream.tellg();
  588. stream.seekg(0, std::ifstream::end);
  589. int size = ((int) stream.tellg()) - start;
  590. if(size > 0)
  591. {
  592. stream.seekg(0, std::ifstream::beg);
  593. std::vector<char> buffer(size);
  594. stream.read( (char *)&buffer[0], size );
  595. readPlist(&buffer[0], size, message);
  596. }
  597. else
  598. {
  599. throw Error("Can't read zero length data");
  600. }
  601. }
  602. void readPlist(const char* byteArrayTemp, int64_t size, boost::any& message)
  603. {
  604. using namespace std;
  605. const unsigned char* byteArray = (const unsigned char*) byteArrayTemp;
  606. if (!byteArray || (size == 0))
  607. throw Error("Plist: Empty plist data");
  608. // infer plist type from header. If it has the bplist00 header as first 8
  609. // bytes, then it's a binary plist. Otherwise, assume it's XML
  610. std::string magicHeader((const char*) byteArray, 8);
  611. if(magicHeader == "bplist00")
  612. {
  613. PlistHelperData d;
  614. parseTrailer(d, getRange(byteArray, size - 32, 32));
  615. d._objectTable = getRange(byteArray, 0, d._offsetTableOffset);
  616. std::vector<unsigned char> offsetTableBytes = getRange(byteArray, d._offsetTableOffset, size - d._offsetTableOffset - 32);
  617. parseOffsetTable(d, offsetTableBytes);
  618. message = parseBinary(d, 0);
  619. }
  620. else
  621. {
  622. pugi::xml_document doc;
  623. pugi::xml_parse_result result = doc.load_buffer(byteArray, (size_t)size);
  624. if(!result)
  625. throw Error((string("Plist: XML parsed with error ") + result.description()).c_str());
  626. pugi::xml_node rootNode = doc.child("plist").first_child();
  627. message = parse(rootNode);
  628. }
  629. }
  630. dictionary_type parseDictionary(pugi::xml_node& node)
  631. {
  632. using namespace std;
  633. dictionary_type dict;
  634. for(pugi::xml_node_iterator it = node.begin(); it != node.end(); ++it)
  635. {
  636. if(string("key") != it->name())
  637. throw Error("Plist: XML dictionary key expected but not found");
  638. string key(it->first_child().value());
  639. ++it;
  640. if(it == node.end())
  641. throw Error("Plist: XML dictionary value expected for key " + key + "but not found");
  642. else if(string("key") == it->name())
  643. throw Error("Plist: XML dictionary value expected for key " + key + "but found another key node");
  644. dict[key] = parse(*it);
  645. }
  646. return dict;
  647. }
  648. array_type parseArray(pugi::xml_node& node)
  649. {
  650. using namespace std;
  651. array_type array;
  652. for(pugi::xml_node_iterator it = node.begin(); it != node.end(); ++it)
  653. array.push_back(parse(*it));
  654. return array;
  655. }
  656. Date parseDate(pugi::xml_node& node)
  657. {
  658. Date date;
  659. date.setTimeFromXMLConvention(node.first_child().value());
  660. return date;
  661. }
  662. std::vector<char> base64Decode(const char* encodedData)
  663. {
  664. using namespace std;
  665. vector<char> data;
  666. insert_iterator<vector<char> > ii(data, data.begin());
  667. base64<char> b64;
  668. int state = 0;
  669. b64.get(encodedData, encodedData + strlen(encodedData), ii, state);
  670. return data;
  671. }
  672. void base64Encode(std::string& dataEncoded, const std::vector<char>& data)
  673. {
  674. using namespace std;
  675. dataEncoded.clear();
  676. insert_iterator<string> ii(dataEncoded, dataEncoded.begin());
  677. base64<char> b64;
  678. int state = 0;
  679. #if defined(_WIN32) || defined(_WIN64)
  680. b64.put(data.begin(), data.end(), ii, state , base64<>::crlf());
  681. #else
  682. b64.put(data.begin(), data.end(), ii, state , base64<>::lf());
  683. #endif
  684. }
  685. boost::any parse(pugi::xml_node& node)
  686. {
  687. using namespace std;
  688. string nodeName = node.name();
  689. boost::any result;
  690. if("dict" == nodeName)
  691. result = parseDictionary(node);
  692. else if("array" == nodeName)
  693. result = parseArray(node);
  694. else if("string" == nodeName)
  695. result = string(node.first_child().value());
  696. else if("integer" == nodeName)
  697. result = (int64_t) atoll(node.first_child().value());
  698. else if("real" == nodeName)
  699. result = atof(node.first_child().value());
  700. else if("false" == nodeName)
  701. result = bool(false);
  702. else if("true" == nodeName)
  703. result = bool(true);
  704. else if("data" == nodeName)
  705. result = base64Decode(node.first_child().value());
  706. else if("date" == nodeName)
  707. result = parseDate(node);
  708. else
  709. throw Error(string("Plist: XML unknown node type " + nodeName));
  710. return result;
  711. }
  712. void parseOffsetTable(PlistHelperData& d, const std::vector<unsigned char>& offsetTableBytes)
  713. {
  714. for (unsigned int i = 0; i < offsetTableBytes.size(); i += d._offsetByteSize)
  715. {
  716. std::vector<unsigned char> temp = getRange(offsetTableBytes, i, d._offsetByteSize);
  717. std::reverse(temp.begin(), temp.end());
  718. d._offsetTable.push_back(
  719. bytesToInt<int32_t>(
  720. vecData(regulateNullBytes(temp, 4)), hostLittleEndian()));
  721. }
  722. }
  723. void parseTrailer(PlistHelperData& d, const std::vector<unsigned char>& trailer)
  724. {
  725. d._offsetByteSize = bytesToInt<int32_t>(vecData(regulateNullBytes(getRange(trailer, 6, 1), 4)), hostLittleEndian());
  726. d._objRefSize = bytesToInt<int32_t>(vecData(regulateNullBytes(getRange(trailer, 7, 1), 4)), hostLittleEndian());
  727. std::vector<unsigned char> refCountBytes = getRange(trailer, 12, 4);
  728. // std::reverse(refCountBytes.begin(), refCountBytes.end());
  729. d._refCount = bytesToInt<int32_t>(vecData(refCountBytes), false);
  730. std::vector<unsigned char> offsetTableOffsetBytes = getRange(trailer, 24, 8);
  731. // std::reverse(offsetTableOffsetBytes.begin(), offsetTableOffsetBytes.end());
  732. d._offsetTableOffset = bytesToInt<int64_t>(vecData(offsetTableOffsetBytes), false);
  733. }
  734. std::vector<unsigned char> regulateNullBytes(const std::vector<unsigned char>& origBytes, unsigned int minBytes)
  735. {
  736. std::vector<unsigned char> bytes(origBytes);
  737. while((bytes.back() == 0) && (bytes.size() > minBytes))
  738. bytes.pop_back();
  739. while(bytes.size() < minBytes)
  740. bytes.push_back(0);
  741. return bytes;
  742. }
  743. boost::any parseBinary(const PlistHelperData& d, int objRef)
  744. {
  745. unsigned char header = d._objectTable[d._offsetTable[objRef]];
  746. switch (header & 0xF0)
  747. {
  748. case 0x00:
  749. {
  750. return parseBinaryBool(d, d._offsetTable[objRef]);
  751. }
  752. case 0x10:
  753. {
  754. int intByteCount;
  755. return parseBinaryInt(d, d._offsetTable[objRef], intByteCount);
  756. }
  757. case 0x20:
  758. {
  759. return parseBinaryReal(d, d._offsetTable[objRef]);
  760. }
  761. case 0x30:
  762. {
  763. return parseBinaryDate(d, d._offsetTable[objRef]);
  764. }
  765. case 0x40:
  766. {
  767. return parseBinaryByteArray(d, d._offsetTable[objRef]);
  768. }
  769. case 0x50:
  770. {
  771. return parseBinaryString(d, d._offsetTable[objRef]);
  772. }
  773. case 0x60:
  774. {
  775. return parseBinaryUnicode(d, d._offsetTable[objRef]);
  776. }
  777. case 0xD0:
  778. {
  779. return parseBinaryDictionary(d, objRef);
  780. }
  781. case 0xA0:
  782. {
  783. return parseBinaryArray(d, objRef);
  784. }
  785. }
  786. throw Error("This type is not supported");
  787. }
  788. std::vector<int32_t> getRefsForContainers(const PlistHelperData& d, int objRef)
  789. {
  790. using namespace std;
  791. int32_t refCount = 0;
  792. int refStartPosition;
  793. refCount = getCount(d, d._offsetTable[objRef], d._objectTable[d._offsetTable[objRef]], refStartPosition);
  794. refStartPosition += d._offsetTable[objRef];
  795. vector<int32_t> refs;
  796. int mult = 1;
  797. if((((unsigned char) d._objectTable[d._offsetTable[objRef]]) & 0xF0) == 0xD0)
  798. mult = 2;
  799. for (int i = refStartPosition; i < refStartPosition + refCount * mult * d._objRefSize; i += d._objRefSize)
  800. {
  801. std::vector<unsigned char> refBuffer = getRange(d._objectTable, i, d._objRefSize);
  802. reverse(refBuffer.begin(), refBuffer.end());
  803. refs.push_back(bytesToInt<int32_t>(vecData(regulateNullBytes(refBuffer, 4)), hostLittleEndian()));
  804. }
  805. return refs;
  806. }
  807. array_type parseBinaryArray(const PlistHelperData& d, int objRef)
  808. {
  809. using namespace std;
  810. vector<int32_t> refs = getRefsForContainers(d, objRef);
  811. int32_t refCount = refs.size();
  812. array_type array;
  813. for(int i = 0; i < refCount; ++i)
  814. array.push_back(parseBinary(d, refs[i]));
  815. return array;
  816. }
  817. dictionary_type parseBinaryDictionary(const PlistHelperData& d, int objRef)
  818. {
  819. using namespace std;
  820. vector<int32_t> refs = getRefsForContainers(d, objRef);
  821. int32_t refCount = refs.size() / 2;
  822. dictionary_type dict;
  823. for (int i = 0; i < refCount; i++)
  824. {
  825. boost::any keyAny = parseBinary(d, refs[i]);
  826. try
  827. {
  828. std::string& key = boost::any_cast<std::string&>(keyAny);
  829. dict[key] = parseBinary(d, refs[i + refCount]);
  830. }
  831. catch(boost::bad_any_cast& )
  832. {
  833. throw Error("Error parsing dictionary. Key can't be parsed as a string");
  834. }
  835. }
  836. return dict;
  837. }
  838. std::string parseBinaryString(const PlistHelperData& d, int headerPosition)
  839. {
  840. unsigned char headerByte = d._objectTable[headerPosition];
  841. int charStartPosition;
  842. int32_t charCount = getCount(d, headerPosition, headerByte, charStartPosition);
  843. charStartPosition += headerPosition;
  844. std::vector<unsigned char> characterBytes = getRange(d._objectTable, charStartPosition, charCount);
  845. std::string buffer = std::string((char*) vecData(characterBytes), characterBytes.size());
  846. return buffer;
  847. }
  848. std::string parseBinaryUnicode(const PlistHelperData& d, int headerPosition)
  849. {
  850. unsigned char headerByte = d._objectTable[headerPosition];
  851. int charStartPosition;
  852. int32_t charCount = getCount(d, headerPosition, headerByte, charStartPosition);
  853. charStartPosition += headerPosition;
  854. std::vector<unsigned char> characterBytes = getRange(d._objectTable, charStartPosition, charCount * 2);
  855. if (hostLittleEndian()) {
  856. if (! characterBytes.empty()) {
  857. for (std::size_t i = 0, n = characterBytes.size(); i < n - 1; i += 2)
  858. std::swap(characterBytes[i], characterBytes[i + 1]);
  859. }
  860. }
  861. int16_t *u16chars = (int16_t*) vecData(characterBytes);
  862. std::size_t u16len = characterBytes.size() / 2;
  863. std::string result = boost::locale::conv::utf_to_utf<char, int16_t>(u16chars, u16chars + u16len, boost::locale::conv::stop);
  864. return result;
  865. }
  866. int64_t parseBinaryInt(const PlistHelperData& d, int headerPosition, int& intByteCount)
  867. {
  868. unsigned char header = d._objectTable[headerPosition];
  869. intByteCount = 1 << (header & 0xf);
  870. std::vector<unsigned char> buffer = getRange(d._objectTable, headerPosition + 1, intByteCount);
  871. reverse(buffer.begin(), buffer.end());
  872. return bytesToInt<int64_t>(vecData(regulateNullBytes(buffer, 8)), hostLittleEndian());
  873. }
  874. double parseBinaryReal(const PlistHelperData& d, int headerPosition)
  875. {
  876. unsigned char header = d._objectTable[headerPosition];
  877. int byteCount = 1 << (header & 0xf);
  878. std::vector<unsigned char> buffer = getRange(d._objectTable, headerPosition + 1, byteCount);
  879. reverse(buffer.begin(), buffer.end());
  880. return bytesToDouble(vecData(regulateNullBytes(buffer, 8)), hostLittleEndian());
  881. }
  882. bool parseBinaryBool(const PlistHelperData& d, int headerPosition)
  883. {
  884. unsigned char header = d._objectTable[headerPosition];
  885. bool value;
  886. if(header == 0x09)
  887. value = true;
  888. else if (header == 0x08)
  889. value = false;
  890. else if (header == 0x00)
  891. {
  892. // null byte, not sure yet what to do with this. It's in the spec but we
  893. // have never encountered it.
  894. throw Error("Plist: null byte encountered, unsure how to parse");
  895. }
  896. else if (header == 0x0F)
  897. {
  898. // fill byte, not sure yet what to do with this. It's in the spec but we
  899. // have never encountered it.
  900. throw Error("Plist: fill byte encountered, unsure how to parse");
  901. }
  902. else
  903. {
  904. std::stringstream ss;
  905. ss<<"Plist: unknown header "<<header;
  906. throw Error(ss.str().c_str());
  907. }
  908. return value;
  909. }
  910. Date parseBinaryDate(const PlistHelperData& d, int headerPosition)
  911. {
  912. // date always an 8 byte float starting after full byte header
  913. std::vector<unsigned char> buffer = getRange(d._objectTable, headerPosition + 1, 8);
  914. Date date;
  915. // Date is stored as Apple Epoch and big endian.
  916. date.setTimeFromAppleEpoch(bytesToDouble(vecData(buffer), false));
  917. return date;
  918. }
  919. data_type parseBinaryByteArray(const PlistHelperData& d, int headerPosition)
  920. {
  921. unsigned char headerByte = d._objectTable[headerPosition];
  922. int byteStartPosition;
  923. int32_t byteCount = getCount(d, headerPosition, headerByte, byteStartPosition);
  924. byteStartPosition += headerPosition;
  925. return getRange((const char*) vecData(d._objectTable), byteStartPosition, byteCount);
  926. }
  927. int32_t getCount(const PlistHelperData& d, int bytePosition, unsigned char headerByte, int& startOffset)
  928. {
  929. unsigned char headerByteTrail = headerByte & 0xf;
  930. if (headerByteTrail < 15)
  931. {
  932. startOffset = 1;
  933. return headerByteTrail;
  934. }
  935. else
  936. {
  937. int32_t count = (int32_t)parseBinaryInt(d, bytePosition + 1, startOffset);
  938. startOffset += 2;
  939. return count;
  940. }
  941. }
  942. template<typename T>
  943. std::string stringFromValue(const T& value)
  944. {
  945. std::stringstream ss;
  946. ss<<value;
  947. return ss.str();
  948. }
  949. template <typename IntegerType>
  950. IntegerType bytesToInt(const unsigned char* bytes, bool littleEndian)
  951. {
  952. IntegerType result = 0;
  953. if (littleEndian)
  954. for (int n = sizeof( result ) - 1; n >= 0; n--)
  955. result = (result << 8) + bytes[n];
  956. else
  957. for (unsigned n = 0; n < sizeof( result ); n++)
  958. result = (result << 8) + bytes[n];
  959. return result;
  960. }
  961. double bytesToDouble(const unsigned char* bytes, bool littleEndian)
  962. {
  963. double result;
  964. int numBytes = sizeof(double);
  965. if(littleEndian)
  966. memcpy( &result, bytes, numBytes);
  967. else
  968. {
  969. std::vector<unsigned char> bytesReverse(numBytes);
  970. std::reverse_copy(bytes, bytes + numBytes, bytesReverse.begin());
  971. memcpy( &result, vecData(bytesReverse), numBytes);
  972. }
  973. return result;
  974. }
  975. std::vector<unsigned char> doubleToBytes(double val, bool littleEndian)
  976. {
  977. std::vector<unsigned char> result(sizeof(double));
  978. memcpy(vecData(result), &val, sizeof(double));
  979. if(!littleEndian)
  980. std::reverse(result.begin(), result.end());
  981. return result;
  982. }
  983. template<typename IntegerType>
  984. std::vector<unsigned char> intToBytes(IntegerType val, bool littleEndian)
  985. {
  986. unsigned int numBytes = sizeof(val);
  987. std::vector<unsigned char> bytes(numBytes);
  988. for(unsigned n = 0; n < numBytes; ++n)
  989. if(littleEndian)
  990. bytes[n] = (val >> 8 * n) & 0xff;
  991. else
  992. bytes[numBytes - 1 - n] = (val >> 8 * n) & 0xff;
  993. return bytes;
  994. }
  995. std::vector<unsigned char> getRange(const unsigned char* origBytes, int64_t index, int64_t size)
  996. {
  997. std::vector<unsigned char> result((std::vector<unsigned char>::size_type)size);
  998. std::copy(origBytes + index, origBytes + index + size, result.begin());
  999. return result;
  1000. }
  1001. std::vector<char> getRange(const char* origBytes, int64_t index, int64_t size)
  1002. {
  1003. std::vector<char> result((std::vector<char>::size_type)size);
  1004. std::copy(origBytes + index, origBytes + index + size, result.begin());
  1005. return result;
  1006. }
  1007. std::vector<unsigned char> getRange(const std::vector<unsigned char>& origBytes, int64_t index, int64_t size)
  1008. {
  1009. if((index + size) > (int64_t) origBytes.size())
  1010. throw Error("Out of bounds getRange");
  1011. return getRange(vecData(origBytes), index, size);
  1012. }
  1013. } // namespace Plist