compress savestates, and movie no longer needs to do any compression itsself.

savestate compatibility is now broken.
This commit is contained in:
zeromus 2008-05-24 21:25:20 +00:00
parent bf6d70c56d
commit e524818f1e
3 changed files with 132 additions and 94 deletions

View File

@ -22,7 +22,6 @@
#include "movie.h" #include "movie.h"
#include "utils/memory.h" #include "utils/memory.h"
#include "utils/xstring.h" #include "utils/xstring.h"
#include "zlib.h"
#define MOVIE_MAGIC 0x1a4d4346 // FCM\x1a #define MOVIE_MAGIC 0x1a4d4346 // FCM\x1a
@ -438,22 +437,15 @@ void FCEUI_LoadMovie(char *fname, int _read_only, int _pauseframe)
//WE NEED TO LOAD A SAVESTATE //WE NEED TO LOAD A SAVESTATE
if(!currMovieData.poweronFlag) if(!currMovieData.poweronFlag)
{ {
//uncompress the savestate //dump the savestate to disk
int bufsize = ntohl(*(int*)&currMovieData.savestate[0]);
uint8* buf = new uint8[bufsize];
uLongf uncomprlen = bufsize;
uncompress(buf,&uncomprlen,(uint8*)&currMovieData.savestate[4],currMovieData.savestate.size()-4);
//dump it to disk
FILE* fp = tmpfile(); FILE* fp = tmpfile();
fwrite(buf,1,bufsize,fp); fwrite(&currMovieData.savestate[0],1,currMovieData.savestate.size(),fp);
fseek(fp,0,SEEK_SET); fseek(fp,0,SEEK_SET);
//and load the state //and load the state
bool success = FCEUSS_LoadFP(fp,SSLOADPARAM_BACKUP); bool success = FCEUSS_LoadFP(fp,SSLOADPARAM_BACKUP);
fclose(fp); fclose(fp);
delete[] buf;
if(!success) return; if(!success) return;
} }
@ -525,27 +517,14 @@ void FCEUI_SaveMovie(char *fname, uint8 flags, const char* metadata)
//dump a savestate to a tempfile.. //dump a savestate to a tempfile..
FILE* tmp = tmpfile(); FILE* tmp = tmpfile();
FCEUSS_SaveFP(tmp); FCEUSS_SaveFP(tmp);
//reloading the savestate into the data structure
fseek(tmp,0,SEEK_END); fseek(tmp,0,SEEK_END);
int len = (int)ftell(tmp); int len = (int)ftell(tmp);
fseek(tmp,0,SEEK_SET); fseek(tmp,0,SEEK_SET);
//reloading the savestate from the tempfile.. currMovieData.savestate.resize(len);
uint8* buf = new uint8[len]; fread(&currMovieData.savestate[0],1,len,tmp);
fread(buf,1,len,tmp);
fclose(tmp); fclose(tmp);
//compress it
uint8* cbuf = new uint8[len*2]; //worst case compression, lets say twice the input buffer size
uLongf destlen;
int error = compress2(cbuf,&destlen,buf,len,Z_BEST_COMPRESSION);
//poke it in the data structure
currMovieData.savestate.resize(destlen+4);
memcpy(&currMovieData.savestate[4],cbuf,destlen);
*(int*)&currMovieData.savestate[0] = htonl(len);
//cleanup
delete[] buf;
delete[] cbuf;
} }
//we are going to go ahead and dump the header. from now on we will only be appending frames //we are going to go ahead and dump the header. from now on we will only be appending frames

View File

@ -27,6 +27,8 @@
#include <string.h> #include <string.h>
//#include <unistd.h> //mbg merge 7/17/06 removed //#include <unistd.h> //mbg merge 7/17/06 removed
#include <vector>
#include "types.h" #include "types.h"
#include "x6502.h" #include "x6502.h"
#include "fceu.h" #include "fceu.h"
@ -41,6 +43,7 @@
#include "netplay.h" #include "netplay.h"
#include "video.h" #include "video.h"
#include "input.h" #include "input.h"
#include "zlib.h"
static void (*SPreSave)(void); static void (*SPreSave)(void);
static void (*SPostSave)(void); static void (*SPostSave)(void);
@ -305,56 +308,73 @@ static int ReadStateChunks(FILE *st, int32 totalsize)
return ret; return ret;
} }
int CurrentState=1; int CurrentState=1;
extern int geniestage; extern int geniestage;
int FCEUSS_SaveFP(FILE *st) bool FCEUSS_SaveFP(FILE *st)
{ {
static uint32 totalsize; FILE* tmp = tmpfile();
static uint8 header[16]="FCS";
uint32 writeoffset;
writeoffset = ftell(st); uint32 totalsize = 0;
memset(header+4,0,13);
header[3]=0xFF; FCEUPPU_SaveState();
FCEU_en32lsb(header + 8, FCEU_VERSION_NUMERIC); FCEUSND_SaveState();
fwrite(header,1,16,st); totalsize=WriteStateChunk(tmp,1,SFCPU);
FCEUPPU_SaveState(); totalsize+=WriteStateChunk(tmp,2,SFCPUC);
FCEUSND_SaveState(); totalsize+=WriteStateChunk(tmp,3,FCEUPPU_STATEINFO);
totalsize=WriteStateChunk(st,1,SFCPU); totalsize+=WriteStateChunk(tmp,4,FCEUCTRL_STATEINFO);
totalsize+=WriteStateChunk(st,2,SFCPUC); totalsize+=WriteStateChunk(tmp,5,FCEUSND_STATEINFO);
totalsize+=WriteStateChunk(st,3,FCEUPPU_STATEINFO); if(FCEUI_IsMovieActive())
totalsize+=WriteStateChunk(st,4,FCEUCTRL_STATEINFO); {
totalsize+=WriteStateChunk(st,5,FCEUSND_STATEINFO); totalsize+=WriteStateChunk(tmp,6,FCEUMOV_STATEINFO);
if(FCEUI_IsMovieActive()) uint32 size = FCEUMOV_WriteState(0);
{ fputc(7,tmp);
totalsize+=WriteStateChunk(st,6,FCEUMOV_STATEINFO); write32le(size, tmp);
uint32 size = FCEUMOV_WriteState(0); FCEUMOV_WriteState(tmp);
fputc(7,st); totalsize += 5 + size;
write32le(size, st); }
FCEUMOV_WriteState(st); // save back buffer
totalsize += 5 + size; {
} extern uint8 *XBackBuf;
// save back buffer uint32 size = 256 * 256 + 8;
{ fputc(8,tmp);
extern uint8 *XBackBuf; write32le(size, tmp);
uint32 size = 256 * 256 + 8; fwrite(XBackBuf,1,size,tmp);
fputc(8,st); totalsize += 5 + size;
write32le(size, st); }
fwrite(XBackBuf,1,size,st);
totalsize += 5 + size;
}
if(SPreSave) SPreSave(); if(SPreSave) SPreSave();
totalsize+=WriteStateChunk(st,0x10,SFMDATA); totalsize+=WriteStateChunk(tmp,0x10,SFMDATA);
if(SPreSave) SPostSave(); if(SPreSave) SPostSave();
fseek(st,writeoffset+4,SEEK_SET); //save the length of the file
write32le(totalsize,st); int len = (int)ftell(tmp);
return(1);
//reload the savestate from the tempfile
fseek(tmp,0,SEEK_SET);
std::vector<uint8> 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;
int error = compress2(cbuf,&comprlen,&buf[0],len,Z_BEST_COMPRESSION);
//dump the header
uint8 header[16]="FCSX";
FCEU_en32lsb(header+4, totalsize);
FCEU_en32lsb(header+8, FCEU_VERSION_NUMERIC);
FCEU_en32lsb(header+12, comprlen);
//dump it to the destination file
fwrite(header,1,16,st);
fwrite(cbuf,1,comprlen,st);
return error == Z_OK;
} }
void FCEUSS_Save(char *fname) void FCEUSS_Save(char *fname)
{ {
FILE *st=NULL; FILE *st=NULL;
@ -392,14 +412,38 @@ void FCEUSS_Save(char *fname)
} }
} }
int FCEUSS_LoadFP(FILE *st, ENUM_SSLOADPARAMS params) bool FCEUSS_LoadFP(FILE *st, ENUM_SSLOADPARAMS params)
{ {
if(params==SSLOADPARAM_DUMMY && suppress_scan_chunks) if(params==SSLOADPARAM_DUMMY && suppress_scan_chunks)
return 1; return 1;
int x; ////--------------
////read and decompress the savestate
//uint32 comprlen, datalen;
//if(!read32le(&datalen,st))
// return false;
//if(!read32le(&comprlen,st))
// return false;
//
//std::vector<uint8> cbuf(comprlen);
//std::vector<uint8> buf(datalen);
//if(fread(&cbuf[0],1,comprlen,st) != comprlen)
// return false;
//uLongf uncomprlen = datalen;
//int error = uncompress(&buf[0],&uncomprlen,&cbuf[0],comprlen);
//if(error != Z_OK || uncomprlen != datalen)
// return false;
////dump savestate to a tempfile
//FILE* tmp = tmpfile();
//fwrite(&buf[0],0,datalen,tmp);
//fseek(tmp,0,SEEK_SET);
////-----------------
bool x;
uint8 header[16]; uint8 header[16];
int stateversion;
char* fn=0; char* fn=0;
//Make temporary savestate in case something screws up during the load //Make temporary savestate in case something screws up during the load
@ -425,36 +469,50 @@ int FCEUSS_LoadFP(FILE *st, ENUM_SSLOADPARAMS params)
} }
if(params!=SSLOADPARAM_DUMMY) if(params!=SSLOADPARAM_DUMMY)
{
FCEUMOV_PreLoad(); FCEUMOV_PreLoad();
}
//read and analyze the header
fread(&header,1,16,st); fread(&header,1,16,st);
if(memcmp(header,"FCS",3)) if(memcmp(header,"FCSX",4))
{ return false;
return(0); int totalsize = FCEU_de32lsb(header + 4);
} int stateversion = FCEU_de32lsb(header + 8);
if(header[3] == 0xFF) int comprlen = FCEU_de32lsb(header + 12);
{
stateversion = FCEU_de32lsb(header + 8); //load the compressed chunk and decompress
} std::vector<uint8> cbuf(comprlen);
else std::vector<uint8> buf(totalsize);
{ if(fread(&cbuf[0],1,comprlen,st) != comprlen)
stateversion=header[3] * 100; return false;
}
uLongf uncomprlen = totalsize;
int error = uncompress(&buf[0],&uncomprlen,&cbuf[0],comprlen);
if(error != Z_OK || uncomprlen != totalsize)
return false;
//dump it back to a tempfile
FILE* tmp = tmpfile();
fwrite(&buf[0],1,totalsize,tmp);
fseek(tmp,0,SEEK_SET);
if(params == SSLOADPARAM_DUMMY) if(params == SSLOADPARAM_DUMMY)
{ {
scan_chunks=1; scan_chunks=1;
} }
x=ReadStateChunks(st,*(uint32*)(header+4));
x = ReadStateChunks(tmp,totalsize)!=0;
if(params == SSLOADPARAM_DUMMY) if(params == SSLOADPARAM_DUMMY)
{ {
scan_chunks=0; scan_chunks=0;
return 1; fclose(tmp);
} return true;
if(read_sfcpuc && stateversion<9500)
{
X.IRQlow=0;
} }
//mbg 5/24/08 - we don't support old states, so this shouldnt matter.
//if(read_sfcpuc && stateversion<9500)
// X.IRQlow=0;
if(GameStateRestore) if(GameStateRestore)
{ {
GameStateRestore(stateversion); GameStateRestore(stateversion);
@ -463,7 +521,7 @@ int FCEUSS_LoadFP(FILE *st, ENUM_SSLOADPARAMS params)
{ {
FCEUPPU_LoadState(stateversion); FCEUPPU_LoadState(stateversion);
FCEUSND_LoadState(stateversion); FCEUSND_LoadState(stateversion);
x=FCEUMOV_PostLoad(); x=FCEUMOV_PostLoad()!=0;
} }
if(fn) if(fn)
@ -483,7 +541,8 @@ int FCEUSS_LoadFP(FILE *st, ENUM_SSLOADPARAMS params)
free(fn); free(fn);
} }
return(x); fclose(tmp);
return x;
} }
int FCEUSS_Load(char *fname) int FCEUSS_Load(char *fname)

View File

@ -29,8 +29,8 @@ enum ENUM_SSLOADPARAMS
void FCEUSS_Save(char *); void FCEUSS_Save(char *);
int FCEUSS_Load(char *); int FCEUSS_Load(char *);
int FCEUSS_SaveFP(FILE *); bool FCEUSS_SaveFP(FILE *);
int FCEUSS_LoadFP(FILE *, ENUM_SSLOADPARAMS); bool FCEUSS_LoadFP(FILE *, ENUM_SSLOADPARAMS);
extern int CurrentState; extern int CurrentState;
void FCEUSS_CheckStates(void); void FCEUSS_CheckStates(void);