diff --git a/src/fceu.h b/src/fceu.h index 3783fc3f..bc5663ac 100644 --- a/src/fceu.h +++ b/src/fceu.h @@ -1,6 +1,32 @@ #ifndef _FCEUH #define _FCEUH +#include +#include + +class sane_stringbuf : public std::stringbuf +{ +public: + friend class memorystream; +}; + +class memorystream : public std::basic_iostream > +{ +public: + memorystream() + : std::basic_iostream >(&_Stringbuffer) + { // construct empty character buffer + } + + sane_stringbuf _Stringbuffer; + + friend class sane_stringbuf; + + public: + char* buf() { return _Stringbuffer.pbase(); } + int size() { return tellp(); } +}; + extern int fceuindbg; void ResetGameLoaded(void); diff --git a/src/movie.cpp b/src/movie.cpp index 428c03f7..b8f3a96c 100644 --- a/src/movie.cpp +++ b/src/movie.cpp @@ -26,6 +26,7 @@ extern char FileBase[]; extern int EmulationPaused; extern bool moviePleaseLogSavestates; +using namespace std; //TODO - remove the synchack stuff from the replay gui and require it to be put into the fm2 file //which the user would have already converted from fcm @@ -167,6 +168,12 @@ void MovieData::installDictionary(TDictionary& dictionary) } } +void MovieData::dump(std::ostream *os) +{ + *os << "version " << version; + *os << "emuVersion " << emuVersion; +} + void MovieData::dump(FILE *fp) { fprintf(fp,"version %d\n", version); @@ -624,6 +631,22 @@ void FCEU_DrawMovies(uint8 *XBuf) } } +int FCEUMOV_WriteState(std::ostream* os) +{ + //we are supposed to dump the movie data into the savestate + + if(movieMode == MOVIEMODE_RECORD || movieMode == MOVIEMODE_PLAY) + { + int todo = currMovieData.dumpLen(); + + if(os) + currMovieData.dump(os); + + return todo; + } + else return 0; +} + int FCEUMOV_WriteState(FILE* st) { //we are supposed to dump the movie data into the savestate diff --git a/src/movie.h b/src/movie.h index 654ac110..e8473910 100644 --- a/src/movie.h +++ b/src/movie.h @@ -4,6 +4,7 @@ #include #include #include +#include void FCEUMOV_AddJoy(uint8 *, int SkipFlush); void FCEUMOV_AddCommand(int cmd); @@ -14,6 +15,7 @@ bool FCEUMOV_ShouldPause(void); int FCEUMOV_GetFrame(void); int FCEUMOV_WriteState(FILE* st); +int FCEUMOV_WriteState(std::ostream* os); bool FCEUMOV_ReadState(FILE* st, uint32 size); void FCEUMOV_PreLoad(void); int FCEUMOV_PostLoad(void); @@ -58,6 +60,7 @@ public: std::vector savestate; void dump(FILE* fp, int index); + void dump(std::ostream* os, int index); static const char mnemonics[8]; @@ -122,6 +125,7 @@ public: void truncateAt(int frame); void installDictionary(TDictionary& dictionary); void dump(FILE *fp); + void dump(std::ostream* os); int dumpLen(); void clearRecordRange(int start, int len); diff --git a/src/state.cpp b/src/state.cpp index fe9c33da..e91ec666 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -28,6 +28,7 @@ //#include //mbg merge 7/17/06 removed #include +#include #include "types.h" #include "x6502.h" @@ -89,6 +90,49 @@ SFORMAT SFCPUC[]={ { 0 } }; +static int SubWrite(std::ostream* os, SFORMAT *sf) +{ + uint32 acc=0; + + while(sf->v) + { + if(sf->s==~0) /* Link to another struct. */ + { + uint32 tmp; + + if(!(tmp=SubWrite(os,(SFORMAT *)sf->v))) + return(0); + acc+=tmp; + sf++; + continue; + } + + acc+=8; /* Description + size */ + acc+=sf->s&(~RLSB); + + if(os) /* Are we writing or calculating the size of this block? */ + { + os->write(sf->desc,4); + write32le(sf->s&(~RLSB),os); + + #ifndef LSB_FIRST + if(sf->s&RLSB) + FlipByteOrder(sf->v,sf->s&(~RLSB)); + #endif + + os->write((char*)sf->v,sf->s&(~RLSB)); + /* Now restore the original byte order. */ + #ifndef LSB_FIRST + if(sf->s&RLSB) + FlipByteOrder(sf->v,sf->s&(~RLSB)); + #endif + } + sf++; + } + + return(acc); +} + static int SubWrite(FILE *st, SFORMAT *sf) { uint32 acc=0; @@ -132,13 +176,26 @@ static int SubWrite(FILE *st, SFORMAT *sf) return(acc); } +static int WriteStateChunk(std::ostream* os, int type, SFORMAT *sf) +{ + os->put(type); + int bsize = SubWrite((std::ostream*)0,sf); + write32le(bsize,os); + + if(!SubWrite(os,sf)) + { + return 5; + } + return (bsize+5); +} + static int WriteStateChunk(FILE *st, int type, SFORMAT *sf) { int bsize; fputc(type,st); - bsize=SubWrite(0,sf); + bsize=SubWrite((FILE*)0,sf); write32le(bsize,st); if(!SubWrite(st,sf)) @@ -313,54 +370,48 @@ extern int geniestage; bool FCEUSS_SaveFP(FILE *st) { - FILE* tmp = tmpfile(); + //a temporary buffer. we're goign to put the savestate in here and then compress it + memorystream ms; + std::ostream* os = (std::ostream*)&ms; uint32 totalsize = 0; FCEUPPU_SaveState(); FCEUSND_SaveState(); - totalsize=WriteStateChunk(tmp,1,SFCPU); - totalsize+=WriteStateChunk(tmp,2,SFCPUC); - totalsize+=WriteStateChunk(tmp,3,FCEUPPU_STATEINFO); - totalsize+=WriteStateChunk(tmp,4,FCEUCTRL_STATEINFO); - totalsize+=WriteStateChunk(tmp,5,FCEUSND_STATEINFO); + totalsize=WriteStateChunk(os,1,SFCPU); + totalsize+=WriteStateChunk(os,2,SFCPUC); + totalsize+=WriteStateChunk(os,3,FCEUPPU_STATEINFO); + totalsize+=WriteStateChunk(os,4,FCEUCTRL_STATEINFO); + totalsize+=WriteStateChunk(os,5,FCEUSND_STATEINFO); if(FCEUI_IsMovieActive()) { - totalsize+=WriteStateChunk(tmp,6,FCEUMOV_STATEINFO); - uint32 size = FCEUMOV_WriteState(0); - fputc(7,tmp); - write32le(size, tmp); - FCEUMOV_WriteState(tmp); + totalsize+=WriteStateChunk(os,6,FCEUMOV_STATEINFO); + uint32 size = FCEUMOV_WriteState((std::ostream*)0); + os->put(7); + write32le(size, os); + FCEUMOV_WriteState(os); totalsize += 5 + size; } // save back buffer { extern uint8 *XBackBuf; uint32 size = 256 * 256 + 8; - fputc(8,tmp); - write32le(size, tmp); - fwrite(XBackBuf,1,size,tmp); + os->put(8); + write32le(size, os); + os->write((char*)XBackBuf,size); totalsize += 5 + size; } if(SPreSave) SPreSave(); - totalsize+=WriteStateChunk(tmp,0x10,SFMDATA); + totalsize+=WriteStateChunk(os,0x10,SFMDATA); if(SPreSave) SPostSave(); //save the length of the file - int len = (int)ftell(tmp); + int len = ms.size(); - //reload the savestate from the tempfile - fseek(tmp,0,SEEK_SET); - std::vector buf(len); - fread(&buf[0],1,len,tmp); - fclose(tmp); - - //compress it uint8* cbuf = new uint8[len*2]; //worst case compression, lets say twice the input buffer size uLongf comprlen = len*2; - //int error = compress2(cbuf,&comprlen,&buf[0],len,Z_BEST_COMPRESSION); - int error = compress2(cbuf,&comprlen,&buf[0],len,Z_BEST_SPEED); + int error = compress2(cbuf,&comprlen,(uint8*)ms.buf(),len,Z_BEST_SPEED); //dump the header uint8 header[16]="FCSX"; @@ -369,6 +420,7 @@ bool FCEUSS_SaveFP(FILE *st) FCEU_en32lsb(header+12, comprlen); //dump it to the destination file + fwrite(header,1,16,st); fwrite(cbuf,1,comprlen,st); diff --git a/src/utils/endian.cpp b/src/utils/endian.cpp index 75458e10..589089b6 100644 --- a/src/utils/endian.cpp +++ b/src/utils/endian.cpp @@ -65,6 +65,17 @@ int write32le(uint32 b, FILE *fp) return((fwrite(s,1,4,fp)<4)?0:4); } +int write32le(uint32 b, std::ostream* os) +{ + uint8 s[4]; + s[0]=b; + s[1]=b>>8; + s[2]=b>>16; + s[3]=b>>24; + os->write((char*)&s,4); + return 4; +} + ///reads a little endian 32bit value from the specified file int read32le(uint32 *Bufo, FILE *fp) { diff --git a/src/utils/endian.h b/src/utils/endian.h index 3dcaaff9..4b92918b 100644 --- a/src/utils/endian.h +++ b/src/utils/endian.h @@ -3,6 +3,7 @@ int write16le(uint16 b, FILE *fp); int write32le(uint32 b, FILE *fp); +int write32le(uint32 b, std::ostream* os); int read32le(uint32 *Bufo, FILE *fp); void FlipByteOrder(uint8 *src, uint32 count); @@ -11,4 +12,4 @@ uint64 FCEU_de64lsb(uint8 *morp); uint32 FCEU_de32lsb(uint8 *morp); uint16 FCEU_de16lsb(uint8 *morp); -#endif +#endif