1
0

serialization_utils.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. /*
  2. * serialization_utils.h
  3. * ---------------------
  4. * Purpose: Serializing data to and from MPTM files.
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #pragma once
  10. #include "openmpt/all/BuildSettings.hpp"
  11. #include "mpt/io/io.hpp"
  12. #include "mpt/io/io_stdstream.hpp"
  13. #include "openmpt/base/Endian.hpp"
  14. #include "../common/mptBaseTypes.h"
  15. #include <algorithm>
  16. #include <bitset>
  17. #include <ios>
  18. #include <iosfwd>
  19. #include <limits>
  20. #include <string>
  21. #include <vector>
  22. #include <istream>
  23. #include <ostream>
  24. #include <cstring>
  25. OPENMPT_NAMESPACE_BEGIN
  26. namespace srlztn //SeRiaLiZaTioN
  27. {
  28. typedef std::ios::off_type Offtype;
  29. typedef Offtype Postype;
  30. typedef uintptr_t DataSize; // Data size type.
  31. typedef uintptr_t RposType; // Relative position type.
  32. typedef uintptr_t NumType; // Entry count type.
  33. const DataSize invalidDatasize = DataSize(-1);
  34. enum
  35. {
  36. SNT_PROGRESS = 0x08000000, // = 1 << 27
  37. SNT_FAILURE = 0x40000000, // = 1 << 30
  38. SNT_NOTE = 0x20000000, // = 1 << 29
  39. SNT_WARNING = 0x10000000, // = 1 << 28
  40. SNT_NONE = 0,
  41. SNRW_BADGIVEN_STREAM = 1 | SNT_FAILURE,
  42. // Read failures.
  43. SNR_BADSTREAM_AFTER_MAPHEADERSEEK = 2 | SNT_FAILURE,
  44. SNR_STARTBYTE_MISMATCH = 3 | SNT_FAILURE,
  45. SNR_BADSTREAM_AT_MAP_READ = 4 | SNT_FAILURE,
  46. SNR_INSUFFICIENT_STREAM_OFFTYPE = 5 | SNT_FAILURE,
  47. SNR_OBJECTCLASS_IDMISMATCH = 6 | SNT_FAILURE,
  48. SNR_TOO_MANY_ENTRIES_TO_READ = 7 | SNT_FAILURE,
  49. SNR_INSUFFICIENT_RPOSTYPE = 8 | SNT_FAILURE,
  50. // Read notes and warnings.
  51. SNR_ZEROENTRYCOUNT = 0x80 | SNT_NOTE, // 0x80 == 1 << 7
  52. SNR_NO_ENTRYIDS_WITH_CUSTOMID_DEFINED = 0x100 | SNT_NOTE,
  53. SNR_LOADING_OBJECT_WITH_LARGER_VERSION = 0x200 | SNT_NOTE,
  54. // Write failures.
  55. SNW_INSUFFICIENT_FIXEDSIZE = (0x10) | SNT_FAILURE,
  56. SNW_CHANGING_IDSIZE_WITH_FIXED_IDSIZESETTING = (0x11) | SNT_FAILURE,
  57. SNW_DATASIZETYPE_OVERFLOW = (0x13) | SNT_FAILURE,
  58. SNW_MAX_WRITE_COUNT_REACHED = (0x14) | SNT_FAILURE,
  59. SNW_INSUFFICIENT_DATASIZETYPE = (0x16) | SNT_FAILURE
  60. };
  61. enum
  62. {
  63. IdSizeVariable = std::numeric_limits<uint16>::max(),
  64. IdSizeMaxFixedSize = (std::numeric_limits<uint8>::max() >> 1)
  65. };
  66. typedef int32 SsbStatus;
  67. struct ReadEntry
  68. {
  69. ReadEntry() : nIdpos(0), rposStart(0), nSize(invalidDatasize), nIdLength(0) {}
  70. uintptr_t nIdpos; // Index of id start in ID array.
  71. RposType rposStart; // Entry start position.
  72. DataSize nSize; // Entry size.
  73. uint16 nIdLength; // Length of id.
  74. };
  75. enum Rwf
  76. {
  77. RwfWMapStartPosEntry, // Write. True to include data start pos entry to map.
  78. RwfWMapSizeEntry, // Write. True to include data size entry to map.
  79. RwfWMapDescEntry, // Write. True to include description entry to map.
  80. RwfWVersionNum, // Write. True to include version numeric.
  81. RwfRMapCached, // Read. True if map has been cached.
  82. RwfRMapHasId, // Read. True if map has IDs
  83. RwfRMapHasStartpos, // Read. True if map data start pos.
  84. RwfRMapHasSize, // Read. True if map has entry size.
  85. RwfRMapHasDesc, // Read. True if map has entry description.
  86. RwfRTwoBytesDescChar, // Read. True if map description characters are two bytes.
  87. RwfRHeaderIsRead, // Read. True when header is read.
  88. RwfRwHasMap, // Read/write. True if map exists.
  89. RwfNumFlags
  90. };
  91. template<class T>
  92. inline void Binarywrite(std::ostream& oStrm, const T& data)
  93. {
  94. mpt::IO::WriteIntLE(oStrm, data);
  95. }
  96. template<>
  97. inline void Binarywrite(std::ostream& oStrm, const float& data)
  98. {
  99. IEEE754binary32LE tmp = IEEE754binary32LE(data);
  100. mpt::IO::Write(oStrm, tmp);
  101. }
  102. template<>
  103. inline void Binarywrite(std::ostream& oStrm, const double& data)
  104. {
  105. IEEE754binary64LE tmp = IEEE754binary64LE(data);
  106. mpt::IO::Write(oStrm, tmp);
  107. }
  108. template <class T>
  109. inline void WriteItem(std::ostream& oStrm, const T& data)
  110. {
  111. static_assert(std::is_trivial<T>::value == true, "");
  112. Binarywrite(oStrm, data);
  113. }
  114. void WriteItemString(std::ostream& oStrm, const std::string &str);
  115. template <>
  116. inline void WriteItem<std::string>(std::ostream& oStrm, const std::string& str) {WriteItemString(oStrm, str);}
  117. template<class T>
  118. inline void Binaryread(std::istream& iStrm, T& data)
  119. {
  120. mpt::IO::ReadIntLE(iStrm, data);
  121. }
  122. template<>
  123. inline void Binaryread(std::istream& iStrm, float& data)
  124. {
  125. IEEE754binary32LE tmp = IEEE754binary32LE(0.0f);
  126. mpt::IO::Read(iStrm, tmp);
  127. data = tmp;
  128. }
  129. template<>
  130. inline void Binaryread(std::istream& iStrm, double& data)
  131. {
  132. IEEE754binary64LE tmp = IEEE754binary64LE(0.0);
  133. mpt::IO::Read(iStrm, tmp);
  134. data = tmp;
  135. }
  136. //Read only given number of bytes to the beginning of data; data bytes are memset to 0 before reading.
  137. template <class T>
  138. inline void Binaryread(std::istream& iStrm, T& data, const Offtype bytecount)
  139. {
  140. mpt::IO::ReadBinaryTruncatedLE(iStrm, data, static_cast<std::size_t>(bytecount));
  141. }
  142. template <>
  143. inline void Binaryread<float>(std::istream& iStrm, float& data, const Offtype bytecount)
  144. {
  145. typedef IEEE754binary32LE T;
  146. std::byte bytes[sizeof(T)];
  147. std::memset(bytes, 0, sizeof(T));
  148. mpt::IO::ReadRaw(iStrm, bytes, std::min(static_cast<std::size_t>(bytecount), sizeof(T)));
  149. // There is not much we can sanely do for truncated floats,
  150. // thus we ignore what we just read and return 0.
  151. data = 0.0f;
  152. }
  153. template <>
  154. inline void Binaryread<double>(std::istream& iStrm, double& data, const Offtype bytecount)
  155. {
  156. typedef IEEE754binary64LE T;
  157. std::byte bytes[sizeof(T)];
  158. std::memset(bytes, 0, sizeof(T));
  159. mpt::IO::ReadRaw(iStrm, bytes, std::min(static_cast<std::size_t>(bytecount), sizeof(T)));
  160. // There is not much we can sanely do for truncated floats,
  161. // thus we ignore what we just read and return 0.
  162. data = 0.0;
  163. }
  164. template <class T>
  165. inline void ReadItem(std::istream& iStrm, T& data, const DataSize nSize)
  166. {
  167. static_assert(std::is_trivial<T>::value == true, "");
  168. if (nSize == sizeof(T) || nSize == invalidDatasize)
  169. Binaryread(iStrm, data);
  170. else
  171. Binaryread(iStrm, data, nSize);
  172. }
  173. void ReadItemString(std::istream& iStrm, std::string& str, const DataSize);
  174. template <>
  175. inline void ReadItem<std::string>(std::istream& iStrm, std::string& str, const DataSize nSize)
  176. {
  177. ReadItemString(iStrm, str, nSize);
  178. }
  179. class ID
  180. {
  181. private:
  182. std::string m_ID; // NOTE: can contain null characters ('\0')
  183. public:
  184. ID() { }
  185. ID(const std::string &id) : m_ID(id) { }
  186. ID(const char *beg, const char *end) : m_ID(beg, end) { }
  187. ID(const char *id) : m_ID(id?id:"") { }
  188. ID(const char * str, std::size_t len) : m_ID(str, str + len) { }
  189. template <typename T>
  190. static ID FromInt(const T &val)
  191. {
  192. static_assert(std::numeric_limits<T>::is_integer);
  193. typename mpt::make_le<T>::type valle;
  194. valle = val;
  195. return ID(std::string(mpt::byte_cast<const char*>(mpt::as_raw_memory(valle).data()), mpt::byte_cast<const char*>(mpt::as_raw_memory(valle).data() + sizeof(valle))));
  196. }
  197. bool IsPrintable() const;
  198. mpt::ustring AsString() const;
  199. const char *GetBytes() const { return m_ID.c_str(); }
  200. std::size_t GetSize() const { return m_ID.length(); }
  201. bool operator == (const ID &other) const { return m_ID == other.m_ID; }
  202. bool operator != (const ID &other) const { return m_ID != other.m_ID; }
  203. };
  204. class Ssb
  205. {
  206. protected:
  207. Ssb();
  208. public:
  209. SsbStatus GetStatus() const
  210. {
  211. return m_Status;
  212. }
  213. protected:
  214. // When writing, returns the number of entries written.
  215. // When reading, returns the number of entries read not including unrecognized entries.
  216. NumType GetCounter() const {return m_nCounter;}
  217. void SetFlag(Rwf flag, bool val) {m_Flags.set(flag, val);}
  218. bool GetFlag(Rwf flag) const {return m_Flags[flag];}
  219. protected:
  220. SsbStatus m_Status;
  221. uint32 m_nFixedEntrySize; // Read/write: If > 0, data entries have given fixed size.
  222. Postype m_posStart; // Read/write: Stream position at the beginning of object.
  223. uint16 m_nIdbytes; // Read/Write: Tells map ID entry size in bytes. If size is variable, value is IdSizeVariable.
  224. NumType m_nCounter; // Read/write: Keeps count of entries written/read.
  225. std::bitset<RwfNumFlags> m_Flags; // Read/write: Various flags.
  226. protected:
  227. enum : uint8 { s_DefaultFlagbyte = 0 };
  228. static const char s_EntryID[3];
  229. };
  230. class SsbRead
  231. : public Ssb
  232. {
  233. public:
  234. enum ReadRv // Read return value.
  235. {
  236. EntryRead,
  237. EntryNotFound
  238. };
  239. enum IdMatchStatus
  240. {
  241. IdMatch, IdMismatch
  242. };
  243. typedef std::vector<ReadEntry>::const_iterator ReadIterator;
  244. SsbRead(std::istream& iStrm);
  245. // Call this to begin reading: must be called before other read functions.
  246. void BeginRead(const ID &id, const uint64& nVersion);
  247. // After calling BeginRead(), this returns number of entries in the file.
  248. NumType GetNumEntries() const {return m_nReadEntrycount;}
  249. // Returns read iterator to the beginning of entries.
  250. // The behaviour of read iterators is undefined if map doesn't
  251. // contain entry ids or data begin positions.
  252. ReadIterator GetReadBegin();
  253. // Returns read iterator to the end(one past last) of entries.
  254. ReadIterator GetReadEnd();
  255. // Compares given id with read entry id
  256. IdMatchStatus CompareId(const ReadIterator& iter, const ID &id);
  257. uint64 GetReadVersion() {return m_nReadVersion;}
  258. // Read item using default read implementation.
  259. template <class T>
  260. ReadRv ReadItem(T& obj, const ID &id) {return ReadItem(obj, id, srlztn::ReadItem<T>);}
  261. // Read item using given function.
  262. template <class T, class FuncObj>
  263. ReadRv ReadItem(T& obj, const ID &id, FuncObj);
  264. // Read item using read iterator.
  265. template <class T>
  266. ReadRv ReadIterItem(const ReadIterator& iter, T& obj) {return ReadIterItem(iter, obj, srlztn::ReadItem<T>);}
  267. template <class T, class FuncObj>
  268. ReadRv ReadIterItem(const ReadIterator& iter, T& obj, FuncObj func);
  269. private:
  270. // Reads map to cache.
  271. void CacheMap();
  272. // Searches for entry with given ID. If found, returns pointer to corresponding entry, else
  273. // returns nullptr.
  274. const ReadEntry* Find(const ID &id);
  275. // Called after reading an object.
  276. ReadRv OnReadEntry(const ReadEntry* pE, const ID &id, const Postype& posReadBegin);
  277. void AddReadNote(const SsbStatus s);
  278. // Called after reading entry. pRe is a pointer to associated map entry if exists.
  279. void AddReadNote(const ReadEntry* const pRe, const NumType nNum);
  280. void ResetReadstatus();
  281. private:
  282. // mapData is a cache that facilitates faster access to the stored data
  283. // without having to reparse on every access.
  284. // Iterator invalidation in CacheMap() is not a problem because every code
  285. // path that ever returns an iterator into mapData does CacheMap exactly once
  286. // beforehand. Following calls use this already cached map. As the data is
  287. // immutable when reading, there is no need to ever invalidate the cache and
  288. // redo CacheMap().
  289. std::istream& iStrm;
  290. std::vector<char> m_Idarray; // Read: Holds entry ids.
  291. std::vector<ReadEntry> mapData; // Read: Contains map information.
  292. uint64 m_nReadVersion; // Read: Version is placed here when reading.
  293. RposType m_rposMapBegin; // Read: If map exists, rpos of map begin, else m_rposEndofHdrData.
  294. Postype m_posMapEnd; // Read: If map exists, map end position, else pos of end of hdrData.
  295. Postype m_posDataBegin; // Read: Data begin position.
  296. RposType m_rposEndofHdrData; // Read: rpos of end of header data.
  297. NumType m_nReadEntrycount; // Read: Number of entries.
  298. NumType m_nNextReadHint; // Read: Hint where to start looking for the next read entry.
  299. };
  300. class SsbWrite
  301. : public Ssb
  302. {
  303. public:
  304. SsbWrite(std::ostream& oStrm);
  305. // Write header
  306. void BeginWrite(const ID &id, const uint64& nVersion);
  307. // Write item using default write implementation.
  308. template <class T>
  309. void WriteItem(const T& obj, const ID &id) {WriteItem(obj, id, &srlztn::WriteItem<T>);}
  310. // Write item using given function.
  311. template <class T, class FuncObj>
  312. void WriteItem(const T& obj, const ID &id, FuncObj);
  313. // Writes mapping.
  314. void FinishWrite();
  315. private:
  316. // Called after writing an item.
  317. void OnWroteItem(const ID &id, const Postype& posBeforeWrite);
  318. void AddWriteNote(const SsbStatus s);
  319. void AddWriteNote(const ID &id,
  320. const NumType nEntryNum,
  321. const DataSize nBytecount,
  322. const RposType rposStart);
  323. // Writes mapping item to mapstream.
  324. void WriteMapItem(const ID &id,
  325. const RposType& rposDataStart,
  326. const DataSize& nDatasize,
  327. const char* pszDesc);
  328. void ResetWritestatus() {m_Status = SNT_NONE;}
  329. void IncrementWriteCounter();
  330. private:
  331. std::ostream& oStrm;
  332. Postype m_posEntrycount; // Write: Pos of entrycount field.
  333. Postype m_posMapPosField; // Write: Pos of map position field.
  334. std::string m_MapStreamString; // Write: Map stream string.
  335. };
  336. template <class T, class FuncObj>
  337. void SsbWrite::WriteItem(const T& obj, const ID &id, FuncObj Func)
  338. {
  339. const Postype pos = oStrm.tellp();
  340. Func(oStrm, obj);
  341. OnWroteItem(id, pos);
  342. }
  343. template <class T, class FuncObj>
  344. SsbRead::ReadRv SsbRead::ReadItem(T& obj, const ID &id, FuncObj Func)
  345. {
  346. const ReadEntry* pE = Find(id);
  347. const Postype pos = iStrm.tellg();
  348. if (pE != nullptr || GetFlag(RwfRMapHasId) == false)
  349. Func(iStrm, obj, (pE) ? (pE->nSize) : invalidDatasize);
  350. return OnReadEntry(pE, id, pos);
  351. }
  352. template <class T, class FuncObj>
  353. SsbRead::ReadRv SsbRead::ReadIterItem(const ReadIterator& iter, T& obj, FuncObj func)
  354. {
  355. iStrm.clear();
  356. if (iter->rposStart != 0)
  357. iStrm.seekg(m_posStart + Postype(iter->rposStart));
  358. const Postype pos = iStrm.tellg();
  359. func(iStrm, obj, iter->nSize);
  360. return OnReadEntry(&(*iter), ID(&m_Idarray[iter->nIdpos], iter->nIdLength), pos);
  361. }
  362. inline SsbRead::IdMatchStatus SsbRead::CompareId(const ReadIterator& iter, const ID &id)
  363. {
  364. if(iter->nIdpos >= m_Idarray.size()) return IdMismatch;
  365. return (id == ID(&m_Idarray[iter->nIdpos], iter->nIdLength)) ? IdMatch : IdMismatch;
  366. }
  367. inline SsbRead::ReadIterator SsbRead::GetReadBegin()
  368. {
  369. MPT_ASSERT(GetFlag(RwfRMapHasId) && (GetFlag(RwfRMapHasStartpos) || GetFlag(RwfRMapHasSize) || m_nFixedEntrySize > 0));
  370. if (GetFlag(RwfRMapCached) == false)
  371. CacheMap();
  372. return mapData.begin();
  373. }
  374. inline SsbRead::ReadIterator SsbRead::GetReadEnd()
  375. {
  376. if (GetFlag(RwfRMapCached) == false)
  377. CacheMap();
  378. return mapData.end();
  379. }
  380. template <class T>
  381. struct VectorWriter
  382. {
  383. VectorWriter(size_t nCount) : m_nCount(nCount) {}
  384. void operator()(std::ostream &oStrm, const std::vector<T> &vec)
  385. {
  386. for(size_t i = 0; i < m_nCount; i++)
  387. {
  388. Binarywrite(oStrm, vec[i]);
  389. }
  390. }
  391. size_t m_nCount;
  392. };
  393. template <class T>
  394. struct VectorReader
  395. {
  396. VectorReader(size_t nCount) : m_nCount(nCount) {}
  397. void operator()(std::istream& iStrm, std::vector<T> &vec, const size_t)
  398. {
  399. vec.resize(m_nCount);
  400. for(std::size_t i = 0; i < m_nCount; ++i)
  401. {
  402. Binaryread(iStrm, vec[i]);
  403. }
  404. }
  405. size_t m_nCount;
  406. };
  407. template <class T>
  408. struct ArrayReader
  409. {
  410. ArrayReader(size_t nCount) : m_nCount(nCount) {}
  411. void operator()(std::istream& iStrm, T* pData, const size_t)
  412. {
  413. for(std::size_t i=0; i<m_nCount; ++i)
  414. {
  415. Binaryread(iStrm, pData[i]);
  416. }
  417. }
  418. size_t m_nCount;
  419. };
  420. } //namespace srlztn.
  421. OPENMPT_NAMESPACE_END