chunk_file.h 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  1. // Copyright (C) 2003 Dolphin Project.
  2. // This program is free software: you can redistribute it and/or modify
  3. // it under the terms of the GNU General Public License as published by
  4. // the Free Software Foundation, version 2.0 or later versions.
  5. // This program is distributed in the hope that it will be useful,
  6. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. // GNU General Public License 2.0 for more details.
  9. // A copy of the GPL 2.0 should have been included with the program.
  10. // If not, see http://www.gnu.org/licenses/
  11. // Official SVN repository and contact information can be found at
  12. // http://code.google.com/p/dolphin-emu/
  13. #ifndef _POINTERWRAP_H_
  14. #define _POINTERWRAP_H_
  15. // Extremely simple serialization framework.
  16. // (mis)-features:
  17. // + Super fast
  18. // + Very simple
  19. // + Same code is used for serialization and deserializaition (in most cases)
  20. // - Zero backwards/forwards compatibility
  21. // - Serialization code for anything complex has to be manually written.
  22. #include <map>
  23. #include <vector>
  24. #include <deque>
  25. #include <string>
  26. #include <list>
  27. #include <set>
  28. #ifndef __SYMBIAN32__
  29. #if defined(IOS) || defined(MACGNUSTD)
  30. #include <tr1/type_traits>
  31. #else
  32. #include <type_traits>
  33. #endif
  34. #endif
  35. #include "common/common.h"
  36. #include "common/file_util.h"
  37. //#include "../ext/snappy/snappy-c.h"
  38. #if defined(IOS) || defined(MACGNUSTD)
  39. namespace std {
  40. using tr1::is_pointer;
  41. }
  42. #endif
  43. #ifdef __SYMBIAN32__
  44. namespace std {
  45. template <bool bool_value>
  46. struct bool_constant {
  47. typedef bool_constant<bool_value> type;
  48. static const bool value = bool_value;
  49. };
  50. template <bool bool_value> const bool bool_constant<bool_value>::value;
  51. template <typename T> struct is_pointer : public bool_constant<false> {};
  52. template <typename T> struct is_pointer<T*> : public bool_constant<true> {};
  53. }
  54. #endif
  55. template <class T>
  56. struct LinkedListItem : public T
  57. {
  58. LinkedListItem<T> *next;
  59. };
  60. class PointerWrap;
  61. class PointerWrapSection
  62. {
  63. public:
  64. PointerWrapSection(PointerWrap &p, int ver, const char *title) : p_(p), ver_(ver), title_(title) {
  65. }
  66. ~PointerWrapSection();
  67. bool operator == (const int &v) const { return ver_ == v; }
  68. bool operator != (const int &v) const { return ver_ != v; }
  69. bool operator <= (const int &v) const { return ver_ <= v; }
  70. bool operator >= (const int &v) const { return ver_ >= v; }
  71. bool operator < (const int &v) const { return ver_ < v; }
  72. bool operator > (const int &v) const { return ver_ > v; }
  73. operator bool() const {
  74. return ver_ > 0;
  75. }
  76. private:
  77. PointerWrap &p_;
  78. int ver_;
  79. const char *title_;
  80. };
  81. // Wrapper class
  82. class PointerWrap
  83. {
  84. // This makes it a compile error if you forget to define DoState() on non-POD.
  85. // Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason...
  86. #ifdef _MSC_VER
  87. template<typename T, bool isPOD = std::is_pod<T>::value, bool isPointer = std::is_pointer<T>::value>
  88. #else
  89. template<typename T, bool isPOD = __is_pod(T), bool isPointer = std::is_pointer<T>::value>
  90. #endif
  91. struct DoHelper
  92. {
  93. static void DoArray(PointerWrap *p, T *x, int count)
  94. {
  95. for (int i = 0; i < count; ++i)
  96. p->Do(x[i]);
  97. }
  98. static void Do(PointerWrap *p, T &x)
  99. {
  100. p->DoClass(x);
  101. }
  102. };
  103. template<typename T>
  104. struct DoHelper<T, true, false>
  105. {
  106. static void DoArray(PointerWrap *p, T *x, int count)
  107. {
  108. p->DoVoid((void *)x, sizeof(T) * count);
  109. }
  110. static void Do(PointerWrap *p, T &x)
  111. {
  112. p->DoVoid((void *)&x, sizeof(x));
  113. }
  114. };
  115. public:
  116. enum Mode {
  117. MODE_READ = 1, // load
  118. MODE_WRITE, // save
  119. MODE_MEASURE, // calculate size
  120. MODE_VERIFY, // compare
  121. };
  122. enum Error {
  123. ERROR_NONE = 0,
  124. ERROR_WARNING = 1,
  125. ERROR_FAILURE = 2,
  126. };
  127. u8 **ptr;
  128. Mode mode;
  129. Error error;
  130. public:
  131. PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_), error(ERROR_NONE) {}
  132. PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), mode((Mode)mode_), error(ERROR_NONE) {}
  133. PointerWrapSection Section(const char *title, int ver) {
  134. return Section(title, ver, ver);
  135. }
  136. // The returned object can be compared against the version that was loaded.
  137. // This can be used to support versions as old as minVer.
  138. // Version = 0 means the section was not found.
  139. PointerWrapSection Section(const char *title, int minVer, int ver) {
  140. char marker[16] = {0};
  141. int foundVersion = ver;
  142. strncpy(marker, title, sizeof(marker));
  143. if (!ExpectVoid(marker, sizeof(marker)))
  144. {
  145. // Might be before we added name markers for safety.
  146. if (foundVersion == 1 && ExpectVoid(&foundVersion, sizeof(foundVersion)))
  147. DoMarker(title);
  148. // Wasn't found, but maybe we can still load the state.
  149. else
  150. foundVersion = 0;
  151. }
  152. else
  153. Do(foundVersion);
  154. if (error == ERROR_FAILURE || foundVersion < minVer || foundVersion > ver) {
  155. WARN_LOG(COMMON, "Savestate failure: wrong version %d found for %s", foundVersion, title);
  156. SetError(ERROR_FAILURE);
  157. return PointerWrapSection(*this, -1, title);
  158. }
  159. return PointerWrapSection(*this, foundVersion, title);
  160. }
  161. void SetMode(Mode mode_) {mode = mode_;}
  162. Mode GetMode() const {return mode;}
  163. u8 **GetPPtr() {return ptr;}
  164. void SetError(Error error_)
  165. {
  166. if (error < error_)
  167. error = error_;
  168. if (error > ERROR_WARNING)
  169. mode = PointerWrap::MODE_MEASURE;
  170. }
  171. bool ExpectVoid(void *data, int size)
  172. {
  173. switch (mode) {
  174. case MODE_READ: if (memcmp(data, *ptr, size) != 0) return false; break;
  175. case MODE_WRITE: memcpy(*ptr, data, size); break;
  176. case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything
  177. case MODE_VERIFY: for(int i = 0; i < size; i++) _dbg_assert_msg_(COMMON, ((u8*)data)[i] == (*ptr)[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], &(*ptr)[i]); break;
  178. default: break; // throw an error?
  179. }
  180. (*ptr) += size;
  181. return true;
  182. }
  183. void DoVoid(void *data, int size)
  184. {
  185. switch (mode) {
  186. case MODE_READ: memcpy(data, *ptr, size); break;
  187. case MODE_WRITE: memcpy(*ptr, data, size); break;
  188. case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything
  189. case MODE_VERIFY: for(int i = 0; i < size; i++) _dbg_assert_msg_(COMMON, ((u8*)data)[i] == (*ptr)[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], &(*ptr)[i]); break;
  190. default: break; // throw an error?
  191. }
  192. (*ptr) += size;
  193. }
  194. template<class K, class T>
  195. void Do(std::map<K, T *> &x)
  196. {
  197. if (mode == MODE_READ)
  198. {
  199. for (auto it = x.begin(), end = x.end(); it != end; ++it)
  200. {
  201. if (it->second != NULL)
  202. delete it->second;
  203. }
  204. }
  205. T *dv = NULL;
  206. DoMap(x, dv);
  207. }
  208. template<class K, class T>
  209. void Do(std::map<K, T> &x)
  210. {
  211. T dv = T();
  212. DoMap(x, dv);
  213. }
  214. template<class K, class T>
  215. void DoMap(std::map<K, T> &x, T &default_val)
  216. {
  217. unsigned int number = (unsigned int)x.size();
  218. Do(number);
  219. switch (mode) {
  220. case MODE_READ:
  221. {
  222. x.clear();
  223. while (number > 0)
  224. {
  225. K first = K();
  226. Do(first);
  227. T second = default_val;
  228. Do(second);
  229. x[first] = second;
  230. --number;
  231. }
  232. }
  233. break;
  234. case MODE_WRITE:
  235. case MODE_MEASURE:
  236. case MODE_VERIFY:
  237. {
  238. typename std::map<K, T>::iterator itr = x.begin();
  239. while (number > 0)
  240. {
  241. K first = itr->first;
  242. Do(first);
  243. Do(itr->second);
  244. --number;
  245. ++itr;
  246. }
  247. }
  248. break;
  249. }
  250. }
  251. template<class K, class T>
  252. void Do(std::multimap<K, T *> &x)
  253. {
  254. if (mode == MODE_READ)
  255. {
  256. for (auto it = x.begin(), end = x.end(); it != end; ++it)
  257. {
  258. if (it->second != NULL)
  259. delete it->second;
  260. }
  261. }
  262. T *dv = NULL;
  263. DoMultimap(x, dv);
  264. }
  265. template<class K, class T>
  266. void Do(std::multimap<K, T> &x)
  267. {
  268. T dv = T();
  269. DoMultimap(x, dv);
  270. }
  271. template<class K, class T>
  272. void DoMultimap(std::multimap<K, T> &x, T &default_val)
  273. {
  274. unsigned int number = (unsigned int)x.size();
  275. Do(number);
  276. switch (mode) {
  277. case MODE_READ:
  278. {
  279. x.clear();
  280. while (number > 0)
  281. {
  282. K first = K();
  283. Do(first);
  284. T second = default_val;
  285. Do(second);
  286. x.insert(std::make_pair(first, second));
  287. --number;
  288. }
  289. }
  290. break;
  291. case MODE_WRITE:
  292. case MODE_MEASURE:
  293. case MODE_VERIFY:
  294. {
  295. typename std::multimap<K, T>::iterator itr = x.begin();
  296. while (number > 0)
  297. {
  298. Do(itr->first);
  299. Do(itr->second);
  300. --number;
  301. ++itr;
  302. }
  303. }
  304. break;
  305. }
  306. }
  307. // Store vectors.
  308. template<class T>
  309. void Do(std::vector<T *> &x)
  310. {
  311. T *dv = NULL;
  312. DoVector(x, dv);
  313. }
  314. template<class T>
  315. void Do(std::vector<T> &x)
  316. {
  317. T dv = T();
  318. DoVector(x, dv);
  319. }
  320. template<class T>
  321. void DoPOD(std::vector<T> &x)
  322. {
  323. T dv = T();
  324. DoVectorPOD(x, dv);
  325. }
  326. template<class T>
  327. void Do(std::vector<T> &x, T &default_val)
  328. {
  329. DoVector(x, default_val);
  330. }
  331. template<class T>
  332. void DoVector(std::vector<T> &x, T &default_val)
  333. {
  334. u32 vec_size = (u32)x.size();
  335. Do(vec_size);
  336. x.resize(vec_size, default_val);
  337. if (vec_size > 0)
  338. DoArray(&x[0], vec_size);
  339. }
  340. template<class T>
  341. void DoVectorPOD(std::vector<T> &x, T &default_val)
  342. {
  343. u32 vec_size = (u32)x.size();
  344. Do(vec_size);
  345. x.resize(vec_size, default_val);
  346. if (vec_size > 0)
  347. DoArray(&x[0], vec_size);
  348. }
  349. // Store deques.
  350. template<class T>
  351. void Do(std::deque<T *> &x)
  352. {
  353. T *dv = NULL;
  354. DoDeque(x, dv);
  355. }
  356. template<class T>
  357. void Do(std::deque<T> &x)
  358. {
  359. T dv = T();
  360. DoDeque(x, dv);
  361. }
  362. template<class T>
  363. void DoDeque(std::deque<T> &x, T &default_val)
  364. {
  365. u32 deq_size = (u32)x.size();
  366. Do(deq_size);
  367. x.resize(deq_size, default_val);
  368. u32 i;
  369. for(i = 0; i < deq_size; i++)
  370. Do(x[i]);
  371. }
  372. // Store STL lists.
  373. template<class T>
  374. void Do(std::list<T *> &x)
  375. {
  376. T *dv = NULL;
  377. Do(x, dv);
  378. }
  379. template<class T>
  380. void Do(std::list<T> &x)
  381. {
  382. T dv = T();
  383. DoList(x, dv);
  384. }
  385. template<class T>
  386. void Do(std::list<T> &x, T &default_val)
  387. {
  388. DoList(x, default_val);
  389. }
  390. template<class T>
  391. void DoList(std::list<T> &x, T &default_val)
  392. {
  393. u32 list_size = (u32)x.size();
  394. Do(list_size);
  395. x.resize(list_size, default_val);
  396. typename std::list<T>::iterator itr, end;
  397. for (itr = x.begin(), end = x.end(); itr != end; ++itr)
  398. Do(*itr);
  399. }
  400. // Store STL sets.
  401. template <class T>
  402. void Do(std::set<T *> &x)
  403. {
  404. if (mode == MODE_READ)
  405. {
  406. for (auto it = x.begin(), end = x.end(); it != end; ++it)
  407. {
  408. if (*it != NULL)
  409. delete *it;
  410. }
  411. }
  412. DoSet(x);
  413. }
  414. template <class T>
  415. void Do(std::set<T> &x)
  416. {
  417. DoSet(x);
  418. }
  419. template <class T>
  420. void DoSet(std::set<T> &x)
  421. {
  422. unsigned int number = (unsigned int)x.size();
  423. Do(number);
  424. switch (mode)
  425. {
  426. case MODE_READ:
  427. {
  428. x.clear();
  429. while (number-- > 0)
  430. {
  431. T it = T();
  432. Do(it);
  433. x.insert(it);
  434. }
  435. }
  436. break;
  437. case MODE_WRITE:
  438. case MODE_MEASURE:
  439. case MODE_VERIFY:
  440. {
  441. typename std::set<T>::iterator itr = x.begin();
  442. while (number-- > 0)
  443. Do(*itr++);
  444. }
  445. break;
  446. default:
  447. ERROR_LOG(COMMON, "Savestate error: invalid mode %d.", mode);
  448. }
  449. }
  450. // Store strings.
  451. void Do(std::string &x)
  452. {
  453. int stringLen = (int)x.length() + 1;
  454. Do(stringLen);
  455. switch (mode) {
  456. case MODE_READ: x = (char*)*ptr; break;
  457. case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break;
  458. case MODE_MEASURE: break;
  459. case MODE_VERIFY: _dbg_assert_msg_(COMMON, !strcmp(x.c_str(), (char*)*ptr), "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", x.c_str(), (char*)*ptr, ptr); break;
  460. }
  461. (*ptr) += stringLen;
  462. }
  463. void Do(std::wstring &x)
  464. {
  465. int stringLen = sizeof(wchar_t)*((int)x.length() + 1);
  466. Do(stringLen);
  467. switch (mode) {
  468. case MODE_READ: x = (wchar_t*)*ptr; break;
  469. case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break;
  470. case MODE_MEASURE: break;
  471. case MODE_VERIFY: _dbg_assert_msg_(COMMON, x == (wchar_t*)*ptr, "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", x.c_str(), (wchar_t*)*ptr, ptr); break;
  472. }
  473. (*ptr) += stringLen;
  474. }
  475. template<class T>
  476. void DoClass(T &x) {
  477. x.DoState(*this);
  478. }
  479. template<class T>
  480. void DoClass(T *&x) {
  481. if (mode == MODE_READ)
  482. {
  483. if (x != NULL)
  484. delete x;
  485. x = new T();
  486. }
  487. x->DoState(*this);
  488. }
  489. template<class T>
  490. void DoArray(T *x, int count) {
  491. DoHelper<T>::DoArray(this, x, count);
  492. }
  493. template<class T>
  494. void Do(T &x) {
  495. DoHelper<T>::Do(this, x);
  496. }
  497. template<class T>
  498. void DoPOD(T &x) {
  499. DoHelper<T>::Do(this, x);
  500. }
  501. template<class T>
  502. void DoPointer(T* &x, T*const base) {
  503. // pointers can be more than 2^31 apart, but you're using this function wrong if you need that much range
  504. s32 offset = x - base;
  505. Do(offset);
  506. if (mode == MODE_READ)
  507. x = base + offset;
  508. }
  509. template<class T, LinkedListItem<T>* (*TNew)(), void (*TFree)(LinkedListItem<T>*), void (*TDo)(PointerWrap&, T*)>
  510. void DoLinkedList(LinkedListItem<T>*& list_start, LinkedListItem<T>** list_end=0)
  511. {
  512. LinkedListItem<T>* list_cur = list_start;
  513. LinkedListItem<T>* prev = 0;
  514. while (true)
  515. {
  516. u8 shouldExist = (list_cur ? 1 : 0);
  517. Do(shouldExist);
  518. if (shouldExist == 1)
  519. {
  520. LinkedListItem<T>* cur = list_cur ? list_cur : TNew();
  521. TDo(*this, (T*)cur);
  522. if (!list_cur)
  523. {
  524. if (mode == MODE_READ)
  525. {
  526. cur->next = 0;
  527. list_cur = cur;
  528. if (prev)
  529. prev->next = cur;
  530. else
  531. list_start = cur;
  532. }
  533. else
  534. {
  535. TFree(cur);
  536. continue;
  537. }
  538. }
  539. }
  540. else
  541. {
  542. if (mode == MODE_READ)
  543. {
  544. if (prev)
  545. prev->next = 0;
  546. if (list_end)
  547. *list_end = prev;
  548. if (list_cur)
  549. {
  550. if (list_start == list_cur)
  551. list_start = 0;
  552. do
  553. {
  554. LinkedListItem<T>* next = list_cur->next;
  555. TFree(list_cur);
  556. list_cur = next;
  557. }
  558. while (list_cur);
  559. }
  560. }
  561. break;
  562. }
  563. prev = list_cur;
  564. list_cur = list_cur->next;
  565. }
  566. }
  567. void DoMarker(const char* prevName, u32 arbitraryNumber=0x42)
  568. {
  569. u32 cookie = arbitraryNumber;
  570. Do(cookie);
  571. if(mode == PointerWrap::MODE_READ && cookie != arbitraryNumber)
  572. {
  573. PanicAlertT("Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...", prevName, cookie, cookie, arbitraryNumber, arbitraryNumber);
  574. SetError(ERROR_FAILURE);
  575. }
  576. }
  577. };
  578. inline PointerWrapSection::~PointerWrapSection() {
  579. if (ver_ > 0) {
  580. p_.DoMarker(title_);
  581. }
  582. }
  583. // Commented out because it is currently unused, and breaks builds on OSX
  584. /*class CChunkFileReader
  585. {
  586. public:
  587. enum Error {
  588. ERROR_NONE,
  589. ERROR_BAD_FILE,
  590. ERROR_BROKEN_STATE,
  591. };
  592. // Load file template
  593. template<class T>
  594. static Error Load(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class, std::string* _failureReason)
  595. {
  596. INFO_LOG(COMMON, "ChunkReader: Loading %s" , _rFilename.c_str());
  597. _failureReason->clear();
  598. _failureReason->append("LoadStateWrongVersion");
  599. if (!File::Exists(_rFilename)) {
  600. _failureReason->clear();
  601. _failureReason->append("LoadStateDoesntExist");
  602. ERROR_LOG(COMMON, "ChunkReader: File doesn't exist");
  603. return ERROR_BAD_FILE;
  604. }
  605. // Check file size
  606. const u64 fileSize = File::GetSize(_rFilename);
  607. static const u64 headerSize = sizeof(SChunkHeader);
  608. if (fileSize < headerSize)
  609. {
  610. ERROR_LOG(COMMON,"ChunkReader: File too small");
  611. return ERROR_BAD_FILE;
  612. }
  613. File::IOFile pFile(_rFilename, "rb");
  614. if (!pFile)
  615. {
  616. ERROR_LOG(COMMON,"ChunkReader: Can't open file for reading");
  617. return ERROR_BAD_FILE;
  618. }
  619. // read the header
  620. SChunkHeader header;
  621. if (!pFile.ReadArray(&header, 1))
  622. {
  623. ERROR_LOG(COMMON,"ChunkReader: Bad header size");
  624. return ERROR_BAD_FILE;
  625. }
  626. // Check revision
  627. if (header.Revision != _Revision)
  628. {
  629. ERROR_LOG(COMMON,"ChunkReader: Wrong file revision, got %d expected %d",
  630. header.Revision, _Revision);
  631. return ERROR_BAD_FILE;
  632. }
  633. if (strcmp(header.GitVersion, _VersionString) != 0)
  634. {
  635. WARN_LOG(COMMON, "This savestate was generated by a different version of PPSSPP, %s. It may not load properly.",
  636. header.GitVersion);
  637. }
  638. // get size
  639. const int sz = (int)(fileSize - headerSize);
  640. if (header.ExpectedSize != sz)
  641. {
  642. ERROR_LOG(COMMON,"ChunkReader: Bad file size, got %d expected %d",
  643. sz, header.ExpectedSize);
  644. return ERROR_BAD_FILE;
  645. }
  646. // read the state
  647. u8* buffer = new u8[sz];
  648. if (!pFile.ReadBytes(buffer, sz))
  649. {
  650. ERROR_LOG(COMMON,"ChunkReader: Error reading file");
  651. return ERROR_BAD_FILE;
  652. }
  653. u8 *ptr = buffer;
  654. u8 *buf = buffer;
  655. if (header.Compress) {
  656. u8 *uncomp_buffer = new u8[header.UncompressedSize];
  657. size_t uncomp_size = header.UncompressedSize;
  658. snappy_uncompress((const char *)buffer, sz, (char *)uncomp_buffer, &uncomp_size);
  659. if ((int)uncomp_size != header.UncompressedSize) {
  660. ERROR_LOG(COMMON,"Size mismatch: file: %i calc: %i", (int)header.UncompressedSize, (int)uncomp_size);
  661. }
  662. ptr = uncomp_buffer;
  663. buf = uncomp_buffer;
  664. delete [] buffer;
  665. }
  666. PointerWrap p(&ptr, PointerWrap::MODE_READ);
  667. _class.DoState(p);
  668. delete[] buf;
  669. INFO_LOG(COMMON, "ChunkReader: Done loading %s" , _rFilename.c_str());
  670. if (p.error != p.ERROR_FAILURE) {
  671. return ERROR_NONE;
  672. } else {
  673. return ERROR_BROKEN_STATE;
  674. }
  675. }
  676. // Save file template
  677. template<class T>
  678. static Error Save(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class)
  679. {
  680. INFO_LOG(COMMON, "ChunkReader: Writing %s" , _rFilename.c_str());
  681. File::IOFile pFile(_rFilename, "wb");
  682. if (!pFile)
  683. {
  684. ERROR_LOG(COMMON,"ChunkReader: Error opening file for write");
  685. return ERROR_BAD_FILE;
  686. }
  687. bool compress = true;
  688. // Get data
  689. u8 *ptr = 0;
  690. PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
  691. _class.DoState(p);
  692. size_t const sz = (size_t)ptr;
  693. u8 * buffer = new u8[sz];
  694. ptr = &buffer[0];
  695. p.SetMode(PointerWrap::MODE_WRITE);
  696. _class.DoState(p);
  697. // Create header
  698. SChunkHeader header;
  699. header.Compress = compress ? 1 : 0;
  700. header.Revision = _Revision;
  701. header.ExpectedSize = (int)sz;
  702. header.UncompressedSize = (int)sz;
  703. strncpy(header.GitVersion, _VersionString, 32);
  704. header.GitVersion[31] = '\0';
  705. // Write to file
  706. if (compress) {
  707. size_t comp_len = snappy_max_compressed_length(sz);
  708. u8 *compressed_buffer = new u8[comp_len];
  709. snappy_compress((const char *)buffer, sz, (char *)compressed_buffer, &comp_len);
  710. delete [] buffer;
  711. header.ExpectedSize = (int)comp_len;
  712. if (!pFile.WriteArray(&header, 1))
  713. {
  714. ERROR_LOG(COMMON,"ChunkReader: Failed writing header");
  715. return ERROR_BAD_FILE;
  716. }
  717. if (!pFile.WriteBytes(&compressed_buffer[0], comp_len)) {
  718. ERROR_LOG(COMMON,"ChunkReader: Failed writing compressed data");
  719. return ERROR_BAD_FILE;
  720. } else {
  721. INFO_LOG(COMMON, "Savestate: Compressed %i bytes into %i", (int)sz, (int)comp_len);
  722. }
  723. delete [] compressed_buffer;
  724. } else {
  725. if (!pFile.WriteArray(&header, 1))
  726. {
  727. ERROR_LOG(COMMON,"ChunkReader: Failed writing header");
  728. return ERROR_BAD_FILE;
  729. }
  730. if (!pFile.WriteBytes(&buffer[0], sz))
  731. {
  732. ERROR_LOG(COMMON,"ChunkReader: Failed writing data");
  733. return ERROR_BAD_FILE;
  734. }
  735. delete [] buffer;
  736. }
  737. INFO_LOG(COMMON,"ChunkReader: Done writing %s",
  738. _rFilename.c_str());
  739. if (p.error != p.ERROR_FAILURE) {
  740. return ERROR_NONE;
  741. } else {
  742. return ERROR_BROKEN_STATE;
  743. }
  744. }
  745. template <class T>
  746. static Error Verify(T& _class)
  747. {
  748. u8 *ptr = 0;
  749. // Step 1: Measure the space required.
  750. PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
  751. _class.DoState(p);
  752. size_t const sz = (size_t)ptr;
  753. std::vector<u8> buffer(sz);
  754. // Step 2: Dump the state.
  755. ptr = &buffer[0];
  756. p.SetMode(PointerWrap::MODE_WRITE);
  757. _class.DoState(p);
  758. // Step 3: Verify the state.
  759. ptr = &buffer[0];
  760. p.SetMode(PointerWrap::MODE_VERIFY);
  761. _class.DoState(p);
  762. return ERROR_NONE;
  763. }
  764. private:
  765. struct SChunkHeader
  766. {
  767. int Revision;
  768. int Compress;
  769. int ExpectedSize;
  770. int UncompressedSize;
  771. char GitVersion[32];
  772. };
  773. }; */
  774. #endif // _POINTERWRAP_H_