|
|
|
@ -32,35 +32,10 @@ |
|
|
|
#include <string> |
|
|
|
#include <list> |
|
|
|
#include <set> |
|
|
|
#ifndef __SYMBIAN32__ |
|
|
|
#if defined(IOS) || defined(MACGNUSTD) |
|
|
|
#include <tr1/type_traits> |
|
|
|
#else |
|
|
|
#include <type_traits> |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
#include "common/common.h" |
|
|
|
#include "common/file_util.h" |
|
|
|
//#include "../ext/snappy/snappy-c.h" |
|
|
|
|
|
|
|
#if defined(IOS) || defined(MACGNUSTD) |
|
|
|
namespace std { |
|
|
|
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> {}; |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
template <class T> |
|
|
|
struct LinkedListItem : public T |
|
|
|
@ -651,222 +626,3 @@ inline PointerWrapSection::~PointerWrapSection() { |
|
|
|
p_.DoMarker(title_); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Commented out because it is currently unused, and breaks builds on OSX |
|
|
|
/*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 (!FileUtil::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 = FileUtil::GetSize(_rFilename); |
|
|
|
static const u64 headerSize = sizeof(SChunkHeader); |
|
|
|
if (fileSize < headerSize) |
|
|
|
{ |
|
|
|
ERROR_LOG(COMMON,"ChunkReader: File too small"); |
|
|
|
return ERROR_BAD_FILE; |
|
|
|
} |
|
|
|
|
|
|
|
FileUtil::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()); |
|
|
|
|
|
|
|
FileUtil::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]; |
|
|
|
}; |
|
|
|
}; */ |