1
0

serialization_utils.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  1. /*
  2. * serialization_utils.cpp
  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. #include "stdafx.h"
  10. #include "serialization_utils.h"
  11. #include "mpt/io/io.hpp"
  12. #include "mpt/io/io_stdstream.hpp"
  13. #include <array>
  14. #include <istream>
  15. #include <ostream>
  16. #include <sstream>
  17. #include "misc_util.h"
  18. OPENMPT_NAMESPACE_BEGIN
  19. namespace srlztn
  20. {
  21. #ifdef MPT_ALL_LOGGING
  22. #define SSB_LOGGING
  23. #endif
  24. #ifdef SSB_LOGGING
  25. #define SSB_LOG(x) MPT_LOG_GLOBAL(LogDebug, "serialization", x)
  26. #else
  27. #define SSB_LOG(x) do { } while(0)
  28. #endif
  29. static const uint8 HeaderId_FlagByte = 0;
  30. // Indexing starts from 0.
  31. static inline bool Testbit(uint8 val, uint8 bitindex) {return ((val & (1 << bitindex)) != 0);}
  32. static inline void Setbit(uint8& val, uint8 bitindex, bool newval)
  33. {
  34. if(newval) val |= (1 << bitindex);
  35. else val &= ~(1 << bitindex);
  36. }
  37. bool ID::IsPrintable() const
  38. {
  39. for(std::size_t i = 0; i < m_ID.length(); ++i)
  40. {
  41. if(m_ID[i] <= 0 || isprint(static_cast<unsigned char>(m_ID[i])) == 0)
  42. {
  43. return false;
  44. }
  45. }
  46. return true;
  47. }
  48. //Format: First bit tells whether the size indicator is 1 or 2 bytes.
  49. static void WriteAdaptive12String(std::ostream& oStrm, const std::string& str)
  50. {
  51. uint16 s = static_cast<uint16>(str.size());
  52. LimitMax(s, uint16(std::numeric_limits<uint16>::max() / 2));
  53. mpt::IO::WriteAdaptiveInt16LE(oStrm, s);
  54. oStrm.write(str.c_str(), s);
  55. }
  56. void WriteItemString(std::ostream& oStrm, const std::string &str)
  57. {
  58. uint32 id = static_cast<uint32>(std::min(str.size(), static_cast<std::size_t>((std::numeric_limits<uint32>::max() >> 4)))) << 4;
  59. id |= 12; // 12 == 1100b
  60. Binarywrite<uint32>(oStrm, id);
  61. id >>= 4;
  62. if(id > 0)
  63. oStrm.write(str.data(), id);
  64. }
  65. void ReadItemString(std::istream& iStrm, std::string& str, const DataSize)
  66. {
  67. // bits 0,1: Bytes per char type: 1,2,3,4.
  68. // bits 2,3: Bytes in size indicator, 1,2,3,4
  69. uint32 id = 0;
  70. Binaryread(iStrm, id, 1);
  71. const uint8 nSizeBytes = (id & 12) >> 2; // 12 == 1100b
  72. if (nSizeBytes > 0)
  73. {
  74. uint8 bytes = std::min(uint8(3), nSizeBytes);
  75. uint8 v2 = 0;
  76. uint8 v3 = 0;
  77. uint8 v4 = 0;
  78. if(bytes >= 1) Binaryread(iStrm, v2);
  79. if(bytes >= 2) Binaryread(iStrm, v3);
  80. if(bytes >= 3) Binaryread(iStrm, v4);
  81. id &= 0xff;
  82. id |= (v2 << 8) | (v3 << 16) | (v4 << 24);
  83. }
  84. // Limit to 1 MB.
  85. str.resize(std::min(id >> 4, uint32(1000000)));
  86. for(size_t i = 0; i < str.size(); i++)
  87. iStrm.read(&str[i], 1);
  88. id = (id >> 4) - static_cast<uint32>(str.size());
  89. if(id > 0)
  90. iStrm.ignore(id);
  91. }
  92. mpt::ustring ID::AsString() const
  93. {
  94. if(IsPrintable())
  95. {
  96. return mpt::ToUnicode(mpt::Charset::ISO8859_1, m_ID);
  97. }
  98. if(m_ID.length() > 8)
  99. {
  100. return mpt::ustring();
  101. }
  102. uint64le val;
  103. val.set(0);
  104. std::memcpy(&val, m_ID.data(), m_ID.length());
  105. return mpt::ufmt::val(val);
  106. }
  107. const char Ssb::s_EntryID[3] = {'2','2','8'};
  108. Ssb::Ssb()
  109. : m_Status(SNT_NONE)
  110. , m_nFixedEntrySize(0)
  111. , m_posStart(0)
  112. , m_nIdbytes(IdSizeVariable)
  113. , m_nCounter(0)
  114. , m_Flags((1 << RwfWMapStartPosEntry) + (1 << RwfWMapSizeEntry) + (1 << RwfWVersionNum))
  115. {
  116. return;
  117. }
  118. SsbWrite::SsbWrite(std::ostream& os)
  119. : oStrm(os)
  120. , m_posEntrycount(0)
  121. , m_posMapPosField(0)
  122. {
  123. return;
  124. }
  125. SsbRead::SsbRead(std::istream& is)
  126. : iStrm(is)
  127. , m_nReadVersion(0)
  128. , m_rposMapBegin(0)
  129. , m_posMapEnd(0)
  130. , m_posDataBegin(0)
  131. , m_rposEndofHdrData(0)
  132. , m_nReadEntrycount(0)
  133. , m_nNextReadHint(0)
  134. {
  135. return;
  136. }
  137. void SsbWrite::AddWriteNote(const SsbStatus s)
  138. {
  139. m_Status |= s;
  140. SSB_LOG(MPT_UFORMAT("{}: 0x{}")(U_("Write note: "), mpt::ufmt::hex(s)));
  141. }
  142. void SsbRead::AddReadNote(const SsbStatus s)
  143. {
  144. m_Status |= s;
  145. SSB_LOG(MPT_UFORMAT("{}: 0x{}")(U_("Read note: "), mpt::ufmt::hex(s)));
  146. }
  147. void SsbRead::AddReadNote(const ReadEntry* const pRe, const NumType nNum)
  148. {
  149. m_Status |= SNT_PROGRESS;
  150. SSB_LOG(MPT_UFORMAT("Read entry: {{num, id, rpos, size, desc}} = {{{}, {}, {}, {}, {}}}")(
  151. nNum,
  152. (pRe && pRe->nIdLength < 30 && m_Idarray.size() > 0) ? ID(&m_Idarray[pRe->nIdpos], pRe->nIdLength).AsString() : U_(""),
  153. (pRe) ? pRe->rposStart : 0,
  154. (pRe && pRe->nSize != invalidDatasize) ? mpt::ufmt::val(pRe->nSize) : U_(""),
  155. U_("")));
  156. #ifndef SSB_LOGGING
  157. MPT_UNREFERENCED_PARAMETER(pRe);
  158. MPT_UNREFERENCED_PARAMETER(nNum);
  159. #endif
  160. }
  161. // Called after writing an entry.
  162. void SsbWrite::AddWriteNote(const ID &id, const NumType nEntryNum, const DataSize nBytecount, const RposType rposStart)
  163. {
  164. m_Status |= SNT_PROGRESS;
  165. SSB_LOG(MPT_UFORMAT("Wrote entry: {{num, id, rpos, size}} = {{{}, {}, {}, {}}}")(nEntryNum, id.AsString(), rposStart, nBytecount));
  166. #ifndef SSB_LOGGING
  167. MPT_UNREFERENCED_PARAMETER(id);
  168. MPT_UNREFERENCED_PARAMETER(nEntryNum);
  169. MPT_UNREFERENCED_PARAMETER(nBytecount);
  170. MPT_UNREFERENCED_PARAMETER(rposStart);
  171. #endif
  172. }
  173. void SsbRead::ResetReadstatus()
  174. {
  175. m_Status = SNT_NONE;
  176. m_Idarray.reserve(32);
  177. m_Idarray.push_back(0);
  178. }
  179. void SsbWrite::WriteMapItem(const ID &id,
  180. const RposType& rposDataStart,
  181. const DataSize& nDatasize,
  182. const char* pszDesc)
  183. {
  184. SSB_LOG(MPT_UFORMAT("Writing map entry: id={}, rpos={}, size={}")(
  185. (id.GetSize() > 0) ? id.AsString() : U_(""),
  186. rposDataStart,
  187. nDatasize));
  188. std::ostringstream mapStream;
  189. if(m_nIdbytes > 0)
  190. {
  191. if (m_nIdbytes != IdSizeVariable && id.GetSize() != m_nIdbytes)
  192. { AddWriteNote(SNW_CHANGING_IDSIZE_WITH_FIXED_IDSIZESETTING); return; }
  193. if (m_nIdbytes == IdSizeVariable) //Variablesize ID?
  194. mpt::IO::WriteAdaptiveInt16LE(mapStream, static_cast<uint16>(id.GetSize()));
  195. if(id.GetSize() > 0)
  196. mapStream.write(id.GetBytes(), id.GetSize());
  197. }
  198. if (GetFlag(RwfWMapStartPosEntry)) //Startpos
  199. mpt::IO::WriteAdaptiveInt64LE(mapStream, rposDataStart);
  200. if (GetFlag(RwfWMapSizeEntry)) //Entrysize
  201. mpt::IO::WriteAdaptiveInt64LE(mapStream, nDatasize);
  202. if (GetFlag(RwfWMapDescEntry)) //Entry descriptions
  203. WriteAdaptive12String(mapStream, std::string(pszDesc));
  204. m_MapStreamString.append(mapStream.str());
  205. }
  206. void SsbWrite::IncrementWriteCounter()
  207. {
  208. m_nCounter++;
  209. if(m_nCounter >= static_cast<uint16>(std::numeric_limits<uint16>::max() >> 2))
  210. {
  211. FinishWrite();
  212. AddWriteNote(SNW_MAX_WRITE_COUNT_REACHED);
  213. }
  214. }
  215. void SsbWrite::BeginWrite(const ID &id, const uint64& nVersion)
  216. {
  217. SSB_LOG(MPT_UFORMAT("Write header with ID = {}")(id.AsString()));
  218. ResetWritestatus();
  219. if(!oStrm.good())
  220. { AddWriteNote(SNRW_BADGIVEN_STREAM); return; }
  221. // Start bytes.
  222. oStrm.write(s_EntryID, sizeof(s_EntryID));
  223. m_posStart = oStrm.tellp() - Offtype(sizeof(s_EntryID));
  224. // Object ID.
  225. {
  226. uint8 idsize = static_cast<uint8>(id.GetSize());
  227. Binarywrite<uint8>(oStrm, idsize);
  228. if(idsize > 0) oStrm.write(id.GetBytes(), id.GetSize());
  229. }
  230. // Form header.
  231. uint8 header = 0;
  232. SetFlag(RwfWMapStartPosEntry, GetFlag(RwfWMapStartPosEntry) && m_nFixedEntrySize == 0);
  233. SetFlag(RwfWMapSizeEntry, GetFlag(RwfWMapSizeEntry) && m_nFixedEntrySize == 0);
  234. header = (m_nIdbytes != 4) ? (m_nIdbytes & 3) : 3; //0,1 : Bytes per IDtype, 0,1,2,4
  235. Setbit(header, 2, GetFlag(RwfWMapStartPosEntry)); //2 : Startpos in map?
  236. Setbit(header, 3, GetFlag(RwfWMapSizeEntry)); //3 : Datasize in map?
  237. Setbit(header, 4, GetFlag(RwfWVersionNum)); //4 : Version numeric field?
  238. Setbit(header, 7, GetFlag(RwfWMapDescEntry)); //7 : Entrydescriptions in map?
  239. // Write header
  240. Binarywrite<uint8>(oStrm, header);
  241. // Additional options.
  242. uint8 tempU8 = 0;
  243. Setbit(tempU8, 0, (m_nIdbytes == IdSizeVariable) || (m_nIdbytes == 3) || (m_nIdbytes > 4));
  244. Setbit(tempU8, 1, m_nFixedEntrySize != 0);
  245. const uint8 flags = tempU8;
  246. if(flags != s_DefaultFlagbyte)
  247. {
  248. mpt::IO::WriteAdaptiveInt32LE(oStrm, 2); //Headersize - now it is 2.
  249. Binarywrite<uint8>(oStrm, HeaderId_FlagByte);
  250. Binarywrite<uint8>(oStrm, flags);
  251. }
  252. else
  253. mpt::IO::WriteAdaptiveInt32LE(oStrm, 0);
  254. if(Testbit(header, 4)) // Version(numeric)?
  255. mpt::IO::WriteAdaptiveInt64LE(oStrm, nVersion);
  256. if(Testbit(flags, 0)) // Custom IDbytecount?
  257. {
  258. uint8 n = (m_nIdbytes == IdSizeVariable) ? 1 : static_cast<uint8>((m_nIdbytes << 1));
  259. Binarywrite<uint8>(oStrm, n);
  260. }
  261. if(Testbit(flags, 1)) // Fixedsize entries?
  262. mpt::IO::WriteAdaptiveInt32LE(oStrm, m_nFixedEntrySize);
  263. //Entrycount. Reserve two bytes(max uint16_max / 4 entries), actual value is written after writing data.
  264. m_posEntrycount = oStrm.tellp();
  265. Binarywrite<uint16>(oStrm, 0);
  266. SetFlag(RwfRwHasMap, (m_nIdbytes != 0 || GetFlag(RwfWMapStartPosEntry) || GetFlag(RwfWMapSizeEntry) || GetFlag(RwfWMapDescEntry)));
  267. m_posMapPosField = oStrm.tellp();
  268. if (GetFlag(RwfRwHasMap)) //Mapping begin pos(reserve space - actual value is written after writing data)
  269. Binarywrite<uint64>(oStrm, 0);
  270. }
  271. SsbRead::ReadRv SsbRead::OnReadEntry(const ReadEntry* pE, const ID &id, const Postype& posReadBegin)
  272. {
  273. if (pE != nullptr)
  274. AddReadNote(pE, m_nCounter);
  275. else if (GetFlag(RwfRMapHasId) == false) // Not ID's in map.
  276. {
  277. ReadEntry e;
  278. e.rposStart = static_cast<RposType>(posReadBegin - m_posStart);
  279. e.nSize = static_cast<DataSize>(iStrm.tellg() - posReadBegin);
  280. AddReadNote(&e, m_nCounter);
  281. }
  282. else // Entry not found.
  283. {
  284. SSB_LOG(MPT_UFORMAT("No entry with id {} found.")(id.AsString()));
  285. #ifndef SSB_LOGGING
  286. MPT_UNREFERENCED_PARAMETER(id);
  287. #endif
  288. return EntryNotFound;
  289. }
  290. m_nCounter++;
  291. return EntryRead;
  292. }
  293. void SsbWrite::OnWroteItem(const ID &id, const Postype& posBeforeWrite)
  294. {
  295. const Offtype nRawEntrySize = oStrm.tellp() - posBeforeWrite;
  296. MPT_MAYBE_CONSTANT_IF(nRawEntrySize < 0 || static_cast<uint64>(nRawEntrySize) > std::numeric_limits<DataSize>::max())
  297. {
  298. AddWriteNote(SNW_INSUFFICIENT_DATASIZETYPE);
  299. return;
  300. }
  301. if(GetFlag(RwfRMapHasSize) && (nRawEntrySize < 0 || static_cast<uint64>(nRawEntrySize) > (std::numeric_limits<DataSize>::max() >> 2)))
  302. { AddWriteNote(SNW_DATASIZETYPE_OVERFLOW); return; }
  303. DataSize nEntrySize = static_cast<DataSize>(nRawEntrySize);
  304. // Handle fixed size entries:
  305. if (m_nFixedEntrySize > 0)
  306. {
  307. if(nEntrySize <= m_nFixedEntrySize)
  308. {
  309. for(uint32 i = 0; i<m_nFixedEntrySize-nEntrySize; i++)
  310. oStrm.put(0);
  311. nEntrySize = m_nFixedEntrySize;
  312. }
  313. else
  314. { AddWriteNote(SNW_INSUFFICIENT_FIXEDSIZE); return; }
  315. }
  316. if (GetFlag(RwfRwHasMap))
  317. WriteMapItem(id, static_cast<RposType>(posBeforeWrite - m_posStart), nEntrySize, "");
  318. AddWriteNote(id, m_nCounter, nEntrySize, static_cast<RposType>(posBeforeWrite - m_posStart));
  319. IncrementWriteCounter();
  320. }
  321. void SsbRead::BeginRead(const ID &id, const uint64& nVersion)
  322. {
  323. SSB_LOG(MPT_UFORMAT("Read header with expected ID = {}")(id.AsString()));
  324. ResetReadstatus();
  325. if (!iStrm.good())
  326. { AddReadNote(SNRW_BADGIVEN_STREAM); return; }
  327. m_posStart = iStrm.tellg();
  328. // Start bytes.
  329. {
  330. char temp[sizeof(s_EntryID)];
  331. ArrayReader<char>(sizeof(s_EntryID))(iStrm, temp, sizeof(s_EntryID));
  332. if(std::memcmp(temp, s_EntryID, sizeof(s_EntryID)))
  333. {
  334. AddReadNote(SNR_STARTBYTE_MISMATCH);
  335. return;
  336. }
  337. }
  338. // Compare IDs.
  339. uint8 storedIdLen = 0;
  340. Binaryread<uint8>(iStrm, storedIdLen);
  341. std::array<char, 256> storedIdBuf;
  342. storedIdBuf = {};
  343. if(storedIdLen > 0)
  344. {
  345. iStrm.read(storedIdBuf.data(), storedIdLen);
  346. }
  347. if(!(id == ID(storedIdBuf.data(), storedIdLen)))
  348. {
  349. AddReadNote(SNR_OBJECTCLASS_IDMISMATCH);
  350. }
  351. if ((m_Status & SNT_FAILURE) != 0)
  352. {
  353. SSB_LOG(U_("ID mismatch, terminating read."));
  354. return;
  355. }
  356. SSB_LOG(U_("ID match, continuing reading."));
  357. // Header
  358. uint8 tempU8;
  359. Binaryread<uint8>(iStrm, tempU8);
  360. const uint8 header = tempU8;
  361. m_nIdbytes = ((header & 3) == 3) ? 4 : (header & 3);
  362. if (Testbit(header, 6))
  363. SetFlag(RwfRTwoBytesDescChar, true);
  364. // Read headerdata size
  365. uint32 tempU32 = 0;
  366. mpt::IO::ReadAdaptiveInt32LE(iStrm, tempU32);
  367. const uint32 headerdatasize = tempU32;
  368. // If headerdatasize != 0, read known headerdata and ignore rest.
  369. uint8 flagbyte = s_DefaultFlagbyte;
  370. if(headerdatasize >= 2)
  371. {
  372. Binaryread<uint8>(iStrm, tempU8);
  373. if(tempU8 == HeaderId_FlagByte)
  374. Binaryread<uint8>(iStrm, flagbyte);
  375. iStrm.ignore( (tempU8 == HeaderId_FlagByte) ? headerdatasize - 2 : headerdatasize - 1);
  376. }
  377. uint64 tempU64 = 0;
  378. // Read version numeric if available.
  379. if (Testbit(header, 4))
  380. {
  381. mpt::IO::ReadAdaptiveInt64LE(iStrm, tempU64);
  382. m_nReadVersion = tempU64;
  383. if(tempU64 > nVersion)
  384. AddReadNote(SNR_LOADING_OBJECT_WITH_LARGER_VERSION);
  385. }
  386. if (Testbit(header, 5))
  387. {
  388. Binaryread<uint8>(iStrm, tempU8);
  389. iStrm.ignore(tempU8);
  390. }
  391. if(Testbit(flagbyte, 0)) // Custom ID?
  392. {
  393. Binaryread<uint8>(iStrm, tempU8);
  394. if ((tempU8 & 1) != 0)
  395. m_nIdbytes = IdSizeVariable;
  396. else
  397. m_nIdbytes = (tempU8 >> 1);
  398. if(m_nIdbytes == 0)
  399. AddReadNote(SNR_NO_ENTRYIDS_WITH_CUSTOMID_DEFINED);
  400. }
  401. m_nFixedEntrySize = 0;
  402. if(Testbit(flagbyte, 1)) // Fixedsize entries?
  403. mpt::IO::ReadAdaptiveInt32LE(iStrm, m_nFixedEntrySize);
  404. SetFlag(RwfRMapHasStartpos, Testbit(header, 2));
  405. SetFlag(RwfRMapHasSize, Testbit(header, 3));
  406. SetFlag(RwfRMapHasId, (m_nIdbytes > 0));
  407. SetFlag(RwfRMapHasDesc, Testbit(header, 7));
  408. SetFlag(RwfRwHasMap, GetFlag(RwfRMapHasId) || GetFlag(RwfRMapHasStartpos) || GetFlag(RwfRMapHasSize) || GetFlag(RwfRMapHasDesc));
  409. if (GetFlag(RwfRwHasMap) == false)
  410. {
  411. SSB_LOG(U_("No map in the file."));
  412. }
  413. if (Testbit(flagbyte, 2)) // Object description?
  414. {
  415. uint16 size = 0;
  416. mpt::IO::ReadAdaptiveInt16LE(iStrm, size);
  417. iStrm.ignore(size * (GetFlag(RwfRTwoBytesDescChar) ? 2 : 1));
  418. }
  419. if(Testbit(flagbyte, 3))
  420. iStrm.ignore(5);
  421. // Read entrycount
  422. mpt::IO::ReadAdaptiveInt64LE(iStrm, tempU64);
  423. if(tempU64 > 16000)
  424. // The current code can only write 16383 entries because it uses a Adaptive64LE with a fixed size=2
  425. // Additionally, 16000 is an arbitrary limit to avoid an out-of-memory DoS when caching the map.
  426. { AddReadNote(SNR_TOO_MANY_ENTRIES_TO_READ); return; }
  427. m_nReadEntrycount = static_cast<NumType>(tempU64);
  428. if(m_nReadEntrycount == 0)
  429. AddReadNote(SNR_ZEROENTRYCOUNT);
  430. // Read map rpos if map exists.
  431. if (GetFlag(RwfRwHasMap))
  432. {
  433. mpt::IO::ReadAdaptiveInt64LE(iStrm, tempU64);
  434. if(tempU64 > static_cast<uint64>(std::numeric_limits<Offtype>::max()))
  435. { AddReadNote(SNR_INSUFFICIENT_STREAM_OFFTYPE); return; }
  436. }
  437. const Offtype rawEndOfHdrData = iStrm.tellg() - m_posStart;
  438. MPT_MAYBE_CONSTANT_IF(rawEndOfHdrData < 0 || static_cast<uint64>(rawEndOfHdrData) > std::numeric_limits<RposType>::max())
  439. {
  440. AddReadNote(SNR_INSUFFICIENT_RPOSTYPE);
  441. return;
  442. }
  443. m_rposEndofHdrData = static_cast<RposType>(rawEndOfHdrData);
  444. m_rposMapBegin = (GetFlag(RwfRwHasMap)) ? static_cast<RposType>(tempU64) : m_rposEndofHdrData;
  445. if (GetFlag(RwfRwHasMap) == false)
  446. m_posMapEnd = m_posStart + m_rposEndofHdrData;
  447. SetFlag(RwfRHeaderIsRead, true);
  448. }
  449. void SsbRead::CacheMap()
  450. {
  451. if(GetFlag(RwfRwHasMap) || m_nFixedEntrySize > 0)
  452. {
  453. iStrm.seekg(m_posStart + m_rposMapBegin);
  454. if(iStrm.fail())
  455. { AddReadNote(SNR_BADSTREAM_AFTER_MAPHEADERSEEK); return; }
  456. SSB_LOG(MPT_UFORMAT("Reading map from rpos: {}")(m_rposMapBegin));
  457. mapData.resize(m_nReadEntrycount);
  458. m_Idarray.reserve(m_nReadEntrycount * 4);
  459. //Read map
  460. for(NumType i = 0; i<m_nReadEntrycount; i++)
  461. {
  462. if(iStrm.fail())
  463. { AddReadNote(SNR_BADSTREAM_AT_MAP_READ); return; }
  464. // Read ID.
  465. uint16 nIdsize = m_nIdbytes;
  466. if(nIdsize == IdSizeVariable) //Variablesize ID
  467. mpt::IO::ReadAdaptiveInt16LE(iStrm, nIdsize);
  468. const size_t nOldEnd = m_Idarray.size();
  469. if (nIdsize > 0 && (Util::MaxValueOfType(nOldEnd) - nOldEnd >= nIdsize))
  470. {
  471. m_Idarray.resize(nOldEnd + nIdsize);
  472. iStrm.read(&m_Idarray[nOldEnd], nIdsize);
  473. }
  474. mapData[i].nIdLength = nIdsize;
  475. mapData[i].nIdpos = nOldEnd;
  476. // Read position.
  477. if(GetFlag(RwfRMapHasStartpos))
  478. {
  479. uint64 tempU64;
  480. mpt::IO::ReadAdaptiveInt64LE(iStrm, tempU64);
  481. if(tempU64 > static_cast<uint64>(std::numeric_limits<Offtype>::max()))
  482. { AddReadNote(SNR_INSUFFICIENT_STREAM_OFFTYPE); return; }
  483. mapData[i].rposStart = static_cast<RposType>(tempU64);
  484. }
  485. // Read entry size.
  486. if (m_nFixedEntrySize > 0)
  487. mapData[i].nSize = m_nFixedEntrySize;
  488. else if(GetFlag(RwfRMapHasSize)) // Map has datasize field.
  489. {
  490. uint64 tempU64;
  491. mpt::IO::ReadAdaptiveInt64LE(iStrm, tempU64);
  492. if(tempU64 > static_cast<uint64>(std::numeric_limits<Offtype>::max()))
  493. { AddReadNote(SNR_INSUFFICIENT_STREAM_OFFTYPE); return; }
  494. mapData[i].nSize = static_cast<DataSize>(tempU64);
  495. }
  496. // If there's no entry startpos in map, count start pos from datasizes.
  497. // Here readentry.rposStart is set to relative position from databegin.
  498. if (mapData[i].nSize != invalidDatasize && GetFlag(RwfRMapHasStartpos) == false)
  499. mapData[i].rposStart = (i > 0) ? mapData[i-1].rposStart + mapData[i-1].nSize : 0;
  500. if(GetFlag(RwfRMapHasDesc)) //Map has entrydescriptions?
  501. {
  502. uint16 size = 0;
  503. mpt::IO::ReadAdaptiveInt16LE(iStrm, size);
  504. if(GetFlag(RwfRTwoBytesDescChar))
  505. iStrm.ignore(size * 2);
  506. else
  507. iStrm.ignore(size);
  508. }
  509. }
  510. m_posMapEnd = iStrm.tellg();
  511. SSB_LOG(MPT_UFORMAT("End of map(rpos): {}")(m_posMapEnd - m_posStart));
  512. }
  513. SetFlag(RwfRMapCached, true);
  514. m_posDataBegin = (m_rposMapBegin == m_rposEndofHdrData) ? m_posMapEnd : m_posStart + Postype(m_rposEndofHdrData);
  515. iStrm.seekg(m_posDataBegin);
  516. // If there are no positions in the map but there are entry sizes, rposStart will
  517. // be relative to data start. Now that posDataBegin is known, make them relative to
  518. // startpos.
  519. if (GetFlag(RwfRMapHasStartpos) == false && (GetFlag(RwfRMapHasSize) || m_nFixedEntrySize > 0))
  520. {
  521. const RposType offset = static_cast<RposType>(m_posDataBegin - m_posStart);
  522. for(size_t i = 0; i < m_nReadEntrycount; i++)
  523. mapData[i].rposStart += offset;
  524. }
  525. }
  526. const ReadEntry* SsbRead::Find(const ID &id)
  527. {
  528. iStrm.clear();
  529. if (GetFlag(RwfRMapCached) == false)
  530. CacheMap();
  531. if (m_nFixedEntrySize > 0 && GetFlag(RwfRMapHasStartpos) == false && GetFlag(RwfRMapHasSize) == false)
  532. iStrm.seekg(m_posDataBegin + Postype(m_nFixedEntrySize * m_nCounter));
  533. if (GetFlag(RwfRMapHasId) == true)
  534. {
  535. const size_t nEntries = mapData.size();
  536. for(size_t i0 = 0; i0 < nEntries; i0++)
  537. {
  538. const size_t i = (i0 + m_nNextReadHint) % nEntries;
  539. if(mapData[i].nIdpos < m_Idarray.size() && id == ID(&m_Idarray[mapData[i].nIdpos], mapData[i].nIdLength))
  540. {
  541. m_nNextReadHint = (i + 1) % nEntries;
  542. if (mapData[i].rposStart != 0)
  543. iStrm.seekg(m_posStart + Postype(mapData[i].rposStart));
  544. return &mapData[i];
  545. }
  546. }
  547. }
  548. return nullptr;
  549. }
  550. void SsbWrite::FinishWrite()
  551. {
  552. const Postype posDataEnd = oStrm.tellp();
  553. Postype posMapStart = oStrm.tellp();
  554. SSB_LOG(MPT_UFORMAT("Writing map to rpos: {}")(posMapStart - m_posStart));
  555. if (GetFlag(RwfRwHasMap)) //Write map
  556. {
  557. oStrm.write(m_MapStreamString.c_str(), m_MapStreamString.length());
  558. }
  559. const Postype posMapEnd = oStrm.tellp();
  560. // Write entry count.
  561. oStrm.seekp(m_posEntrycount);
  562. // Write a fixed size=2 Adaptive64LE because space for this value has already been reserved berforehand.
  563. mpt::IO::WriteAdaptiveInt64LE(oStrm, m_nCounter, 2);
  564. if (GetFlag(RwfRwHasMap))
  565. { // Write map start position.
  566. oStrm.seekp(m_posMapPosField);
  567. const uint64 rposMap = posMapStart - m_posStart;
  568. // Write a fixed size=8 Adaptive64LE because space for this value has already been reserved berforehand.
  569. mpt::IO::WriteAdaptiveInt64LE(oStrm, rposMap, 8);
  570. }
  571. // Seek to end.
  572. oStrm.seekp(std::max(posMapEnd, posDataEnd));
  573. SSB_LOG(MPT_UFORMAT("End of stream(rpos): {}")(oStrm.tellp() - m_posStart));
  574. }
  575. } // namespace srlztn
  576. OPENMPT_NAMESPACE_END