diff --git a/src/driver.h b/src/driver.h index 5e1ba25e..c7bee01d 100644 --- a/src/driver.h +++ b/src/driver.h @@ -3,11 +3,13 @@ #include #include +#include #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 diff --git a/src/drivers/win/main.cpp b/src/drivers/win/main.cpp index ae98b9f4..92044938 100644 --- a/src/drivers/win/main.cpp +++ b/src/drivers/win/main.cpp @@ -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, '+')) diff --git a/src/movie.cpp b/src/movie.cpp index 2ad15ff2..dd484886 100644 --- a/src/movie.cpp +++ b/src/movie.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #ifdef WIN32 #include @@ -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* buf) +bool MovieData::loadSavestateFrom(std::vector* buf) { //dump the savestate to disk FILE* fp = tmpfile(); @@ -430,19 +431,10 @@ bool MovieData::loadSavestateFrom(std::vector* buf) return success; } -void MovieData::dumpSavestateTo(std::vector* buf) +void MovieData::dumpSavestateTo(std::vector* 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 diff --git a/src/movie.h b/src/movie.h index e8473910..5e813c63 100644 --- a/src/movie.h +++ b/src/movie.h @@ -57,7 +57,7 @@ public: } //a waste of memory in lots of cases.. maybe make it a pointer later? - std::vector savestate; + std::vector 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 savestate; + std::vector savestate; std::vector 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* buf); - static void dumpSavestateTo(std::vector* buf); + static bool loadSavestateFrom(std::vector* buf); + static void dumpSavestateTo(std::vector* buf, int compressionLevel); void TryDumpIncremental(); }; diff --git a/src/netplay.cpp b/src/netplay.cpp index c8a455b8..2af83900 100644 --- a/src/netplay.cpp +++ b/src/netplay.cpp @@ -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)) diff --git a/src/state.cpp b/src/state.cpp index 0d2bcff9..c668b077 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -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; diff --git a/src/state.h b/src/state.h index 465c1daf..943247f8 100644 --- a/src/state.h +++ b/src/state.h @@ -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; diff --git a/src/utils/memorystream.h b/src/utils/memorystream.h index db8e1958..98e8f48a 100644 --- a/src/utils/memorystream.h +++ b/src/utils/memorystream.h @@ -2,13 +2,14 @@ #include #include +template 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* 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* _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& out) + void toVector(std::vector& 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 toVector() + std::vector toVector() { - return std::vector(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(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 > public: memorystream() : std::basic_iostream >(&streambuf) - { - } + {} + + memorystream(char* usebuf, int buflength) + : streambuf(usebuf, buflength) + , std::basic_iostream >(&streambuf) + {} + + memorystream(std::vector* usevec) + : streambuf(usevec) + , std::basic_iostream >(&streambuf) + {} //the underlying memory_streambuf - memory_streambuf streambuf; + memory_streambuf 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); } -}; \ No newline at end of file +};