clean up the binary save state api a bit

This commit is contained in:
goyuken 2013-12-17 21:26:15 +00:00
parent 0582ef4c42
commit 8bd8af15fe
4 changed files with 135 additions and 106 deletions

View File

@ -1,24 +1,55 @@
using System; using System;
using ICSharpCode.SharpZipLib.Zip; using ICSharpCode.SharpZipLib.Zip;
using System.IO; using System.IO;
using System.Collections.Generic;
namespace BizHawk.Client.Common namespace BizHawk.Client.Common
{ {
public class BinaryStateFileNames public class BinaryStateFileNames
{ {
/*
public const string Versiontag = "BizState 1.0"; public const string Versiontag = "BizState 1.0";
public const string Corestate = "Core"; public const string Corestate = "Core";
public const string Framebuffer = "Framebuffer"; public const string Framebuffer = "Framebuffer";
public const string Input = "Input Log"; public const string Input = "Input Log";
public const string CorestateText = "CoreText"; public const string CorestateText = "CoreText";
public const string Movieheader = "Header"; public const string Movieheader = "Header";
*/
private static Dictionary<BinaryStateLump, string> LumpNames;
static BinaryStateFileNames()
{
LumpNames = new Dictionary<BinaryStateLump, string>();
LumpNames[BinaryStateLump.Versiontag] = "BizState 1.0";
LumpNames[BinaryStateLump.Corestate] = "Core";
LumpNames[BinaryStateLump.Framebuffer] = "Framebuffer";
LumpNames[BinaryStateLump.Input] = "Input Log";
LumpNames[BinaryStateLump.CorestateText] = "CoreText";
LumpNames[BinaryStateLump.Movieheader] = "Header";
}
public static string Get(BinaryStateLump Lump) { return LumpNames[Lump]; }
} }
public enum BinaryStateLump
{
Versiontag,
Corestate,
Framebuffer,
Input,
CorestateText,
Movieheader
};
/// <summary> /// <summary>
/// more accurately should be called ZipStateLoader, as it supports both text and binary core data /// more accurately should be called ZipStateLoader, as it supports both text and binary core data
/// </summary> /// </summary>
public class BinaryStateLoader : IDisposable public class BinaryStateLoader : IDisposable
{ {
private bool isDisposed; private bool isDisposed;
public void Dispose() public void Dispose()
{ {
@ -76,8 +107,7 @@ namespace BizHawk.Client.Common
try try
{ {
ret.zip = new ZipFile(Filename); ret.zip = new ZipFile(Filename);
var e = ret.zip.GetEntry(BinaryStateFileNames.Versiontag); if (!ret.GetLump(BinaryStateLump.Versiontag, false, ret.ReadVersion))
if (!ret.GetFileByName(BinaryStateFileNames.Versiontag, false, ret.ReadVersion))
{ {
ret.zip.Close(); ret.zip.Close();
return null; return null;
@ -90,8 +120,16 @@ namespace BizHawk.Client.Common
} }
} }
bool GetFileByName(string Name, bool abort, Action<Stream> callback) /// <summary>
///
/// </summary>
/// <param name="Lump">lump to retriever</param>
/// <param name="abort">true to throw exception on failure</param>
/// <param name="callback">function to call with the desired stream</param>
/// <returns>true if callback was called and stream was loaded</returns>
public bool GetLump(BinaryStateLump Lump, bool abort, Action<Stream> callback)
{ {
string Name = BinaryStateFileNames.Get(Lump);
var e = zip.GetEntry(Name); var e = zip.GetEntry(Name);
if (e != null) if (e != null)
{ {
@ -111,13 +149,44 @@ namespace BizHawk.Client.Common
} }
} }
public bool GetLump(BinaryStateLump Lump, bool abort, Action<BinaryReader> callback)
{
return GetLump(Lump, abort, delegate(Stream s)
{
BinaryReader br = new BinaryReader(s);
callback(br);
});
}
public bool GetLump(BinaryStateLump Lump, bool abort, Action<TextReader> callback)
{
return GetLump(Lump, abort, delegate(Stream s)
{
TextReader tr = new StreamReader(s);
callback(tr);
});
}
/// <summary>
/// load binary state, or text state if binary state lump doesn't exist
/// </summary>
/// <param name="callbackBinary"></param>
/// <param name="callbackText"></param>
public void GetCoreState(Action<Stream> callbackBinary, Action<Stream> callbackText) public void GetCoreState(Action<Stream> callbackBinary, Action<Stream> callbackText)
{ {
if (!GetFileByName(BinaryStateFileNames.Corestate, false, callbackBinary) if (!GetLump(BinaryStateLump.Corestate, false, callbackBinary)
&& !GetFileByName(BinaryStateFileNames.CorestateText, false, callbackText)) && !GetLump(BinaryStateLump.CorestateText, false, callbackText))
throw new Exception("Couldn't find Binary or Text savestate"); throw new Exception("Couldn't find Binary or Text savestate");
} }
public void GetCoreState(Action<BinaryReader> callbackBinary, Action<TextReader> callbackText)
{
if (!GetLump(BinaryStateLump.Corestate, false, callbackBinary)
&& !GetLump(BinaryStateLump.CorestateText, false, callbackText))
throw new Exception("Couldn't find Binary or Text savestate");
}
/*
public bool GetFrameBuffer(Action<Stream> callback) public bool GetFrameBuffer(Action<Stream> callback)
{ {
return GetFileByName(BinaryStateFileNames.Framebuffer, false, callback); return GetFileByName(BinaryStateFileNames.Framebuffer, false, callback);
@ -132,6 +201,7 @@ namespace BizHawk.Client.Common
{ {
GetFileByName(BinaryStateFileNames.Movieheader, true, callback); GetFileByName(BinaryStateFileNames.Movieheader, true, callback);
} }
*/
} }
public class BinaryStateSaver : IDisposable public class BinaryStateSaver : IDisposable
@ -158,17 +228,39 @@ namespace BizHawk.Client.Common
}; };
zip.SetLevel(0); zip.SetLevel(0);
PutFileByName(BinaryStateFileNames.Versiontag, WriteVersion); PutLump(BinaryStateLump.Versiontag, WriteVersion);
} }
void PutFileByName(string Name, Action<Stream> callback) public void PutLump(BinaryStateLump Lump, Action<Stream> callback)
{ {
string Name = BinaryStateFileNames.Get(Lump);
var e = new ZipEntry(Name) {CompressionMethod = CompressionMethod.Stored}; var e = new ZipEntry(Name) {CompressionMethod = CompressionMethod.Stored};
zip.PutNextEntry(e); zip.PutNextEntry(e);
callback(zip); callback(zip);
zip.CloseEntry(); zip.CloseEntry();
} }
public void PutLump(BinaryStateLump Lump, Action<BinaryWriter> callback)
{
PutLump(Lump, delegate(Stream s)
{
BinaryWriter bw = new BinaryWriter(s);
callback(bw);
bw.Flush();
});
}
public void PutLump(BinaryStateLump Lump, Action<TextWriter> callback)
{
PutLump(Lump, delegate(Stream s)
{
TextWriter tw = new StreamWriter(s);
callback(tw);
tw.Flush();
});
}
/*
public void PutCoreStateBinary(Action<Stream> callback) public void PutCoreStateBinary(Action<Stream> callback)
{ {
PutFileByName(BinaryStateFileNames.Corestate, callback); PutFileByName(BinaryStateFileNames.Corestate, callback);
@ -193,6 +285,7 @@ namespace BizHawk.Client.Common
{ {
PutFileByName(BinaryStateFileNames.Movieheader, callback); PutFileByName(BinaryStateFileNames.Movieheader, callback);
} }
*/
private bool isDisposed; private bool isDisposed;
public void Dispose() public void Dispose()

View File

@ -30,44 +30,24 @@ namespace BizHawk.Client.Common
using (BinaryStateSaver bs = new BinaryStateSaver(fs)) using (BinaryStateSaver bs = new BinaryStateSaver(fs))
{ {
#if true #if true
bs.PutCoreStateBinary( bs.PutLump(BinaryStateLump.Corestate, (bw) => Global.Emulator.SaveStateBinary(bw));
delegate(Stream s)
{
BinaryWriter bw = new BinaryWriter(s);
Global.Emulator.SaveStateBinary(bw);
bw.Flush();
});
#else #else
// this would put text states inside the zipfile // this would put text states inside the zipfile
bs.PutCoreStateText( bs.PutLump(BinaryStateLump.CorestateText, (tw) => Global.Emulator.SaveStateText(tw));
delegate(Stream s)
{
StreamWriter sw = new StreamWriter(s);
Global.Emulator.SaveStateText(sw);
sw.Flush();
});
#endif #endif
if (Global.Config.SaveScreenshotWithStates) if (Global.Config.SaveScreenshotWithStates)
{ {
bs.PutFrameBuffer( var buff = Global.Emulator.VideoProvider.GetVideoBuffer();
delegate(Stream s) bs.PutLump(BinaryStateLump.Framebuffer, (BinaryWriter bw) => bw.Write(buff));
{
var buff = Global.Emulator.VideoProvider.GetVideoBuffer();
BinaryWriter bw = new BinaryWriter(s);
bw.Write(buff);
bw.Flush();
});
} }
if (Global.MovieSession.Movie.IsActive) if (Global.MovieSession.Movie.IsActive)
{ {
bs.PutInputLog( bs.PutLump(BinaryStateLump.Input,
delegate(Stream s) delegate(TextWriter tw)
{ {
StreamWriter sw = new StreamWriter(s);
// this never should have been a core's responsibility // this never should have been a core's responsibility
sw.WriteLine("Frame {0}", Global.Emulator.Frame); tw.WriteLine("Frame {0}", Global.Emulator.Frame);
Global.MovieSession.HandleMovieSaveState(sw); Global.MovieSession.HandleMovieSaveState(tw);
sw.Flush();
}); });
} }
} }
@ -77,8 +57,8 @@ namespace BizHawk.Client.Common
public static bool LoadStateFile(string path, string name) public static bool LoadStateFile(string path, string name)
{ {
// try to detect binary first // try to detect binary first
BinaryStateLoader bw = BinaryStateLoader.LoadAndDetect(path); BinaryStateLoader bl = BinaryStateLoader.LoadAndDetect(path);
if (bw != null) if (bl != null)
{ {
try try
{ {
@ -86,34 +66,16 @@ namespace BizHawk.Client.Common
if (Global.MovieSession.Movie.IsActive) if (Global.MovieSession.Movie.IsActive)
{ {
bw.GetInputLogRequired( bl.GetLump(BinaryStateLump.Input, true, (tr) => succeed = Global.MovieSession.HandleMovieLoadState(tr));
delegate(Stream s)
{
StreamReader sr = new StreamReader(s);
succeed = Global.MovieSession.HandleMovieLoadState(sr);
});
if (!succeed) if (!succeed)
{
return false; return false;
}
} }
bw.GetCoreState( bl.GetCoreState((br) => Global.Emulator.LoadStateBinary(br), (tr) => Global.Emulator.LoadStateText(tr));
delegate(Stream s)
{
BinaryReader br = new BinaryReader(s);
Global.Emulator.LoadStateBinary(br);
},
delegate(Stream s)
{
StreamReader sr = new StreamReader(s);
Global.Emulator.LoadStateText(sr);
});
bw.GetFrameBuffer( bl.GetLump(BinaryStateLump.Framebuffer, false,
delegate(Stream s) delegate(BinaryReader br)
{ {
BinaryReader br = new BinaryReader(s);
int i; int i;
var buff = Global.Emulator.VideoProvider.GetVideoBuffer(); var buff = Global.Emulator.VideoProvider.GetVideoBuffer();
try try
@ -129,7 +91,7 @@ namespace BizHawk.Client.Common
} }
finally finally
{ {
bw.Dispose(); bl.Dispose();
} }
return true; return true;

View File

@ -96,7 +96,7 @@ namespace BizHawk.Client.Common
} }
} }
public void HandleMovieSaveState(StreamWriter writer) public void HandleMovieSaveState(TextWriter writer)
{ {
if (Movie.IsActive) if (Movie.IsActive)
{ {
@ -185,7 +185,7 @@ namespace BizHawk.Client.Common
} }
} }
public bool HandleMovieLoadState(StreamReader reader) public bool HandleMovieLoadState(TextReader reader)
{ {
if (!Movie.IsActive) if (!Movie.IsActive)
{ {
@ -223,8 +223,9 @@ namespace BizHawk.Client.Common
Movie.SwitchToRecord(); Movie.SwitchToRecord();
} }
reader.BaseStream.Position = 0; // fixme: this is evil
reader.DiscardBufferedData(); ((StreamReader)reader).BaseStream.Position = 0;
((StreamReader)reader).DiscardBufferedData();
var result = Movie.ExtractInputLog(reader, out errorMsg); var result = Movie.ExtractInputLog(reader, out errorMsg);
if (!result) if (!result)
{ {

View File

@ -314,31 +314,29 @@ namespace BizHawk.Client.Common
return false; return false;
} }
// there's a lot of common code here with SavestateManager. refactor? // there's a lot of common code here with SavestateManager. refactor?
using (BinaryStateLoader bw = BinaryStateLoader.LoadAndDetect(Filename)) using (BinaryStateLoader bl = BinaryStateLoader.LoadAndDetect(Filename))
{ {
if (bw == null) if (bl == null)
return false; return false;
Header.Clear(); Header.Clear();
_records.Clear(); _records.Clear();
bw.GetMovieHeaderRequired( bl.GetLump(BinaryStateLump.Movieheader, true,
delegate(Stream s) delegate(TextReader tr)
{ {
StreamReader sr = new StreamReader(s);
string line; string line;
while ((line = sr.ReadLine()) != null) while ((line = tr.ReadLine()) != null)
if (!Header.ParseLineFromFile(line)) if (!Header.ParseLineFromFile(line))
Header.Comments.Add(line); Header.Comments.Add(line);
}); });
bw.GetInputLogRequired( bl.GetLump(BinaryStateLump.Input, true,
delegate(Stream s) delegate(TextReader tr)
{ {
StreamReader sr = new StreamReader(s);
string line = String.Empty; string line = String.Empty;
while (true) while (true)
{ {
line = sr.ReadLine(); line = tr.ReadLine();
if (line == null) if (line == null)
{ {
break; break;
@ -354,7 +352,7 @@ namespace BizHawk.Client.Common
if (Header.StartsFromSavestate) if (Header.StartsFromSavestate)
{ {
// should we raise some sort of error if there's a savestate in the archive but Header.StartsFromSavestate is false? // should we raise some sort of error if there's a savestate in the archive but Header.StartsFromSavestate is false?
bw.GetCoreState( bl.GetCoreState(
delegate(Stream s) delegate(Stream s)
{ {
BinaryReader br = new BinaryReader(s); BinaryReader br = new BinaryReader(s);
@ -366,10 +364,9 @@ namespace BizHawk.Client.Common
Global.Emulator.LoadStateText(sr); Global.Emulator.LoadStateText(sr);
}); });
} }
bw.GetFrameBuffer( bl.GetLump(BinaryStateLump.Framebuffer, false,
delegate(Stream s) delegate(BinaryReader br)
{ {
BinaryReader br = new BinaryReader(s);
int i; int i;
var buff = Global.Emulator.VideoProvider.GetVideoBuffer(); var buff = Global.Emulator.VideoProvider.GetVideoBuffer();
try try
@ -395,38 +392,14 @@ namespace BizHawk.Client.Common
using (FileStream fs = new FileStream(Filename, FileMode.Create, FileAccess.Write)) using (FileStream fs = new FileStream(Filename, FileMode.Create, FileAccess.Write))
using (BinaryStateSaver bs = new BinaryStateSaver(fs)) using (BinaryStateSaver bs = new BinaryStateSaver(fs))
{ {
bs.PutMovieHeader( bs.PutLump(BinaryStateLump.Movieheader, (tw) => tw.WriteLine(Header.ToString()));
delegate(Stream s) bs.PutLump(BinaryStateLump.Input, (tw) => tw.WriteLine(GetInputLog()));
{
StreamWriter sw = new StreamWriter(s);
sw.WriteLine(Header.ToString());
sw.Flush();
});
bs.PutInputLog(
delegate(Stream s)
{
StreamWriter sw = new StreamWriter(s);
sw.WriteLine(GetInputLog());
sw.Flush();
});
if (Header.StartsFromSavestate) if (Header.StartsFromSavestate)
{ {
#if true #if true
bs.PutCoreStateText( bs.PutLump(BinaryStateLump.CorestateText, (tw) => Global.Emulator.SaveStateText(tw));
delegate(Stream s)
{
StreamWriter sw = new StreamWriter(s);
Global.Emulator.SaveStateText(sw);
sw.Flush();
});
#else #else
bs.PutCoreStateBinary( bs.PutLump(BinaryStateLump.Corestate, (bw) => Global.Emulator.SaveStateBinary(bw));
delegate(Stream s)
{
BinaryWriter bw = new BinaryWriter(s);
Global.Emulator.SaveStateBinary(bw);
bw.Flush();
});
#endif #endif
} }
} }