diff options
Diffstat (limited to 'src/common/src/chunk_file.h')
-rw-r--r-- | src/common/src/chunk_file.h | 1560 |
1 files changed, 780 insertions, 780 deletions
diff --git a/src/common/src/chunk_file.h b/src/common/src/chunk_file.h index c480bc8e..68c2943a 100644 --- a/src/common/src/chunk_file.h +++ b/src/common/src/chunk_file.h @@ -47,26 +47,26 @@ #if defined(IOS) || defined(MACGNUSTD) namespace std { - using tr1::is_pointer; + using tr1::is_pointer; } #endif #ifdef __SYMBIAN32__ namespace std { - template <bool bool_value> - struct bool_constant { - typedef bool_constant<bool_value> type; - static const bool value = bool_value; - }; - template <bool bool_value> const bool bool_constant<bool_value>::value; - template <typename T> struct is_pointer : public bool_constant<false> {}; - template <typename T> struct is_pointer<T*> : public bool_constant<true> {}; + template <bool bool_value> + struct bool_constant { + typedef bool_constant<bool_value> type; + static const bool value = bool_value; + }; + template <bool bool_value> const bool bool_constant<bool_value>::value; + template <typename T> struct is_pointer : public bool_constant<false> {}; + template <typename T> struct is_pointer<T*> : public bool_constant<true> {}; } #endif template <class T> struct LinkedListItem : public T { - LinkedListItem<T> *next; + LinkedListItem<T> *next; }; class PointerWrap; @@ -74,801 +74,801 @@ class PointerWrap; class PointerWrapSection { public: - PointerWrapSection(PointerWrap &p, int ver, const char *title) : p_(p), ver_(ver), title_(title) { - } - ~PointerWrapSection(); - - bool operator == (const int &v) const { return ver_ == v; } - bool operator != (const int &v) const { return ver_ != v; } - bool operator <= (const int &v) const { return ver_ <= v; } - bool operator >= (const int &v) const { return ver_ >= v; } - bool operator < (const int &v) const { return ver_ < v; } - bool operator > (const int &v) const { return ver_ > v; } - - operator bool() const { - return ver_ > 0; - } + PointerWrapSection(PointerWrap &p, int ver, const char *title) : p_(p), ver_(ver), title_(title) { + } + ~PointerWrapSection(); + + bool operator == (const int &v) const { return ver_ == v; } + bool operator != (const int &v) const { return ver_ != v; } + bool operator <= (const int &v) const { return ver_ <= v; } + bool operator >= (const int &v) const { return ver_ >= v; } + bool operator < (const int &v) const { return ver_ < v; } + bool operator > (const int &v) const { return ver_ > v; } + + operator bool() const { + return ver_ > 0; + } private: - PointerWrap &p_; - int ver_; - const char *title_; + PointerWrap &p_; + int ver_; + const char *title_; }; // Wrapper class class PointerWrap { - // This makes it a compile error if you forget to define DoState() on non-POD. - // Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason... + // This makes it a compile error if you forget to define DoState() on non-POD. + // Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason... #ifdef _MSC_VER - template<typename T, bool isPOD = std::is_pod<T>::value, bool isPointer = std::is_pointer<T>::value> + template<typename T, bool isPOD = std::is_pod<T>::value, bool isPointer = std::is_pointer<T>::value> #else - template<typename T, bool isPOD = __is_pod(T), bool isPointer = std::is_pointer<T>::value> + template<typename T, bool isPOD = __is_pod(T), bool isPointer = std::is_pointer<T>::value> #endif - struct DoHelper - { - static void DoArray(PointerWrap *p, T *x, int count) - { - for (int i = 0; i < count; ++i) - p->Do(x[i]); - } - - static void Do(PointerWrap *p, T &x) - { - p->DoClass(x); - } - }; - - template<typename T> - struct DoHelper<T, true, false> - { - static void DoArray(PointerWrap *p, T *x, int count) - { - p->DoVoid((void *)x, sizeof(T) * count); - } - - static void Do(PointerWrap *p, T &x) - { - p->DoVoid((void *)&x, sizeof(x)); - } - }; + struct DoHelper + { + static void DoArray(PointerWrap *p, T *x, int count) + { + for (int i = 0; i < count; ++i) + p->Do(x[i]); + } + + static void Do(PointerWrap *p, T &x) + { + p->DoClass(x); + } + }; + + template<typename T> + struct DoHelper<T, true, false> + { + static void DoArray(PointerWrap *p, T *x, int count) + { + p->DoVoid((void *)x, sizeof(T) * count); + } + + static void Do(PointerWrap *p, T &x) + { + p->DoVoid((void *)&x, sizeof(x)); + } + }; public: - enum Mode { - MODE_READ = 1, // load - MODE_WRITE, // save - MODE_MEASURE, // calculate size - MODE_VERIFY, // compare - }; - - enum Error { - ERROR_NONE = 0, - ERROR_WARNING = 1, - ERROR_FAILURE = 2, - }; - - u8 **ptr; - Mode mode; - Error error; + enum Mode { + MODE_READ = 1, // load + MODE_WRITE, // save + MODE_MEASURE, // calculate size + MODE_VERIFY, // compare + }; + + enum Error { + ERROR_NONE = 0, + ERROR_WARNING = 1, + ERROR_FAILURE = 2, + }; + + u8 **ptr; + Mode mode; + Error error; public: - PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_), error(ERROR_NONE) {} - PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), mode((Mode)mode_), error(ERROR_NONE) {} - - PointerWrapSection Section(const char *title, int ver) { - return Section(title, ver, ver); - } - - // The returned object can be compared against the version that was loaded. - // This can be used to support versions as old as minVer. - // Version = 0 means the section was not found. - PointerWrapSection Section(const char *title, int minVer, int ver) { - char marker[16] = {0}; - int foundVersion = ver; - - strncpy(marker, title, sizeof(marker)); - if (!ExpectVoid(marker, sizeof(marker))) - { - // Might be before we added name markers for safety. - if (foundVersion == 1 && ExpectVoid(&foundVersion, sizeof(foundVersion))) - DoMarker(title); - // Wasn't found, but maybe we can still load the state. - else - foundVersion = 0; - } - else - Do(foundVersion); - - if (error == ERROR_FAILURE || foundVersion < minVer || foundVersion > ver) { - WARN_LOG(COMMON, "Savestate failure: wrong version %d found for %s", foundVersion, title); - SetError(ERROR_FAILURE); - return PointerWrapSection(*this, -1, title); - } - return PointerWrapSection(*this, foundVersion, title); - } - - void SetMode(Mode mode_) {mode = mode_;} - Mode GetMode() const {return mode;} - u8 **GetPPtr() {return ptr;} - void SetError(Error error_) - { - if (error < error_) - error = error_; - if (error > ERROR_WARNING) - mode = PointerWrap::MODE_MEASURE; - } - - bool ExpectVoid(void *data, int size) - { - switch (mode) { - case MODE_READ: if (memcmp(data, *ptr, size) != 0) return false; break; - case MODE_WRITE: memcpy(*ptr, data, size); break; - case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything - 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; - default: break; // throw an error? - } - (*ptr) += size; - return true; - } - - void DoVoid(void *data, int size) - { - switch (mode) { - case MODE_READ: memcpy(data, *ptr, size); break; - case MODE_WRITE: memcpy(*ptr, data, size); break; - case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything - 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; - default: break; // throw an error? - } - (*ptr) += size; - } - - template<class K, class T> - void Do(std::map<K, T *> &x) - { - if (mode == MODE_READ) - { - for (auto it = x.begin(), end = x.end(); it != end; ++it) - { - if (it->second != NULL) - delete it->second; - } - } - T *dv = NULL; - DoMap(x, dv); - } - - template<class K, class T> - void Do(std::map<K, T> &x) - { - T dv = T(); - DoMap(x, dv); - } - - template<class K, class T> - void DoMap(std::map<K, T> &x, T &default_val) - { - unsigned int number = (unsigned int)x.size(); - Do(number); - switch (mode) { - case MODE_READ: - { - x.clear(); - while (number > 0) - { - K first = K(); - Do(first); - T second = default_val; - Do(second); - x[first] = second; - --number; - } - } - break; - case MODE_WRITE: - case MODE_MEASURE: - case MODE_VERIFY: - { - typename std::map<K, T>::iterator itr = x.begin(); - while (number > 0) - { - K first = itr->first; - Do(first); - Do(itr->second); - --number; - ++itr; - } - } - break; - } - } - - template<class K, class T> - void Do(std::multimap<K, T *> &x) - { - if (mode == MODE_READ) - { - for (auto it = x.begin(), end = x.end(); it != end; ++it) - { - if (it->second != NULL) - delete it->second; - } - } - T *dv = NULL; - DoMultimap(x, dv); - } - - template<class K, class T> - void Do(std::multimap<K, T> &x) - { - T dv = T(); - DoMultimap(x, dv); - } - - template<class K, class T> - void DoMultimap(std::multimap<K, T> &x, T &default_val) - { - unsigned int number = (unsigned int)x.size(); - Do(number); - switch (mode) { - case MODE_READ: - { - x.clear(); - while (number > 0) - { - K first = K(); - Do(first); - T second = default_val; - Do(second); - x.insert(std::make_pair(first, second)); - --number; - } - } - break; - case MODE_WRITE: - case MODE_MEASURE: - case MODE_VERIFY: - { - typename std::multimap<K, T>::iterator itr = x.begin(); - while (number > 0) - { - Do(itr->first); - Do(itr->second); - --number; - ++itr; - } - } - break; - } - } - - // Store vectors. - template<class T> - void Do(std::vector<T *> &x) - { - T *dv = NULL; - DoVector(x, dv); - } - - template<class T> - void Do(std::vector<T> &x) - { - T dv = T(); - DoVector(x, dv); - } - - - template<class T> - void DoPOD(std::vector<T> &x) - { - T dv = T(); - DoVectorPOD(x, dv); - } - - template<class T> - void Do(std::vector<T> &x, T &default_val) - { - DoVector(x, default_val); - } - - template<class T> - void DoVector(std::vector<T> &x, T &default_val) - { - u32 vec_size = (u32)x.size(); - Do(vec_size); - x.resize(vec_size, default_val); - if (vec_size > 0) - DoArray(&x[0], vec_size); - } - - template<class T> - void DoVectorPOD(std::vector<T> &x, T &default_val) - { - u32 vec_size = (u32)x.size(); - Do(vec_size); - x.resize(vec_size, default_val); - if (vec_size > 0) - DoArray(&x[0], vec_size); - } - - // Store deques. - template<class T> - void Do(std::deque<T *> &x) - { - T *dv = NULL; - DoDeque(x, dv); - } - - template<class T> - void Do(std::deque<T> &x) - { - T dv = T(); - DoDeque(x, dv); - } - - template<class T> - void DoDeque(std::deque<T> &x, T &default_val) - { - u32 deq_size = (u32)x.size(); - Do(deq_size); - x.resize(deq_size, default_val); - u32 i; - for(i = 0; i < deq_size; i++) - Do(x[i]); - } - - // Store STL lists. - template<class T> - void Do(std::list<T *> &x) - { - T *dv = NULL; - Do(x, dv); - } - - template<class T> - void Do(std::list<T> &x) - { - T dv = T(); - DoList(x, dv); - } - - template<class T> - void Do(std::list<T> &x, T &default_val) - { - DoList(x, default_val); - } - - template<class T> - void DoList(std::list<T> &x, T &default_val) - { - u32 list_size = (u32)x.size(); - Do(list_size); - x.resize(list_size, default_val); - - typename std::list<T>::iterator itr, end; - for (itr = x.begin(), end = x.end(); itr != end; ++itr) - Do(*itr); - } - - - // Store STL sets. - template <class T> - void Do(std::set<T *> &x) - { - if (mode == MODE_READ) - { - for (auto it = x.begin(), end = x.end(); it != end; ++it) - { - if (*it != NULL) - delete *it; - } - } - DoSet(x); - } - - template <class T> - void Do(std::set<T> &x) - { - DoSet(x); - } - - template <class T> - void DoSet(std::set<T> &x) - { - unsigned int number = (unsigned int)x.size(); - Do(number); - - switch (mode) - { - case MODE_READ: - { - x.clear(); - while (number-- > 0) - { - T it = T(); - Do(it); - x.insert(it); - } - } - break; - case MODE_WRITE: - case MODE_MEASURE: - case MODE_VERIFY: - { - typename std::set<T>::iterator itr = x.begin(); - while (number-- > 0) - Do(*itr++); - } - break; - - default: - ERROR_LOG(COMMON, "Savestate error: invalid mode %d.", mode); - } - } - - // Store strings. - void Do(std::string &x) - { - int stringLen = (int)x.length() + 1; - Do(stringLen); - - switch (mode) { - case MODE_READ: x = (char*)*ptr; break; - case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; - case MODE_MEASURE: break; - 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; - } - (*ptr) += stringLen; - } - - void Do(std::wstring &x) - { - int stringLen = sizeof(wchar_t)*((int)x.length() + 1); - Do(stringLen); - - switch (mode) { - case MODE_READ: x = (wchar_t*)*ptr; break; - case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; - case MODE_MEASURE: break; - 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; - } - (*ptr) += stringLen; - } - - template<class T> - void DoClass(T &x) { - x.DoState(*this); - } - - template<class T> - void DoClass(T *&x) { - if (mode == MODE_READ) - { - if (x != NULL) - delete x; - x = new T(); - } - x->DoState(*this); - } - - template<class T> - void DoArray(T *x, int count) { - DoHelper<T>::DoArray(this, x, count); - } - - template<class T> - void Do(T &x) { - DoHelper<T>::Do(this, x); - } - - template<class T> - void DoPOD(T &x) { - DoHelper<T>::Do(this, x); - } - - template<class T> - void DoPointer(T* &x, T*const base) { - // pointers can be more than 2^31 apart, but you're using this function wrong if you need that much range - s32 offset = x - base; - Do(offset); - if (mode == MODE_READ) - x = base + offset; - } - - template<class T, LinkedListItem<T>* (*TNew)(), void (*TFree)(LinkedListItem<T>*), void (*TDo)(PointerWrap&, T*)> - void DoLinkedList(LinkedListItem<T>*& list_start, LinkedListItem<T>** list_end=0) - { - LinkedListItem<T>* list_cur = list_start; - LinkedListItem<T>* prev = 0; - - while (true) - { - u8 shouldExist = (list_cur ? 1 : 0); - Do(shouldExist); - if (shouldExist == 1) - { - LinkedListItem<T>* cur = list_cur ? list_cur : TNew(); - TDo(*this, (T*)cur); - if (!list_cur) - { - if (mode == MODE_READ) - { - cur->next = 0; - list_cur = cur; - if (prev) - prev->next = cur; - else - list_start = cur; - } - else - { - TFree(cur); - continue; - } - } - } - else - { - if (mode == MODE_READ) - { - if (prev) - prev->next = 0; - if (list_end) - *list_end = prev; - if (list_cur) - { - if (list_start == list_cur) - list_start = 0; - do - { - LinkedListItem<T>* next = list_cur->next; - TFree(list_cur); - list_cur = next; - } - while (list_cur); - } - } - break; - } - prev = list_cur; - list_cur = list_cur->next; - } - } - - void DoMarker(const char* prevName, u32 arbitraryNumber=0x42) - { - u32 cookie = arbitraryNumber; - Do(cookie); - if(mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) - { - PanicAlertT("Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...", prevName, cookie, cookie, arbitraryNumber, arbitraryNumber); - SetError(ERROR_FAILURE); - } - } + PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_), error(ERROR_NONE) {} + PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), mode((Mode)mode_), error(ERROR_NONE) {} + + PointerWrapSection Section(const char *title, int ver) { + return Section(title, ver, ver); + } + + // The returned object can be compared against the version that was loaded. + // This can be used to support versions as old as minVer. + // Version = 0 means the section was not found. + PointerWrapSection Section(const char *title, int minVer, int ver) { + char marker[16] = {0}; + int foundVersion = ver; + + strncpy(marker, title, sizeof(marker)); + if (!ExpectVoid(marker, sizeof(marker))) + { + // Might be before we added name markers for safety. + if (foundVersion == 1 && ExpectVoid(&foundVersion, sizeof(foundVersion))) + DoMarker(title); + // Wasn't found, but maybe we can still load the state. + else + foundVersion = 0; + } + else + Do(foundVersion); + + if (error == ERROR_FAILURE || foundVersion < minVer || foundVersion > ver) { + WARN_LOG(COMMON, "Savestate failure: wrong version %d found for %s", foundVersion, title); + SetError(ERROR_FAILURE); + return PointerWrapSection(*this, -1, title); + } + return PointerWrapSection(*this, foundVersion, title); + } + + void SetMode(Mode mode_) {mode = mode_;} + Mode GetMode() const {return mode;} + u8 **GetPPtr() {return ptr;} + void SetError(Error error_) + { + if (error < error_) + error = error_; + if (error > ERROR_WARNING) + mode = PointerWrap::MODE_MEASURE; + } + + bool ExpectVoid(void *data, int size) + { + switch (mode) { + case MODE_READ: if (memcmp(data, *ptr, size) != 0) return false; break; + case MODE_WRITE: memcpy(*ptr, data, size); break; + case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything + 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; + default: break; // throw an error? + } + (*ptr) += size; + return true; + } + + void DoVoid(void *data, int size) + { + switch (mode) { + case MODE_READ: memcpy(data, *ptr, size); break; + case MODE_WRITE: memcpy(*ptr, data, size); break; + case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything + 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; + default: break; // throw an error? + } + (*ptr) += size; + } + + template<class K, class T> + void Do(std::map<K, T *> &x) + { + if (mode == MODE_READ) + { + for (auto it = x.begin(), end = x.end(); it != end; ++it) + { + if (it->second != NULL) + delete it->second; + } + } + T *dv = NULL; + DoMap(x, dv); + } + + template<class K, class T> + void Do(std::map<K, T> &x) + { + T dv = T(); + DoMap(x, dv); + } + + template<class K, class T> + void DoMap(std::map<K, T> &x, T &default_val) + { + unsigned int number = (unsigned int)x.size(); + Do(number); + switch (mode) { + case MODE_READ: + { + x.clear(); + while (number > 0) + { + K first = K(); + Do(first); + T second = default_val; + Do(second); + x[first] = second; + --number; + } + } + break; + case MODE_WRITE: + case MODE_MEASURE: + case MODE_VERIFY: + { + typename std::map<K, T>::iterator itr = x.begin(); + while (number > 0) + { + K first = itr->first; + Do(first); + Do(itr->second); + --number; + ++itr; + } + } + break; + } + } + + template<class K, class T> + void Do(std::multimap<K, T *> &x) + { + if (mode == MODE_READ) + { + for (auto it = x.begin(), end = x.end(); it != end; ++it) + { + if (it->second != NULL) + delete it->second; + } + } + T *dv = NULL; + DoMultimap(x, dv); + } + + template<class K, class T> + void Do(std::multimap<K, T> &x) + { + T dv = T(); + DoMultimap(x, dv); + } + + template<class K, class T> + void DoMultimap(std::multimap<K, T> &x, T &default_val) + { + unsigned int number = (unsigned int)x.size(); + Do(number); + switch (mode) { + case MODE_READ: + { + x.clear(); + while (number > 0) + { + K first = K(); + Do(first); + T second = default_val; + Do(second); + x.insert(std::make_pair(first, second)); + --number; + } + } + break; + case MODE_WRITE: + case MODE_MEASURE: + case MODE_VERIFY: + { + typename std::multimap<K, T>::iterator itr = x.begin(); + while (number > 0) + { + Do(itr->first); + Do(itr->second); + --number; + ++itr; + } + } + break; + } + } + + // Store vectors. + template<class T> + void Do(std::vector<T *> &x) + { + T *dv = NULL; + DoVector(x, dv); + } + + template<class T> + void Do(std::vector<T> &x) + { + T dv = T(); + DoVector(x, dv); + } + + + template<class T> + void DoPOD(std::vector<T> &x) + { + T dv = T(); + DoVectorPOD(x, dv); + } + + template<class T> + void Do(std::vector<T> &x, T &default_val) + { + DoVector(x, default_val); + } + + template<class T> + void DoVector(std::vector<T> &x, T &default_val) + { + u32 vec_size = (u32)x.size(); + Do(vec_size); + x.resize(vec_size, default_val); + if (vec_size > 0) + DoArray(&x[0], vec_size); + } + + template<class T> + void DoVectorPOD(std::vector<T> &x, T &default_val) + { + u32 vec_size = (u32)x.size(); + Do(vec_size); + x.resize(vec_size, default_val); + if (vec_size > 0) + DoArray(&x[0], vec_size); + } + + // Store deques. + template<class T> + void Do(std::deque<T *> &x) + { + T *dv = NULL; + DoDeque(x, dv); + } + + template<class T> + void Do(std::deque<T> &x) + { + T dv = T(); + DoDeque(x, dv); + } + + template<class T> + void DoDeque(std::deque<T> &x, T &default_val) + { + u32 deq_size = (u32)x.size(); + Do(deq_size); + x.resize(deq_size, default_val); + u32 i; + for(i = 0; i < deq_size; i++) + Do(x[i]); + } + + // Store STL lists. + template<class T> + void Do(std::list<T *> &x) + { + T *dv = NULL; + Do(x, dv); + } + + template<class T> + void Do(std::list<T> &x) + { + T dv = T(); + DoList(x, dv); + } + + template<class T> + void Do(std::list<T> &x, T &default_val) + { + DoList(x, default_val); + } + + template<class T> + void DoList(std::list<T> &x, T &default_val) + { + u32 list_size = (u32)x.size(); + Do(list_size); + x.resize(list_size, default_val); + + typename std::list<T>::iterator itr, end; + for (itr = x.begin(), end = x.end(); itr != end; ++itr) + Do(*itr); + } + + + // Store STL sets. + template <class T> + void Do(std::set<T *> &x) + { + if (mode == MODE_READ) + { + for (auto it = x.begin(), end = x.end(); it != end; ++it) + { + if (*it != NULL) + delete *it; + } + } + DoSet(x); + } + + template <class T> + void Do(std::set<T> &x) + { + DoSet(x); + } + + template <class T> + void DoSet(std::set<T> &x) + { + unsigned int number = (unsigned int)x.size(); + Do(number); + + switch (mode) + { + case MODE_READ: + { + x.clear(); + while (number-- > 0) + { + T it = T(); + Do(it); + x.insert(it); + } + } + break; + case MODE_WRITE: + case MODE_MEASURE: + case MODE_VERIFY: + { + typename std::set<T>::iterator itr = x.begin(); + while (number-- > 0) + Do(*itr++); + } + break; + + default: + ERROR_LOG(COMMON, "Savestate error: invalid mode %d.", mode); + } + } + + // Store strings. + void Do(std::string &x) + { + int stringLen = (int)x.length() + 1; + Do(stringLen); + + switch (mode) { + case MODE_READ: x = (char*)*ptr; break; + case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; + case MODE_MEASURE: break; + 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; + } + (*ptr) += stringLen; + } + + void Do(std::wstring &x) + { + int stringLen = sizeof(wchar_t)*((int)x.length() + 1); + Do(stringLen); + + switch (mode) { + case MODE_READ: x = (wchar_t*)*ptr; break; + case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; + case MODE_MEASURE: break; + 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; + } + (*ptr) += stringLen; + } + + template<class T> + void DoClass(T &x) { + x.DoState(*this); + } + + template<class T> + void DoClass(T *&x) { + if (mode == MODE_READ) + { + if (x != NULL) + delete x; + x = new T(); + } + x->DoState(*this); + } + + template<class T> + void DoArray(T *x, int count) { + DoHelper<T>::DoArray(this, x, count); + } + + template<class T> + void Do(T &x) { + DoHelper<T>::Do(this, x); + } + + template<class T> + void DoPOD(T &x) { + DoHelper<T>::Do(this, x); + } + + template<class T> + void DoPointer(T* &x, T*const base) { + // pointers can be more than 2^31 apart, but you're using this function wrong if you need that much range + s32 offset = x - base; + Do(offset); + if (mode == MODE_READ) + x = base + offset; + } + + template<class T, LinkedListItem<T>* (*TNew)(), void (*TFree)(LinkedListItem<T>*), void (*TDo)(PointerWrap&, T*)> + void DoLinkedList(LinkedListItem<T>*& list_start, LinkedListItem<T>** list_end=0) + { + LinkedListItem<T>* list_cur = list_start; + LinkedListItem<T>* prev = 0; + + while (true) + { + u8 shouldExist = (list_cur ? 1 : 0); + Do(shouldExist); + if (shouldExist == 1) + { + LinkedListItem<T>* cur = list_cur ? list_cur : TNew(); + TDo(*this, (T*)cur); + if (!list_cur) + { + if (mode == MODE_READ) + { + cur->next = 0; + list_cur = cur; + if (prev) + prev->next = cur; + else + list_start = cur; + } + else + { + TFree(cur); + continue; + } + } + } + else + { + if (mode == MODE_READ) + { + if (prev) + prev->next = 0; + if (list_end) + *list_end = prev; + if (list_cur) + { + if (list_start == list_cur) + list_start = 0; + do + { + LinkedListItem<T>* next = list_cur->next; + TFree(list_cur); + list_cur = next; + } + while (list_cur); + } + } + break; + } + prev = list_cur; + list_cur = list_cur->next; + } + } + + void DoMarker(const char* prevName, u32 arbitraryNumber=0x42) + { + u32 cookie = arbitraryNumber; + Do(cookie); + if(mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) + { + PanicAlertT("Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...", prevName, cookie, cookie, arbitraryNumber, arbitraryNumber); + SetError(ERROR_FAILURE); + } + } }; inline PointerWrapSection::~PointerWrapSection() { - if (ver_ > 0) { - p_.DoMarker(title_); - } + if (ver_ > 0) { + p_.DoMarker(title_); + } } class CChunkFileReader { public: - enum Error { - ERROR_NONE, - ERROR_BAD_FILE, - ERROR_BROKEN_STATE, - }; - - // Load file template - template<class T> - static Error Load(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class, std::string* _failureReason) - { - INFO_LOG(COMMON, "ChunkReader: Loading %s" , _rFilename.c_str()); - _failureReason->clear(); - _failureReason->append("LoadStateWrongVersion"); - - if (!File::Exists(_rFilename)) { - _failureReason->clear(); - _failureReason->append("LoadStateDoesntExist"); - ERROR_LOG(COMMON, "ChunkReader: File doesn't exist"); - return ERROR_BAD_FILE; - } - - // Check file size - const u64 fileSize = File::GetSize(_rFilename); - static const u64 headerSize = sizeof(SChunkHeader); - if (fileSize < headerSize) - { - ERROR_LOG(COMMON,"ChunkReader: File too small"); - return ERROR_BAD_FILE; - } - - File::IOFile pFile(_rFilename, "rb"); - if (!pFile) - { - ERROR_LOG(COMMON,"ChunkReader: Can't open file for reading"); - return ERROR_BAD_FILE; - } - - // read the header - SChunkHeader header; - if (!pFile.ReadArray(&header, 1)) - { - ERROR_LOG(COMMON,"ChunkReader: Bad header size"); - return ERROR_BAD_FILE; - } - - // Check revision - if (header.Revision != _Revision) - { - ERROR_LOG(COMMON,"ChunkReader: Wrong file revision, got %d expected %d", - header.Revision, _Revision); - return ERROR_BAD_FILE; - } - - if (strcmp(header.GitVersion, _VersionString) != 0) - { - WARN_LOG(COMMON, "This savestate was generated by a different version of PPSSPP, %s. It may not load properly.", - header.GitVersion); - } - - // get size - const int sz = (int)(fileSize - headerSize); - if (header.ExpectedSize != sz) - { - ERROR_LOG(COMMON,"ChunkReader: Bad file size, got %d expected %d", - sz, header.ExpectedSize); - return ERROR_BAD_FILE; - } - - // read the state - u8* buffer = new u8[sz]; - if (!pFile.ReadBytes(buffer, sz)) - { - ERROR_LOG(COMMON,"ChunkReader: Error reading file"); - return ERROR_BAD_FILE; - } - - u8 *ptr = buffer; - u8 *buf = buffer; - if (header.Compress) { - u8 *uncomp_buffer = new u8[header.UncompressedSize]; - size_t uncomp_size = header.UncompressedSize; - snappy_uncompress((const char *)buffer, sz, (char *)uncomp_buffer, &uncomp_size); - if ((int)uncomp_size != header.UncompressedSize) { - ERROR_LOG(COMMON,"Size mismatch: file: %i calc: %i", (int)header.UncompressedSize, (int)uncomp_size); - } - ptr = uncomp_buffer; - buf = uncomp_buffer; - delete [] buffer; - } - - PointerWrap p(&ptr, PointerWrap::MODE_READ); - _class.DoState(p); - delete[] buf; - - INFO_LOG(COMMON, "ChunkReader: Done loading %s" , _rFilename.c_str()); - if (p.error != p.ERROR_FAILURE) { - return ERROR_NONE; - } else { - return ERROR_BROKEN_STATE; - } - } - - // Save file template - template<class T> - static Error Save(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class) - { - INFO_LOG(COMMON, "ChunkReader: Writing %s" , _rFilename.c_str()); - - File::IOFile pFile(_rFilename, "wb"); - if (!pFile) - { - ERROR_LOG(COMMON,"ChunkReader: Error opening file for write"); - return ERROR_BAD_FILE; - } - - bool compress = true; - - // Get data - u8 *ptr = 0; - PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); - _class.DoState(p); - size_t const sz = (size_t)ptr; - - u8 * buffer = new u8[sz]; - ptr = &buffer[0]; - p.SetMode(PointerWrap::MODE_WRITE); - _class.DoState(p); - - // Create header - SChunkHeader header; - header.Compress = compress ? 1 : 0; - header.Revision = _Revision; - header.ExpectedSize = (int)sz; - header.UncompressedSize = (int)sz; - strncpy(header.GitVersion, _VersionString, 32); - header.GitVersion[31] = '\0'; - - // Write to file - if (compress) { - size_t comp_len = snappy_max_compressed_length(sz); - u8 *compressed_buffer = new u8[comp_len]; - snappy_compress((const char *)buffer, sz, (char *)compressed_buffer, &comp_len); - delete [] buffer; - header.ExpectedSize = (int)comp_len; - if (!pFile.WriteArray(&header, 1)) - { - ERROR_LOG(COMMON,"ChunkReader: Failed writing header"); - return ERROR_BAD_FILE; - } - if (!pFile.WriteBytes(&compressed_buffer[0], comp_len)) { - ERROR_LOG(COMMON,"ChunkReader: Failed writing compressed data"); - return ERROR_BAD_FILE; - } else { - INFO_LOG(COMMON, "Savestate: Compressed %i bytes into %i", (int)sz, (int)comp_len); - } - delete [] compressed_buffer; - } else { - if (!pFile.WriteArray(&header, 1)) - { - ERROR_LOG(COMMON,"ChunkReader: Failed writing header"); - return ERROR_BAD_FILE; - } - if (!pFile.WriteBytes(&buffer[0], sz)) - { - ERROR_LOG(COMMON,"ChunkReader: Failed writing data"); - return ERROR_BAD_FILE; - } - delete [] buffer; - } - - INFO_LOG(COMMON,"ChunkReader: Done writing %s", - _rFilename.c_str()); - if (p.error != p.ERROR_FAILURE) { - return ERROR_NONE; - } else { - return ERROR_BROKEN_STATE; - } - } - - template <class T> - static Error Verify(T& _class) - { - u8 *ptr = 0; - - // Step 1: Measure the space required. - PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); - _class.DoState(p); - size_t const sz = (size_t)ptr; - std::vector<u8> buffer(sz); - - // Step 2: Dump the state. - ptr = &buffer[0]; - p.SetMode(PointerWrap::MODE_WRITE); - _class.DoState(p); - - // Step 3: Verify the state. - ptr = &buffer[0]; - p.SetMode(PointerWrap::MODE_VERIFY); - _class.DoState(p); - - return ERROR_NONE; - } + enum Error { + ERROR_NONE, + ERROR_BAD_FILE, + ERROR_BROKEN_STATE, + }; + + // Load file template + template<class T> + static Error Load(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class, std::string* _failureReason) + { + INFO_LOG(COMMON, "ChunkReader: Loading %s" , _rFilename.c_str()); + _failureReason->clear(); + _failureReason->append("LoadStateWrongVersion"); + + if (!File::Exists(_rFilename)) { + _failureReason->clear(); + _failureReason->append("LoadStateDoesntExist"); + ERROR_LOG(COMMON, "ChunkReader: File doesn't exist"); + return ERROR_BAD_FILE; + } + + // Check file size + const u64 fileSize = File::GetSize(_rFilename); + static const u64 headerSize = sizeof(SChunkHeader); + if (fileSize < headerSize) + { + ERROR_LOG(COMMON,"ChunkReader: File too small"); + return ERROR_BAD_FILE; + } + + File::IOFile pFile(_rFilename, "rb"); + if (!pFile) + { + ERROR_LOG(COMMON,"ChunkReader: Can't open file for reading"); + return ERROR_BAD_FILE; + } + + // read the header + SChunkHeader header; + if (!pFile.ReadArray(&header, 1)) + { + ERROR_LOG(COMMON,"ChunkReader: Bad header size"); + return ERROR_BAD_FILE; + } + + // Check revision + if (header.Revision != _Revision) + { + ERROR_LOG(COMMON,"ChunkReader: Wrong file revision, got %d expected %d", + header.Revision, _Revision); + return ERROR_BAD_FILE; + } + + if (strcmp(header.GitVersion, _VersionString) != 0) + { + WARN_LOG(COMMON, "This savestate was generated by a different version of PPSSPP, %s. It may not load properly.", + header.GitVersion); + } + + // get size + const int sz = (int)(fileSize - headerSize); + if (header.ExpectedSize != sz) + { + ERROR_LOG(COMMON,"ChunkReader: Bad file size, got %d expected %d", + sz, header.ExpectedSize); + return ERROR_BAD_FILE; + } + + // read the state + u8* buffer = new u8[sz]; + if (!pFile.ReadBytes(buffer, sz)) + { + ERROR_LOG(COMMON,"ChunkReader: Error reading file"); + return ERROR_BAD_FILE; + } + + u8 *ptr = buffer; + u8 *buf = buffer; + if (header.Compress) { + u8 *uncomp_buffer = new u8[header.UncompressedSize]; + size_t uncomp_size = header.UncompressedSize; + snappy_uncompress((const char *)buffer, sz, (char *)uncomp_buffer, &uncomp_size); + if ((int)uncomp_size != header.UncompressedSize) { + ERROR_LOG(COMMON,"Size mismatch: file: %i calc: %i", (int)header.UncompressedSize, (int)uncomp_size); + } + ptr = uncomp_buffer; + buf = uncomp_buffer; + delete [] buffer; + } + + PointerWrap p(&ptr, PointerWrap::MODE_READ); + _class.DoState(p); + delete[] buf; + + INFO_LOG(COMMON, "ChunkReader: Done loading %s" , _rFilename.c_str()); + if (p.error != p.ERROR_FAILURE) { + return ERROR_NONE; + } else { + return ERROR_BROKEN_STATE; + } + } + + // Save file template + template<class T> + static Error Save(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class) + { + INFO_LOG(COMMON, "ChunkReader: Writing %s" , _rFilename.c_str()); + + File::IOFile pFile(_rFilename, "wb"); + if (!pFile) + { + ERROR_LOG(COMMON,"ChunkReader: Error opening file for write"); + return ERROR_BAD_FILE; + } + + bool compress = true; + + // Get data + u8 *ptr = 0; + PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); + _class.DoState(p); + size_t const sz = (size_t)ptr; + + u8 * buffer = new u8[sz]; + ptr = &buffer[0]; + p.SetMode(PointerWrap::MODE_WRITE); + _class.DoState(p); + + // Create header + SChunkHeader header; + header.Compress = compress ? 1 : 0; + header.Revision = _Revision; + header.ExpectedSize = (int)sz; + header.UncompressedSize = (int)sz; + strncpy(header.GitVersion, _VersionString, 32); + header.GitVersion[31] = '\0'; + + // Write to file + if (compress) { + size_t comp_len = snappy_max_compressed_length(sz); + u8 *compressed_buffer = new u8[comp_len]; + snappy_compress((const char *)buffer, sz, (char *)compressed_buffer, &comp_len); + delete [] buffer; + header.ExpectedSize = (int)comp_len; + if (!pFile.WriteArray(&header, 1)) + { + ERROR_LOG(COMMON,"ChunkReader: Failed writing header"); + return ERROR_BAD_FILE; + } + if (!pFile.WriteBytes(&compressed_buffer[0], comp_len)) { + ERROR_LOG(COMMON,"ChunkReader: Failed writing compressed data"); + return ERROR_BAD_FILE; + } else { + INFO_LOG(COMMON, "Savestate: Compressed %i bytes into %i", (int)sz, (int)comp_len); + } + delete [] compressed_buffer; + } else { + if (!pFile.WriteArray(&header, 1)) + { + ERROR_LOG(COMMON,"ChunkReader: Failed writing header"); + return ERROR_BAD_FILE; + } + if (!pFile.WriteBytes(&buffer[0], sz)) + { + ERROR_LOG(COMMON,"ChunkReader: Failed writing data"); + return ERROR_BAD_FILE; + } + delete [] buffer; + } + + INFO_LOG(COMMON,"ChunkReader: Done writing %s", + _rFilename.c_str()); + if (p.error != p.ERROR_FAILURE) { + return ERROR_NONE; + } else { + return ERROR_BROKEN_STATE; + } + } + + template <class T> + static Error Verify(T& _class) + { + u8 *ptr = 0; + + // Step 1: Measure the space required. + PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); + _class.DoState(p); + size_t const sz = (size_t)ptr; + std::vector<u8> buffer(sz); + + // Step 2: Dump the state. + ptr = &buffer[0]; + p.SetMode(PointerWrap::MODE_WRITE); + _class.DoState(p); + + // Step 3: Verify the state. + ptr = &buffer[0]; + p.SetMode(PointerWrap::MODE_VERIFY); + _class.DoState(p); + + return ERROR_NONE; + } private: - struct SChunkHeader - { - int Revision; - int Compress; - int ExpectedSize; - int UncompressedSize; - char GitVersion[32]; - }; + struct SChunkHeader + { + int Revision; + int Compress; + int ExpectedSize; + int UncompressedSize; + char GitVersion[32]; + }; }; #endif // _POINTERWRAP_H_ |