tuningCollection.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /*
  2. * tuningCollection.cpp
  3. * --------------------
  4. * Purpose: Alternative sample tuning collection class.
  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 "tuningcollection.h"
  11. #include "mpt/io/io.hpp"
  12. #include "mpt/io/io_stdstream.hpp"
  13. #include "../common/serialization_utils.h"
  14. #include <algorithm>
  15. #include "../common/mptFileIO.h"
  16. #include "Loaders.h"
  17. #ifdef MODPLUG_TRACKER
  18. #include "../mptrack/TrackerSettings.h"
  19. #endif //MODPLUG_TRACKER
  20. OPENMPT_NAMESPACE_BEGIN
  21. namespace Tuning {
  22. /*
  23. Version history:
  24. 2->3: Serialization revamp(August 2007)
  25. 1->2: Sizetypes of string serialisation from size_t(uint32)
  26. to uint8. (March 2007)
  27. */
  28. namespace CTuningS11n
  29. {
  30. void ReadStr(std::istream &iStrm, mpt::ustring &ustr, const std::size_t dummy, mpt::Charset charset);
  31. void WriteStr(std::ostream &oStrm, const mpt::ustring &ustr);
  32. } // namespace CTuningS11n
  33. using namespace CTuningS11n;
  34. static void ReadTuning(std::istream &iStrm, CTuningCollection &Tc, const std::size_t dummy, mpt::Charset defaultCharset)
  35. {
  36. MPT_UNREFERENCED_PARAMETER(dummy);
  37. Tc.AddTuning(iStrm, defaultCharset);
  38. }
  39. static void WriteTuning(std::ostream& oStrm, const CTuning& t)
  40. {
  41. t.Serialize(oStrm);
  42. }
  43. CTuning* CTuningCollection::GetTuning(const mpt::ustring &name)
  44. {
  45. for(std::size_t i = 0; i<m_Tunings.size(); i++)
  46. {
  47. if(m_Tunings[i]->GetName() == name)
  48. {
  49. return m_Tunings[i].get();
  50. }
  51. }
  52. return nullptr;
  53. }
  54. const CTuning* CTuningCollection::GetTuning(const mpt::ustring &name) const
  55. {
  56. for(std::size_t i = 0; i<m_Tunings.size(); i++)
  57. {
  58. if(m_Tunings[i]->GetName() == name)
  59. {
  60. return m_Tunings[i].get();
  61. }
  62. }
  63. return nullptr;
  64. }
  65. Tuning::SerializationResult CTuningCollection::Serialize(std::ostream& oStrm, const mpt::ustring &name) const
  66. {
  67. srlztn::SsbWrite ssb(oStrm);
  68. ssb.BeginWrite("TC", 3); // version
  69. ssb.WriteItem(int8(1), "UTF8");
  70. ssb.WriteItem(name, "0", &WriteStr);
  71. uint16 dummyEditMask = 0xffff;
  72. ssb.WriteItem(dummyEditMask, "1");
  73. const size_t tcount = m_Tunings.size();
  74. for(size_t i = 0; i<tcount; i++)
  75. ssb.WriteItem(*m_Tunings[i], "2", &WriteTuning);
  76. ssb.FinishWrite();
  77. if(ssb.GetStatus() & srlztn::SNT_FAILURE)
  78. return Tuning::SerializationResult::Failure;
  79. else
  80. return Tuning::SerializationResult::Success;
  81. }
  82. Tuning::SerializationResult CTuningCollection::Deserialize(std::istream &iStrm, mpt::ustring &name, mpt::Charset defaultCharset)
  83. {
  84. std::istream::pos_type startpos = iStrm.tellg();
  85. const Tuning::SerializationResult oldLoadingResult = DeserializeOLD(iStrm, name, defaultCharset);
  86. if(oldLoadingResult == Tuning::SerializationResult::NoMagic)
  87. { // An old version was not recognised - trying new version.
  88. iStrm.clear();
  89. iStrm.seekg(startpos);
  90. srlztn::SsbRead ssb(iStrm);
  91. ssb.BeginRead("TC", 3); // version
  92. int8 use_utf8 = 0;
  93. ssb.ReadItem(use_utf8, "UTF8");
  94. const mpt::Charset charset = use_utf8 ? mpt::Charset::UTF8 : defaultCharset;
  95. const srlztn::SsbRead::ReadIterator iterBeg = ssb.GetReadBegin();
  96. const srlztn::SsbRead::ReadIterator iterEnd = ssb.GetReadEnd();
  97. for(srlztn::SsbRead::ReadIterator iter = iterBeg; iter != iterEnd; iter++)
  98. {
  99. uint16 dummyEditMask = 0xffff;
  100. if (ssb.CompareId(iter, "0") == srlztn::SsbRead::IdMatch)
  101. ssb.ReadIterItem(iter, name, [charset](std::istream &iStrm, mpt::ustring &ustr, const std::size_t dummy){ return ReadStr(iStrm, ustr, dummy, charset); });
  102. else if (ssb.CompareId(iter, "1") == srlztn::SsbRead::IdMatch)
  103. ssb.ReadIterItem(iter, dummyEditMask);
  104. else if (ssb.CompareId(iter, "2") == srlztn::SsbRead::IdMatch)
  105. ssb.ReadIterItem(iter, *this, [charset](std::istream &iStrm, CTuningCollection &Tc, const std::size_t dummy){ return ReadTuning(iStrm, Tc, dummy, charset); });
  106. }
  107. if(ssb.GetStatus() & srlztn::SNT_FAILURE)
  108. return Tuning::SerializationResult::Failure;
  109. else
  110. return Tuning::SerializationResult::Success;
  111. }
  112. else
  113. {
  114. return oldLoadingResult;
  115. }
  116. }
  117. Tuning::SerializationResult CTuningCollection::DeserializeOLD(std::istream &inStrm, mpt::ustring &uname, mpt::Charset defaultCharset)
  118. {
  119. //1. begin marker:
  120. uint32 beginMarker = 0;
  121. mpt::IO::ReadIntLE<uint32>(inStrm, beginMarker);
  122. if(beginMarker != MagicBE("TCSH")) // Magic is reversed in file, hence BE
  123. return Tuning::SerializationResult::NoMagic;
  124. //2. version
  125. int32 version = 0;
  126. mpt::IO::ReadIntLE<int32>(inStrm, version);
  127. if(version > 2 || version < 1)
  128. return Tuning::SerializationResult::Failure;
  129. //3. Name
  130. if(version < 2)
  131. {
  132. std::string name;
  133. if(!mpt::IO::ReadSizedStringLE<uint32>(inStrm, name, 256))
  134. return Tuning::SerializationResult::Failure;
  135. uname = mpt::ToUnicode(defaultCharset, name);
  136. }
  137. else
  138. {
  139. std::string name;
  140. if(!mpt::IO::ReadSizedStringLE<uint8>(inStrm, name))
  141. return Tuning::SerializationResult::Failure;
  142. uname = mpt::ToUnicode(defaultCharset, name);
  143. }
  144. //4. Editmask
  145. int16 em = 0;
  146. mpt::IO::ReadIntLE<int16>(inStrm, em);
  147. //Not assigning the value yet, for if it sets some property const,
  148. //further loading might fail.
  149. //5. Tunings
  150. {
  151. uint32 s = 0;
  152. mpt::IO::ReadIntLE<uint32>(inStrm, s);
  153. if(s > 50)
  154. return Tuning::SerializationResult::Failure;
  155. for(size_t i = 0; i<s; i++)
  156. {
  157. if(!AddTuning(inStrm, defaultCharset))
  158. {
  159. return Tuning::SerializationResult::Failure;
  160. }
  161. }
  162. }
  163. //6. End marker
  164. uint32 endMarker = 0;
  165. mpt::IO::ReadIntLE<uint32>(inStrm, endMarker);
  166. if(endMarker != MagicBE("TCSF")) // Magic is reversed in file, hence BE
  167. return Tuning::SerializationResult::Failure;
  168. return Tuning::SerializationResult::Success;
  169. }
  170. bool CTuningCollection::Remove(const CTuning *pT)
  171. {
  172. const auto it = std::find_if(m_Tunings.begin(), m_Tunings.end(),
  173. [&] (const std::unique_ptr<CTuning> & upT) -> bool
  174. {
  175. return upT.get() == pT;
  176. }
  177. );
  178. if(it == m_Tunings.end())
  179. {
  180. return false;
  181. }
  182. m_Tunings.erase(it);
  183. return true;
  184. }
  185. bool CTuningCollection::Remove(const std::size_t i)
  186. {
  187. if(i >= m_Tunings.size())
  188. {
  189. return false;
  190. }
  191. m_Tunings.erase(m_Tunings.begin() + i);
  192. return true;
  193. }
  194. CTuning* CTuningCollection::AddTuning(std::unique_ptr<CTuning> pT)
  195. {
  196. if(m_Tunings.size() >= s_nMaxTuningCount)
  197. {
  198. return nullptr;
  199. }
  200. if(!pT)
  201. {
  202. return nullptr;
  203. }
  204. CTuning *result = pT.get();
  205. m_Tunings.push_back(std::move(pT));
  206. return result;
  207. }
  208. CTuning* CTuningCollection::AddTuning(std::istream &inStrm, mpt::Charset defaultCharset)
  209. {
  210. if(m_Tunings.size() >= s_nMaxTuningCount)
  211. {
  212. return nullptr;
  213. }
  214. if(!inStrm.good())
  215. {
  216. return nullptr;
  217. }
  218. std::unique_ptr<CTuning> pT = CTuning::CreateDeserializeOLD(inStrm, defaultCharset);
  219. if(!pT)
  220. {
  221. pT = CTuning::CreateDeserialize(inStrm, defaultCharset);
  222. }
  223. if(!pT)
  224. {
  225. return nullptr;
  226. }
  227. CTuning *result = pT.get();
  228. m_Tunings.push_back(std::move(pT));
  229. return result;
  230. }
  231. #ifdef MODPLUG_TRACKER
  232. bool UnpackTuningCollection(const CTuningCollection &tc, const mpt::PathString &prefix)
  233. {
  234. bool error = false;
  235. auto numberFmt = mpt::FormatSpec().Dec().FillNul().Width(1 + static_cast<int>(std::log10(tc.GetNumTunings())));
  236. for(std::size_t i = 0; i < tc.GetNumTunings(); ++i)
  237. {
  238. const CTuning & tuning = *(tc.GetTuning(i));
  239. mpt::PathString fn;
  240. fn += prefix;
  241. mpt::ustring tuningName = tuning.GetName();
  242. if(tuningName.empty())
  243. {
  244. tuningName = U_("untitled");
  245. }
  246. SanitizeFilename(tuningName);
  247. fn += mpt::PathString::FromUnicode(MPT_UFORMAT("{} - {}")(mpt::ufmt::fmt(i + 1, numberFmt), tuningName));
  248. fn += mpt::PathString::FromUTF8(CTuning::s_FileExtension);
  249. if(fn.FileOrDirectoryExists())
  250. {
  251. error = true;
  252. } else
  253. {
  254. mpt::SafeOutputFile sfout(fn, std::ios::binary, mpt::FlushModeFromBool(TrackerSettings::Instance().MiscFlushFileBuffersOnSave));
  255. if(tuning.Serialize(sfout) != Tuning::SerializationResult::Success)
  256. {
  257. error = true;
  258. }
  259. }
  260. }
  261. return !error;
  262. }
  263. #endif
  264. } // namespace Tuning
  265. OPENMPT_NAMESPACE_END