ChunkFile.h 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. // Copyright 2008 Dolphin Emulator Project
  2. // Licensed under GPLv2+
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. // Extremely simple serialization framework.
  6. // (mis)-features:
  7. // + Super fast
  8. // + Very simple
  9. // + Same code is used for serialization and deserializaition (in most cases)
  10. // - Zero backwards/forwards compatibility
  11. // - Serialization code for anything complex has to be manually written.
  12. #include <array>
  13. #include <cstddef>
  14. #include <deque>
  15. #include <list>
  16. #include <map>
  17. #include <set>
  18. #include <string>
  19. #include <type_traits>
  20. #include <utility>
  21. #include <vector>
  22. #include "Common/CommonTypes.h"
  23. #include "Common/FileUtil.h"
  24. #include "Common/Flag.h"
  25. // ewww
  26. #if _LIBCPP_VERSION || __GNUC__ >= 5
  27. #define IsTriviallyCopyable(T) std::is_trivially_copyable<typename std::remove_volatile<T>::type>::value
  28. #elif __GNUC__
  29. #define IsTriviallyCopyable(T) std::has_trivial_copy_constructor<T>::value
  30. #elif _MSC_VER >= 1800
  31. // work around bug
  32. #define IsTriviallyCopyable(T) (std::is_trivially_copyable<T>::value || std::is_pod<T>::value)
  33. #elif defined(_MSC_VER)
  34. #define IsTriviallyCopyable(T) std::has_trivial_copy<T>::value
  35. #else
  36. #error No version of is_trivially_copyable
  37. #endif
  38. template <class T>
  39. struct LinkedListItem : public T
  40. {
  41. LinkedListItem<T> *next;
  42. };
  43. // Wrapper class
  44. class PointerWrap
  45. {
  46. public:
  47. enum Mode
  48. {
  49. MODE_READ = 1, // load
  50. MODE_WRITE, // save
  51. MODE_MEASURE, // calculate size
  52. MODE_VERIFY, // compare
  53. };
  54. u8 **ptr;
  55. Mode mode;
  56. public:
  57. PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_) {}
  58. void SetMode(Mode mode_) { mode = mode_; }
  59. Mode GetMode() const { return mode; }
  60. u8** GetPPtr() { return ptr; }
  61. template <typename K, class V>
  62. void Do(std::map<K, V>& x)
  63. {
  64. u32 count = (u32)x.size();
  65. Do(count);
  66. switch (mode)
  67. {
  68. case MODE_READ:
  69. for (x.clear(); count != 0; --count)
  70. {
  71. std::pair<K, V> pair;
  72. Do(pair.first);
  73. Do(pair.second);
  74. x.insert(pair);
  75. }
  76. break;
  77. case MODE_WRITE:
  78. case MODE_MEASURE:
  79. case MODE_VERIFY:
  80. for (auto& elem : x)
  81. {
  82. Do(elem.first);
  83. Do(elem.second);
  84. }
  85. break;
  86. }
  87. }
  88. template <typename V>
  89. void Do(std::set<V>& x)
  90. {
  91. u32 count = (u32)x.size();
  92. Do(count);
  93. switch (mode)
  94. {
  95. case MODE_READ:
  96. for (x.clear(); count != 0; --count)
  97. {
  98. V value;
  99. Do(value);
  100. x.insert(value);
  101. }
  102. break;
  103. case MODE_WRITE:
  104. case MODE_MEASURE:
  105. case MODE_VERIFY:
  106. for (V& val : x)
  107. {
  108. Do(val);
  109. }
  110. break;
  111. }
  112. }
  113. template <typename T>
  114. void Do(std::vector<T>& x)
  115. {
  116. DoContainer(x);
  117. }
  118. template <typename T>
  119. void Do(std::list<T>& x)
  120. {
  121. DoContainer(x);
  122. }
  123. template <typename T>
  124. void Do(std::deque<T>& x)
  125. {
  126. DoContainer(x);
  127. }
  128. template <typename T>
  129. void Do(std::basic_string<T>& x)
  130. {
  131. DoContainer(x);
  132. }
  133. template <typename T, typename U>
  134. void Do(std::pair<T, U>& x)
  135. {
  136. Do(x.first);
  137. Do(x.second);
  138. }
  139. template <typename T, std::size_t N>
  140. void DoArray(std::array<T, N>& x)
  141. {
  142. DoArray(x.data(), (u32)x.size());
  143. }
  144. template <typename T>
  145. void DoArray(T* x, u32 count)
  146. {
  147. static_assert(IsTriviallyCopyable(T), "Only sane for trivially copyable types");
  148. DoVoid(x, count * sizeof(T));
  149. }
  150. void Do(Common::Flag& flag)
  151. {
  152. bool s = flag.IsSet();
  153. Do(s);
  154. if (mode == MODE_READ)
  155. flag.Set(s);
  156. }
  157. template<typename T>
  158. void Do(std::atomic<T>& atomic)
  159. {
  160. T temp = atomic.load();
  161. Do(temp);
  162. if (mode == MODE_READ)
  163. atomic.store(temp);
  164. }
  165. template <typename T>
  166. void Do(T& x)
  167. {
  168. static_assert(IsTriviallyCopyable(T), "Only sane for trivially copyable types");
  169. // Note:
  170. // Usually we can just use x = **ptr, etc. However, this doesn't work
  171. // for unions containing BitFields (long story, stupid language rules)
  172. // or arrays. This will get optimized anyway.
  173. DoVoid((void*)&x, sizeof(x));
  174. }
  175. template <typename T>
  176. void DoPOD(T& x)
  177. {
  178. DoVoid((void*)&x, sizeof(x));
  179. }
  180. template <typename T>
  181. void DoPointer(T*& x, T* const base)
  182. {
  183. // pointers can be more than 2^31 apart, but you're using this function wrong if you need that much range
  184. ptrdiff_t offset = x - base;
  185. Do(offset);
  186. if (mode == MODE_READ)
  187. {
  188. x = base + offset;
  189. }
  190. }
  191. // Let's pretend std::list doesn't exist!
  192. template <class T, LinkedListItem<T>* (*TNew)(), void (*TFree)(LinkedListItem<T>*), void (*TDo)(PointerWrap&, T*)>
  193. void DoLinkedList(LinkedListItem<T>*& list_start, LinkedListItem<T>** list_end=0)
  194. {
  195. LinkedListItem<T>* list_cur = list_start;
  196. LinkedListItem<T>* prev = nullptr;
  197. while (true)
  198. {
  199. u8 shouldExist = (list_cur ? 1 : 0);
  200. Do(shouldExist);
  201. if (shouldExist == 1)
  202. {
  203. LinkedListItem<T>* cur = list_cur ? list_cur : TNew();
  204. TDo(*this, (T*)cur);
  205. if (!list_cur)
  206. {
  207. if (mode == MODE_READ)
  208. {
  209. cur->next = nullptr;
  210. list_cur = cur;
  211. if (prev)
  212. prev->next = cur;
  213. else
  214. list_start = cur;
  215. }
  216. else
  217. {
  218. TFree(cur);
  219. continue;
  220. }
  221. }
  222. }
  223. else
  224. {
  225. if (mode == MODE_READ)
  226. {
  227. if (prev)
  228. prev->next = nullptr;
  229. if (list_end)
  230. *list_end = prev;
  231. if (list_cur)
  232. {
  233. if (list_start == list_cur)
  234. list_start = nullptr;
  235. do
  236. {
  237. LinkedListItem<T>* next = list_cur->next;
  238. TFree(list_cur);
  239. list_cur = next;
  240. } while (list_cur);
  241. }
  242. }
  243. break;
  244. }
  245. prev = list_cur;
  246. list_cur = list_cur->next;
  247. }
  248. }
  249. void DoMarker(const std::string& prevName, u32 arbitraryNumber = 0x42)
  250. {
  251. u32 cookie = arbitraryNumber;
  252. Do(cookie);
  253. if (mode == PointerWrap::MODE_READ && cookie != arbitraryNumber)
  254. {
  255. PanicAlertT("Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...",
  256. prevName.c_str(), cookie, cookie, arbitraryNumber, arbitraryNumber);
  257. mode = PointerWrap::MODE_MEASURE;
  258. }
  259. }
  260. private:
  261. template <typename T>
  262. void DoContainer(T& x)
  263. {
  264. u32 size = (u32)x.size();
  265. Do(size);
  266. x.resize(size);
  267. for (auto& elem : x)
  268. Do(elem);
  269. }
  270. __forceinline
  271. void DoVoid(void *data, u32 size)
  272. {
  273. switch (mode)
  274. {
  275. case MODE_READ:
  276. memcpy(data, *ptr, size);
  277. break;
  278. case MODE_WRITE:
  279. memcpy(*ptr, data, size);
  280. break;
  281. case MODE_MEASURE:
  282. break;
  283. case MODE_VERIFY:
  284. _dbg_assert_msg_(COMMON, !memcmp(data, *ptr, size),
  285. "Savestate verification failure: buf %p != %p (size %u).\n",
  286. data, *ptr, size);
  287. break;
  288. }
  289. *ptr += size;
  290. }
  291. };
  292. // NOTE: this class is only used in DolphinWX/ISOFile.cpp for caching loaded
  293. // ISO data. It will be removed when DolphinWX is, so please don't use it.
  294. class CChunkFileReader
  295. {
  296. public:
  297. // Load file template
  298. template<class T>
  299. static bool Load(const std::string& _rFilename, u32 _Revision, T& _class)
  300. {
  301. INFO_LOG(COMMON, "ChunkReader: Loading %s", _rFilename.c_str());
  302. if (!File::Exists(_rFilename))
  303. return false;
  304. // Check file size
  305. const u64 fileSize = File::GetSize(_rFilename);
  306. static const u64 headerSize = sizeof(SChunkHeader);
  307. if (fileSize < headerSize)
  308. {
  309. ERROR_LOG(COMMON, "ChunkReader: File too small");
  310. return false;
  311. }
  312. File::IOFile pFile(_rFilename, "rb");
  313. if (!pFile)
  314. {
  315. ERROR_LOG(COMMON, "ChunkReader: Can't open file for reading");
  316. return false;
  317. }
  318. // read the header
  319. SChunkHeader header;
  320. if (!pFile.ReadArray(&header, 1))
  321. {
  322. ERROR_LOG(COMMON, "ChunkReader: Bad header size");
  323. return false;
  324. }
  325. // Check revision
  326. if (header.Revision != _Revision)
  327. {
  328. ERROR_LOG(COMMON, "ChunkReader: Wrong file revision, got %d expected %d",
  329. header.Revision, _Revision);
  330. return false;
  331. }
  332. // get size
  333. const u32 sz = (u32)(fileSize - headerSize);
  334. if (header.ExpectedSize != sz)
  335. {
  336. ERROR_LOG(COMMON, "ChunkReader: Bad file size, got %d expected %d",
  337. sz, header.ExpectedSize);
  338. return false;
  339. }
  340. // read the state
  341. std::vector<u8> buffer(sz);
  342. if (!pFile.ReadArray(&buffer[0], sz))
  343. {
  344. ERROR_LOG(COMMON, "ChunkReader: Error reading file");
  345. return false;
  346. }
  347. u8* ptr = &buffer[0];
  348. PointerWrap p(&ptr, PointerWrap::MODE_READ);
  349. _class.DoState(p);
  350. INFO_LOG(COMMON, "ChunkReader: Done loading %s", _rFilename.c_str());
  351. return true;
  352. }
  353. // Save file template
  354. template<class T>
  355. static bool Save(const std::string& _rFilename, u32 _Revision, T& _class)
  356. {
  357. INFO_LOG(COMMON, "ChunkReader: Writing %s", _rFilename.c_str());
  358. File::IOFile pFile(_rFilename, "wb");
  359. if (!pFile)
  360. {
  361. ERROR_LOG(COMMON, "ChunkReader: Error opening file for write");
  362. return false;
  363. }
  364. // Get data
  365. u8 *ptr = nullptr;
  366. PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
  367. _class.DoState(p);
  368. size_t const sz = (size_t)ptr;
  369. std::vector<u8> buffer(sz);
  370. ptr = &buffer[0];
  371. p.SetMode(PointerWrap::MODE_WRITE);
  372. _class.DoState(p);
  373. // Create header
  374. SChunkHeader header;
  375. header.Revision = _Revision;
  376. header.ExpectedSize = (u32)sz;
  377. // Write to file
  378. if (!pFile.WriteArray(&header, 1))
  379. {
  380. ERROR_LOG(COMMON, "ChunkReader: Failed writing header");
  381. return false;
  382. }
  383. if (!pFile.WriteArray(&buffer[0], sz))
  384. {
  385. ERROR_LOG(COMMON, "ChunkReader: Failed writing data");
  386. return false;
  387. }
  388. INFO_LOG(COMMON, "ChunkReader: Done writing %s", _rFilename.c_str());
  389. return true;
  390. }
  391. private:
  392. struct SChunkHeader
  393. {
  394. u32 Revision;
  395. u32 ExpectedSize;
  396. };
  397. };