more savestate things work better

This commit is contained in:
zeromus 2008-06-03 05:01:07 +00:00
parent c013dd96e6
commit 7a9721e48a
8 changed files with 128 additions and 54 deletions

View File

@ -3,11 +3,13 @@
#include <stdio.h>
#include <string>
#include <fstream>
#include "types.h"
#include "git.h"
FILE *FCEUD_UTF8fopen(const char *fn, const char *mode);
std::fstream* FCEUD_UTF8_fstream(const char *n, const char *m);
//mbg 7/23/06

View File

@ -1235,6 +1235,30 @@ static void FCEUD_MakePathDirs(const char *fname)
} while(1);
}
std::fstream* FCEUD_UTF8_fstream(const char *n, const char *m)
{
if(strchr(m, 'w') || strchr(m, '+'))
{
FCEUD_MakePathDirs(n);
}
std::ios_base::open_mode mode = std::ios_base::binary;
if(!strcmp(m,"r"))
mode |= std::ios_base::in;
else if(!strcmp(m,"w"))
mode |= std::ios_base::out | std::ios_base::trunc;
else if(!strcmp(m,"a"))
mode |= std::ios_base::out | std::ios_base::app;
else if(!strcmp(m,"r+"))
mode |= std::ios_base::in | std::ios_base::out;
else if(!strcmp(m,"w+"))
mode |= std::ios_base::in | std::ios_base::out | std::ios_base::trunc;
else if(!strcmp(m,"a+"))
mode |= std::ios_base::in | std::ios_base::out | std::ios_base::app;
return new std::fstream(n,mode);
}
FILE *FCEUD_UTF8fopen(const char *n, const char *m)
{
if(strchr(m, 'w') || strchr(m, '+'))

View File

@ -2,6 +2,7 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <zlib.h>
#ifdef WIN32
#include <windows.h>
@ -86,7 +87,7 @@ void MovieData::TryDumpIncremental()
{
if(currFrameCounter < (int)currMovieData.records.size())
{
MovieData::dumpSavestateTo(&currMovieData.records[currFrameCounter].savestate);
MovieData::dumpSavestateTo(&currMovieData.records[currFrameCounter].savestate,Z_NO_COMPRESSION);
currMovieData.greenZoneCount++;
}
}
@ -417,7 +418,7 @@ static void ResetInputTypes()
#endif
}
bool MovieData::loadSavestateFrom(std::vector<uint8>* buf)
bool MovieData::loadSavestateFrom(std::vector<char>* buf)
{
//dump the savestate to disk
FILE* fp = tmpfile();
@ -430,19 +431,10 @@ bool MovieData::loadSavestateFrom(std::vector<uint8>* buf)
return success;
}
void MovieData::dumpSavestateTo(std::vector<uint8>* buf)
void MovieData::dumpSavestateTo(std::vector<char>* buf, int compressionLevel)
{
//dump a savestate to a tempfile..
FILE* tmp = tmpfile();
FCEUSS_SaveFP(tmp,-1);
//reloading the savestate into the data structure
fseek(tmp,0,SEEK_END);
int len = (int)ftell(tmp);
fseek(tmp,0,SEEK_SET);
buf->resize(len);
fread(&(*buf)[0],1,len,tmp);
fclose(tmp);
memorystream ms(buf);
FCEUSS_SaveMS(&ms,compressionLevel);
}
//begin playing an existing movie
@ -577,7 +569,7 @@ void FCEUI_SaveMovie(char *fname, uint8 flags)
}
else
{
MovieData::dumpSavestateTo(&currMovieData.savestate);
MovieData::dumpSavestateTo(&currMovieData.savestate,Z_BEST_COMPRESSION);
}
//we are going to go ahead and dump the header. from now on we will only be appending frames

View File

@ -57,7 +57,7 @@ public:
}
//a waste of memory in lots of cases.. maybe make it a pointer later?
std::vector<uint8> savestate;
std::vector<char> savestate;
void dump(FILE* fp, int index);
void dump(std::ostream* os, int index);
@ -82,7 +82,7 @@ public:
bool resetFlag;
MD5DATA romChecksum;
std::string romFilename;
std::vector<uint8> savestate;
std::vector<char> savestate;
std::vector<MovieRecord> records;
//this is the RERECORD COUNT. please rename variable.
int recordCount;
@ -129,8 +129,8 @@ public:
int dumpLen();
void clearRecordRange(int start, int len);
static bool loadSavestateFrom(std::vector<uint8>* buf);
static void dumpSavestateTo(std::vector<uint8>* buf);
static bool loadSavestateFrom(std::vector<char>* buf);
static void dumpSavestateTo(std::vector<char>* buf, int compressionLevel);
void TryDumpIncremental();
};

View File

@ -276,7 +276,7 @@ void NetplayUpdate(uint8 *joyp)
fn = FCEU_MakeFName(FCEUMKF_NPTEMP,0,0);
fp = fopen(fn, "wb");
if(FCEUSS_SaveFP(fp,-1))
if(FCEUSS_SaveFP(fp,Z_BEST_COMPRESSION))
{
fclose(fp);
if(!FCEUNET_SendFile(FCEUNPCMD_LOADSTATE, fn))

View File

@ -368,9 +368,19 @@ static int ReadStateChunks(FILE *st, int32 totalsize)
int CurrentState=1;
extern int geniestage;
bool FCEUSS_SaveFP(FILE *st, int compressionLevel)
bool FCEUSS_SaveFP(FILE* fp, int compressionLevel)
{
//a temporary buffer. we're going to put the savestate in here and then compress it
memorystream ms;
bool ret = FCEUSS_SaveMS(&ms,compressionLevel);
fwrite(ms.buf(),1,ms.size(),fp);
return ret;
}
bool FCEUSS_SaveMS(std::ostream* outstream, int compressionLevel)
{
//a temp memory stream. we'll dump some data here and then compress
//TODO - support dumping directly without compressing to save a buffer copy
memorystream ms;
std::ostream* os = (std::ostream*)&ms;
@ -426,7 +436,7 @@ bool FCEUSS_SaveFP(FILE *st, int compressionLevel)
int error = Z_OK;
uint8* cbuf = (uint8*)ms.buf();
uLongf comprlen = -1;
//if(compressionLevel != Z_NO_COMPRESSION)
if(compressionLevel != Z_NO_COMPRESSION)
{
//worst case compression.
//zlib says "0.1% larger than sourceLen plus 12 bytes"
@ -442,8 +452,8 @@ bool FCEUSS_SaveFP(FILE *st, int compressionLevel)
FCEU_en32lsb(header+12, comprlen);
//dump it to the destination file
fwrite(header,1,16,st);
fwrite(cbuf,1,comprlen,st);
outstream->write((char*)header,16);
outstream->write((char*)cbuf,comprlen);
if(cbuf != (uint8*)ms.buf()) delete[] cbuf;
return error == Z_OK;

View File

@ -29,7 +29,11 @@ enum ENUM_SSLOADPARAMS
void FCEUSS_Save(char *);
int FCEUSS_Load(char *);
bool FCEUSS_SaveFP(FILE *, int compressionLevel); //zlib values: 0 (none) through 9 (max) or -1 (default)
//zlib values: 0 (none) through 9 (max) or -1 (default)
bool FCEUSS_SaveMS(std::ostream* outstream, int compressionLevel);
bool FCEUSS_SaveFP(FILE* fp, int compressionLevel);
bool FCEUSS_LoadFP(FILE *, ENUM_SSLOADPARAMS);
extern int CurrentState;

View File

@ -2,13 +2,14 @@
#include <vector>
#include <sstream>
template<typename T>
class memory_streambuf: public std::streambuf {
private:
friend class memorystream;
//the current buffer
char* buf;
T* buf;
//the current allocated capacity of the buffer
size_t capacity;
@ -21,6 +22,9 @@ private:
//the current 'write window' starting position within the buffer for writing.
size_t ww;
//a vector that we have been told to use
std::vector<T>* usevec;
public:
@ -36,11 +40,39 @@ public:
: length(0)
, myBuf(true)
, ww(0)
, buf(new char[capacity = 8])
, buf(new T[capacity = 128])
, usevec(0)
{
sync();
}
//constructs a non-expandable streambuf around the provided buffer
memory_streambuf(T* usebuf, int buflength)
: length(buflength)
, myBuf(false)
, buf(usebuf)
, ww(0)
, usevec(0)
{
sync();
}
//constructs an expandable streambuf around the provided buffer
memory_streambuf(std::vector<T>* _usevec)
: usevec(_usevec)
, length(_usevec->size())
, capacity(_usevec->size())
, myBuf(false)
, ww(0)
{
if(length>0)
buf = &(*_usevec)[0];
else buf = 0;
sync();
}
~memory_streambuf()
{
//only cleanup if we own the seq
@ -48,26 +80,16 @@ public:
}
//to avoid copying, rebuilds the provided vector and copies the streambuf contents into it
void toVector(std::vector<char>& out)
void toVector(std::vector<T>& out)
{
out.reserve(length);
out.resize(length);
memcpy(&out[0],buf,length);
}
//maybe the compiler can avoid copying, but maybe not: returns a vector representing the current streambuf
std::vector<char> toVector()
std::vector<T> toVector()
{
return std::vector<char>(buf,buf+length);
}
//constructs a non-expandable streambuf around the provided buffer
memory_streambuf(char* usebuf, int buflength)
: length(buflength)
, myBuf(false)
, buf(usebuf)
, ww(0)
{
sync();
return std::vector<T>(buf,buf+length);
}
//tells the current read or write position
@ -98,7 +120,7 @@ public:
return 0;
}
char* getbuf()
T* getbuf()
{
sync();
return buf;
@ -131,7 +153,7 @@ private:
void expand(size_t upto)
{
if(!myBuf)
if(!myBuf && !usevec)
throw new std::exception("memory_streambuf is not expandable");
size_t newcapacity;
@ -139,14 +161,25 @@ private:
newcapacity = capacity + capacity/2 + 2;
else
newcapacity = std::max(upto,capacity);
if(newcapacity == capacity) return;
char* newbuf = new char[newcapacity];
memcpy(newbuf,buf,capacity);
delete[] buf;
capacity = newcapacity;
buf = newbuf;
//if we are supposed to use the vector, then do it now
if(usevec)
{
usevec->resize(newcapacity);
capacity = usevec->size();
buf = &(*usevec)[0];
}
else
{
//otherwise, manage our own buffer
T* newbuf = new T[newcapacity];
memcpy(newbuf,buf,capacity);
delete[] buf;
capacity = newcapacity;
buf = newbuf;
}
}
protected:
@ -197,11 +230,20 @@ class memorystream : public std::basic_iostream<char, std::char_traits<char> >
public:
memorystream()
: std::basic_iostream<char, std::char_traits<char> >(&streambuf)
{
}
{}
memorystream(char* usebuf, int buflength)
: streambuf(usebuf, buflength)
, std::basic_iostream<char, std::char_traits<char> >(&streambuf)
{}
memorystream(std::vector<char>* usevec)
: streambuf(usevec)
, std::basic_iostream<char, std::char_traits<char> >(&streambuf)
{}
//the underlying memory_streambuf
memory_streambuf streambuf;
memory_streambuf<char> streambuf;
public:
@ -212,4 +254,4 @@ public:
void sync() { streambuf.sync(); }
//rewinds the cursors to offset 0
void rewind() { streambuf.seekpos(0,std::ios::in | std::ios::out); }
};
};