using System; using ICSharpCode.SharpZipLib.Zip; using System.IO; using System.Collections.Generic; namespace BizHawk.Client.Common { public class BinaryStateFileNames { /* public const string Versiontag = "BizState 1.0"; public const string Corestate = "Core"; public const string Framebuffer = "Framebuffer"; public const string Input = "Input Log"; public const string CorestateText = "CoreText"; public const string Movieheader = "Header"; */ private static Dictionary LumpNames; static BinaryStateFileNames() { LumpNames = new Dictionary(); 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 }; /// /// more accurately should be called ZipStateLoader, as it supports both text and binary core data /// public class BinaryStateLoader : IDisposable { private bool isDisposed; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!isDisposed) { isDisposed = true; if (disposing) { zip.Close(); } } } ZipFile zip; Version ver; private BinaryStateLoader() { } private void ReadVersion(Stream s) { // the "BizState 1.0" tag contains an integer in it describing the sub version. if (s.Length == 0) ver = new Version(1, 0, 0); // except for the first release, which doesn't else { StreamReader sr = new StreamReader(s); ver = new Version(1, 0, int.Parse(sr.ReadLine())); } Console.WriteLine("Read a zipstate of version {0}", ver.ToString()); } public static BinaryStateLoader LoadAndDetect(string Filename) { BinaryStateLoader ret = new BinaryStateLoader(); //PORTABLE TODO - SKIP THIS.. FOR NOW //check whether its an archive before we try opening it int offset; bool isExecutable; bool isArchive; using(var archiveChecker = new SevenZipSharpArchiveHandler()) isArchive = archiveChecker.CheckSignature(Filename, out offset, out isExecutable); if(!isArchive) return null; try { ret.zip = new ZipFile(Filename); if (!ret.GetLump(BinaryStateLump.Versiontag, false, ret.ReadVersion)) { ret.zip.Close(); return null; } return ret; } catch (ZipException) { return null; } } /// /// /// /// lump to retriever /// true to throw exception on failure /// function to call with the desired stream /// true if callback was called and stream was loaded public bool GetLump(BinaryStateLump Lump, bool abort, Action callback) { string Name = BinaryStateFileNames.Get(Lump); var e = zip.GetEntry(Name); if (e != null) { using (Stream zs = zip.GetInputStream(e)) { callback(zs); } return true; } else if (abort) { throw new Exception("Essential zip section not found: " + Name); } else { return false; } } public bool GetLump(BinaryStateLump Lump, bool abort, Action callback) { return GetLump(Lump, abort, delegate(Stream s) { BinaryReader br = new BinaryReader(s); callback(br); }); } public bool GetLump(BinaryStateLump Lump, bool abort, Action callback) { return GetLump(Lump, abort, delegate(Stream s) { TextReader tr = new StreamReader(s); callback(tr); }); } /// /// load binary state, or text state if binary state lump doesn't exist /// /// /// public void GetCoreState(Action callbackBinary, Action callbackText) { if (!GetLump(BinaryStateLump.Corestate, false, callbackBinary) && !GetLump(BinaryStateLump.CorestateText, false, callbackText)) throw new Exception("Couldn't find Binary or Text savestate"); } public void GetCoreState(Action callbackBinary, Action 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 callback) { return GetFileByName(BinaryStateFileNames.Framebuffer, false, callback); } public void GetInputLogRequired(Action callback) { GetFileByName(BinaryStateFileNames.Input, true, callback); } public void GetMovieHeaderRequired(Action callback) { GetFileByName(BinaryStateFileNames.Movieheader, true, callback); } */ } public class BinaryStateSaver : IDisposable { private readonly ZipOutputStream zip; private void WriteVersion(Stream s) { StreamWriter sw = new StreamWriter(s); sw.WriteLine("1"); // version 1.0.1 sw.Flush(); } /// /// /// /// not closed when finished! public BinaryStateSaver(Stream s) { zip = new ZipOutputStream(s) { IsStreamOwner = false, UseZip64 = UseZip64.Off }; zip.SetLevel(0); PutLump(BinaryStateLump.Versiontag, WriteVersion); } public void PutLump(BinaryStateLump Lump, Action callback) { string Name = BinaryStateFileNames.Get(Lump); var e = new ZipEntry(Name) {CompressionMethod = CompressionMethod.Stored}; zip.PutNextEntry(e); callback(zip); zip.CloseEntry(); } public void PutLump(BinaryStateLump Lump, Action callback) { PutLump(Lump, delegate(Stream s) { BinaryWriter bw = new BinaryWriter(s); callback(bw); bw.Flush(); }); } public void PutLump(BinaryStateLump Lump, Action callback) { PutLump(Lump, delegate(Stream s) { TextWriter tw = new StreamWriter(s); callback(tw); tw.Flush(); }); } /* public void PutCoreStateBinary(Action callback) { PutFileByName(BinaryStateFileNames.Corestate, callback); } public void PutCoreStateText(Action callback) { PutFileByName(BinaryStateFileNames.CorestateText, callback); } public void PutFrameBuffer(Action callback) { PutFileByName(BinaryStateFileNames.Framebuffer, callback); } public void PutInputLog(Action callback) { PutFileByName(BinaryStateFileNames.Input, callback); } public void PutMovieHeader(Action callback) { PutFileByName(BinaryStateFileNames.Movieheader, callback); } */ private bool isDisposed; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!isDisposed) { isDisposed = true; if (disposing) { zip.Close(); } } } } }