2013-08-11 21:02:36 +00:00
|
|
|
|
using System;
|
2013-12-17 21:26:15 +00:00
|
|
|
|
using System.Collections.Generic;
|
2013-12-30 01:58:44 +00:00
|
|
|
|
using System.IO;
|
|
|
|
|
|
|
|
|
|
using ICSharpCode.SharpZipLib.Zip;
|
2014-10-09 23:39:13 +00:00
|
|
|
|
//using Ionic.Zip;
|
2013-08-11 21:02:36 +00:00
|
|
|
|
|
2013-10-27 07:54:00 +00:00
|
|
|
|
namespace BizHawk.Client.Common
|
2013-08-11 21:02:36 +00:00
|
|
|
|
{
|
2014-02-04 03:08:20 +00:00
|
|
|
|
public enum BinaryStateLump
|
|
|
|
|
{
|
|
|
|
|
Versiontag,
|
|
|
|
|
Corestate,
|
|
|
|
|
Framebuffer,
|
|
|
|
|
Input,
|
|
|
|
|
CorestateText,
|
2014-06-13 11:30:25 +00:00
|
|
|
|
|
|
|
|
|
// Only for movies they probably shoudln't be leaching this stuff
|
|
|
|
|
Movieheader,
|
|
|
|
|
Comments,
|
2014-06-14 00:42:45 +00:00
|
|
|
|
Subtitles,
|
2014-07-07 19:32:37 +00:00
|
|
|
|
SyncSettings,
|
|
|
|
|
|
|
|
|
|
// TasMovie
|
|
|
|
|
LagLog,
|
2014-07-09 16:35:39 +00:00
|
|
|
|
Greenzone,
|
2014-07-10 22:44:44 +00:00
|
|
|
|
GreenzoneSettings,
|
2014-10-14 18:09:30 +00:00
|
|
|
|
Markers,
|
2014-11-01 13:37:18 +00:00
|
|
|
|
ClientSettings,
|
|
|
|
|
VerificationLog
|
2014-02-04 03:08:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-10-09 23:39:13 +00:00
|
|
|
|
public static class BinaryStateFileNames
|
2013-08-11 21:02:36 +00:00
|
|
|
|
{
|
2014-08-19 00:59:02 +00:00
|
|
|
|
private static readonly Dictionary<BinaryStateLump, string> ReadNames;
|
|
|
|
|
private static readonly Dictionary<BinaryStateLump, string> WriteNames;
|
2013-12-17 21:26:15 +00:00
|
|
|
|
|
2014-08-19 00:59:02 +00:00
|
|
|
|
static void AddLumpName(BinaryStateLump token, string name)
|
|
|
|
|
{
|
|
|
|
|
ReadNames[token] = Path.GetFileNameWithoutExtension(name);
|
|
|
|
|
WriteNames[token] = name;
|
|
|
|
|
}
|
2013-12-17 21:26:15 +00:00
|
|
|
|
static BinaryStateFileNames()
|
|
|
|
|
{
|
2014-08-19 00:59:02 +00:00
|
|
|
|
ReadNames = new Dictionary<BinaryStateLump, string>();
|
|
|
|
|
WriteNames = new Dictionary<BinaryStateLump, string>();
|
|
|
|
|
AddLumpName(BinaryStateLump.Versiontag, "BizState 1.0");
|
|
|
|
|
AddLumpName(BinaryStateLump.Corestate, "Core");
|
|
|
|
|
AddLumpName(BinaryStateLump.Framebuffer, "Framebuffer");
|
|
|
|
|
AddLumpName(BinaryStateLump.Input, "Input Log.txt");
|
|
|
|
|
AddLumpName(BinaryStateLump.CorestateText, "CoreText.txt");
|
|
|
|
|
AddLumpName(BinaryStateLump.Movieheader, "Header.txt");
|
2014-06-13 11:30:25 +00:00
|
|
|
|
|
|
|
|
|
// Only for movies they probably shoudln't be leaching this stuff
|
2014-08-19 00:59:02 +00:00
|
|
|
|
AddLumpName(BinaryStateLump.Comments, "Comments.txt");
|
|
|
|
|
AddLumpName(BinaryStateLump.Subtitles, "Subtitles.txt");
|
|
|
|
|
AddLumpName(BinaryStateLump.SyncSettings, "SyncSettings.json");
|
2014-07-07 19:32:37 +00:00
|
|
|
|
|
|
|
|
|
// TasMovie
|
2014-08-19 00:59:02 +00:00
|
|
|
|
AddLumpName(BinaryStateLump.LagLog, "LagLog");
|
|
|
|
|
AddLumpName(BinaryStateLump.Greenzone, "GreenZone");
|
|
|
|
|
AddLumpName(BinaryStateLump.GreenzoneSettings, "GreenZoneSettings.txt");
|
|
|
|
|
AddLumpName(BinaryStateLump.Markers, "Markers.txt");
|
2014-10-14 18:09:30 +00:00
|
|
|
|
AddLumpName(BinaryStateLump.ClientSettings, "ClientSettings.json");
|
2014-11-01 13:37:18 +00:00
|
|
|
|
AddLumpName(BinaryStateLump.VerificationLog, "VerificationLog.txt");
|
2013-12-17 21:26:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-08-19 00:59:02 +00:00
|
|
|
|
public static string GetReadName(BinaryStateLump lump)
|
2014-01-08 03:53:53 +00:00
|
|
|
|
{
|
2014-08-19 00:59:02 +00:00
|
|
|
|
return ReadNames[lump];
|
|
|
|
|
}
|
|
|
|
|
public static string GetWriteName(BinaryStateLump lump)
|
|
|
|
|
{
|
|
|
|
|
return WriteNames[lump];
|
2014-01-08 03:53:53 +00:00
|
|
|
|
}
|
2013-08-11 21:02:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-07 21:23:23 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// more accurately should be called ZipStateLoader, as it supports both text and binary core data
|
|
|
|
|
/// </summary>
|
2013-08-11 21:02:36 +00:00
|
|
|
|
public class BinaryStateLoader : IDisposable
|
|
|
|
|
{
|
2014-02-04 03:08:20 +00:00
|
|
|
|
private ZipFile _zip;
|
|
|
|
|
private Version _ver;
|
2013-12-30 01:58:44 +00:00
|
|
|
|
private bool _isDisposed;
|
2014-08-19 00:59:02 +00:00
|
|
|
|
private Dictionary<string, ZipEntry> _entriesbyname;
|
2014-02-04 03:08:20 +00:00
|
|
|
|
|
|
|
|
|
private BinaryStateLoader()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-11 21:02:36 +00:00
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
2013-10-27 17:07:37 +00:00
|
|
|
|
Dispose(true);
|
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
|
|
|
{
|
2013-12-30 01:58:44 +00:00
|
|
|
|
if (!_isDisposed)
|
2013-08-11 21:02:36 +00:00
|
|
|
|
{
|
2013-12-30 01:58:44 +00:00
|
|
|
|
_isDisposed = true;
|
2013-10-27 17:07:37 +00:00
|
|
|
|
if (disposing)
|
|
|
|
|
{
|
2014-01-08 03:53:53 +00:00
|
|
|
|
_zip.Close();
|
2013-10-27 17:07:37 +00:00
|
|
|
|
}
|
2013-08-11 21:02:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-25 16:51:27 +00:00
|
|
|
|
private void ReadVersion(Stream s, long length)
|
2013-12-07 21:23:23 +00:00
|
|
|
|
{
|
|
|
|
|
// the "BizState 1.0" tag contains an integer in it describing the sub version.
|
2014-07-25 16:51:27 +00:00
|
|
|
|
if (length == 0)
|
2013-12-30 01:58:44 +00:00
|
|
|
|
{
|
2014-01-08 03:53:53 +00:00
|
|
|
|
_ver = new Version(1, 0, 0); // except for the first release, which doesn't
|
2013-12-30 01:58:44 +00:00
|
|
|
|
}
|
2013-12-07 21:23:23 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2013-12-30 01:58:44 +00:00
|
|
|
|
var sr = new StreamReader(s);
|
2014-01-08 03:53:53 +00:00
|
|
|
|
_ver = new Version(1, 0, int.Parse(sr.ReadLine()));
|
2013-12-07 21:23:23 +00:00
|
|
|
|
}
|
2014-01-08 03:53:53 +00:00
|
|
|
|
|
|
|
|
|
Console.WriteLine("Read a zipstate of version {0}", _ver);
|
2013-12-07 21:23:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-08-19 00:59:02 +00:00
|
|
|
|
private void PopulateEntries()
|
|
|
|
|
{
|
|
|
|
|
_entriesbyname = new Dictionary<string, ZipEntry>();
|
|
|
|
|
foreach (ZipEntry z in _zip)
|
|
|
|
|
{
|
|
|
|
|
_entriesbyname.Add(Path.GetFileNameWithoutExtension(z.Name), z);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-14 21:37:51 +00:00
|
|
|
|
public static BinaryStateLoader LoadAndDetect(string filename, bool isMovieLoad = false)
|
2013-08-11 21:02:36 +00:00
|
|
|
|
{
|
2013-12-30 01:58:44 +00:00
|
|
|
|
var ret = new BinaryStateLoader();
|
2013-12-03 18:24:24 +00:00
|
|
|
|
|
2013-12-30 01:58:44 +00:00
|
|
|
|
// PORTABLE TODO - SKIP THIS.. FOR NOW
|
|
|
|
|
// check whether its an archive before we try opening it
|
2013-12-03 18:24:24 +00:00
|
|
|
|
bool isArchive;
|
2013-12-30 01:58:44 +00:00
|
|
|
|
using (var archiveChecker = new SevenZipSharpArchiveHandler())
|
|
|
|
|
{
|
2014-01-08 03:53:53 +00:00
|
|
|
|
int offset;
|
|
|
|
|
bool isExecutable;
|
|
|
|
|
isArchive = archiveChecker.CheckSignature(filename, out offset, out isExecutable);
|
2013-12-30 01:58:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!isArchive)
|
|
|
|
|
{
|
2013-12-03 18:24:24 +00:00
|
|
|
|
return null;
|
2013-12-30 01:58:44 +00:00
|
|
|
|
}
|
2013-12-03 18:24:24 +00:00
|
|
|
|
|
2013-08-11 21:02:36 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
2014-01-08 03:53:53 +00:00
|
|
|
|
ret._zip = new ZipFile(filename);
|
2014-08-19 00:59:02 +00:00
|
|
|
|
ret.PopulateEntries();
|
2014-06-14 21:37:51 +00:00
|
|
|
|
if (!isMovieLoad && !ret.GetLump(BinaryStateLump.Versiontag, false, ret.ReadVersion))
|
2013-08-11 21:02:36 +00:00
|
|
|
|
{
|
2014-01-08 03:53:53 +00:00
|
|
|
|
ret._zip.Close();
|
2013-08-11 21:02:36 +00:00
|
|
|
|
return null;
|
|
|
|
|
}
|
2013-12-30 01:58:44 +00:00
|
|
|
|
|
2013-08-11 21:02:36 +00:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
catch (ZipException)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-15 15:55:41 +00:00
|
|
|
|
public bool HasLump(BinaryStateLump lump)
|
|
|
|
|
{
|
|
|
|
|
string name = BinaryStateFileNames.GetReadName(lump);
|
|
|
|
|
ZipEntry e;
|
|
|
|
|
return _entriesbyname.TryGetValue(name, out e);
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-17 21:26:15 +00:00
|
|
|
|
/// <summary>
|
2013-12-30 01:58:44 +00:00
|
|
|
|
/// Gets a lump
|
2013-12-17 21:26:15 +00:00
|
|
|
|
/// </summary>
|
2014-01-08 03:53:53 +00:00
|
|
|
|
/// <param name="lump">lump to retriever</param>
|
2013-12-17 21:26:15 +00:00
|
|
|
|
/// <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>
|
2014-07-25 16:51:27 +00:00
|
|
|
|
public bool GetLump(BinaryStateLump lump, bool abort, Action<Stream, long> callback)
|
2013-08-11 21:02:36 +00:00
|
|
|
|
{
|
2014-08-19 00:59:02 +00:00
|
|
|
|
string name = BinaryStateFileNames.GetReadName(lump);
|
|
|
|
|
ZipEntry e;
|
|
|
|
|
if (_entriesbyname.TryGetValue(name, out e))
|
2013-08-11 21:02:36 +00:00
|
|
|
|
{
|
2014-01-08 03:53:53 +00:00
|
|
|
|
using (var zs = _zip.GetInputStream(e))
|
2013-08-11 21:02:36 +00:00
|
|
|
|
{
|
2014-07-25 16:51:27 +00:00
|
|
|
|
callback(zs, e.Size);
|
2013-08-11 21:02:36 +00:00
|
|
|
|
}
|
2014-01-08 03:53:53 +00:00
|
|
|
|
|
2013-08-11 21:02:36 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
2014-02-04 03:08:20 +00:00
|
|
|
|
|
|
|
|
|
if (abort)
|
2013-08-11 21:02:36 +00:00
|
|
|
|
{
|
2014-02-04 03:08:20 +00:00
|
|
|
|
throw new Exception("Essential zip section not found: " + name);
|
2013-08-11 21:02:36 +00:00
|
|
|
|
}
|
2014-02-04 03:08:20 +00:00
|
|
|
|
|
|
|
|
|
return false;
|
2013-08-11 21:02:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-08 03:53:53 +00:00
|
|
|
|
public bool GetLump(BinaryStateLump lump, bool abort, Action<BinaryReader> callback)
|
2013-12-17 21:26:15 +00:00
|
|
|
|
{
|
2014-07-25 16:51:27 +00:00
|
|
|
|
return GetLump(lump, abort, delegate(Stream s, long unused)
|
2013-12-17 21:26:15 +00:00
|
|
|
|
{
|
2014-01-08 03:53:53 +00:00
|
|
|
|
var br = new BinaryReader(s);
|
2013-12-17 21:26:15 +00:00
|
|
|
|
callback(br);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-25 16:51:27 +00:00
|
|
|
|
public bool GetLump(BinaryStateLump lump, bool abort, Action<BinaryReader, long> callback)
|
|
|
|
|
{
|
|
|
|
|
return GetLump(lump, abort, delegate(Stream s, long length)
|
|
|
|
|
{
|
|
|
|
|
var br = new BinaryReader(s);
|
|
|
|
|
callback(br, length);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-08 03:53:53 +00:00
|
|
|
|
public bool GetLump(BinaryStateLump lump, bool abort, Action<TextReader> callback)
|
2013-12-17 21:26:15 +00:00
|
|
|
|
{
|
2014-07-25 16:51:27 +00:00
|
|
|
|
return GetLump(lump, abort, delegate(Stream s, long unused)
|
2013-12-17 21:26:15 +00:00
|
|
|
|
{
|
2014-01-08 03:53:53 +00:00
|
|
|
|
var tr = new StreamReader(s);
|
2013-12-17 21:26:15 +00:00
|
|
|
|
callback(tr);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-25 16:51:27 +00:00
|
|
|
|
public void GetCoreState(Action<BinaryReader, long> callbackBinary, Action<TextReader> callbackText)
|
2013-08-11 21:02:36 +00:00
|
|
|
|
{
|
2013-12-17 21:26:15 +00:00
|
|
|
|
if (!GetLump(BinaryStateLump.Corestate, false, callbackBinary)
|
2014-01-08 03:53:53 +00:00
|
|
|
|
&& !GetLump(BinaryStateLump.CorestateText, false, callbackText))
|
|
|
|
|
{
|
2013-12-17 21:26:15 +00:00
|
|
|
|
throw new Exception("Couldn't find Binary or Text savestate");
|
2014-01-08 03:53:53 +00:00
|
|
|
|
}
|
2013-12-17 21:26:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void GetCoreState(Action<BinaryReader> callbackBinary, Action<TextReader> callbackText)
|
|
|
|
|
{
|
|
|
|
|
if (!GetLump(BinaryStateLump.Corestate, false, callbackBinary)
|
2014-07-25 16:51:27 +00:00
|
|
|
|
&& !GetLump(BinaryStateLump.CorestateText, false, callbackText))
|
2014-01-08 03:53:53 +00:00
|
|
|
|
{
|
2013-12-07 21:23:23 +00:00
|
|
|
|
throw new Exception("Couldn't find Binary or Text savestate");
|
2014-01-08 03:53:53 +00:00
|
|
|
|
}
|
2013-08-11 21:02:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class BinaryStateSaver : IDisposable
|
|
|
|
|
{
|
2014-10-09 23:39:13 +00:00
|
|
|
|
private readonly IZipWriter _zip;
|
2014-02-04 03:08:20 +00:00
|
|
|
|
private bool _isDisposed;
|
2013-08-11 21:02:36 +00:00
|
|
|
|
|
2014-01-08 03:53:53 +00:00
|
|
|
|
private static void WriteVersion(Stream s)
|
2013-12-07 21:23:23 +00:00
|
|
|
|
{
|
2013-12-30 01:58:44 +00:00
|
|
|
|
var sw = new StreamWriter(s);
|
2013-12-07 21:23:23 +00:00
|
|
|
|
sw.WriteLine("1"); // version 1.0.1
|
|
|
|
|
sw.Flush();
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-12 04:24:31 +00:00
|
|
|
|
|
|
|
|
|
public BinaryStateSaver(string path, bool stateVersionTag = true) // stateVersionTag is a hack for reusing this for movie code
|
2013-08-11 21:02:36 +00:00
|
|
|
|
{
|
2014-11-28 17:36:05 +00:00
|
|
|
|
_zip = new IonicZipWriter(path, Global.Config.SaveStateCompressionLevelNormal);
|
2014-10-12 04:24:31 +00:00
|
|
|
|
//_zip = new SharpZipWriter(path, Global.Config.SaveStateCompressionLevelNormal);
|
2014-11-28 17:36:05 +00:00
|
|
|
|
//_zip = new SevenZipWriter(path, Global.Config.SaveStateCompressionLevelNormal);
|
2013-08-11 21:02:36 +00:00
|
|
|
|
|
2014-06-14 20:17:07 +00:00
|
|
|
|
if (stateVersionTag)
|
|
|
|
|
{
|
|
|
|
|
PutLump(BinaryStateLump.Versiontag, WriteVersion);
|
|
|
|
|
}
|
2013-08-11 21:02:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-08 03:53:53 +00:00
|
|
|
|
public void PutLump(BinaryStateLump lump, Action<Stream> callback)
|
2013-08-11 21:02:36 +00:00
|
|
|
|
{
|
2014-08-19 00:59:02 +00:00
|
|
|
|
var name = BinaryStateFileNames.GetWriteName(lump);
|
2014-10-09 23:39:13 +00:00
|
|
|
|
_zip.WriteItem(name, callback);
|
2013-08-11 21:02:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-08 03:53:53 +00:00
|
|
|
|
public void PutLump(BinaryStateLump lump, Action<BinaryWriter> callback)
|
2013-12-17 21:26:15 +00:00
|
|
|
|
{
|
2014-01-08 03:53:53 +00:00
|
|
|
|
PutLump(lump, delegate(Stream s)
|
2013-12-17 21:26:15 +00:00
|
|
|
|
{
|
2013-12-30 01:58:44 +00:00
|
|
|
|
var bw = new BinaryWriter(s);
|
2013-12-17 21:26:15 +00:00
|
|
|
|
callback(bw);
|
|
|
|
|
bw.Flush();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-08 03:53:53 +00:00
|
|
|
|
public void PutLump(BinaryStateLump lump, Action<TextWriter> callback)
|
2013-12-17 21:26:15 +00:00
|
|
|
|
{
|
2014-01-08 03:53:53 +00:00
|
|
|
|
PutLump(lump, delegate(Stream s)
|
2013-12-17 21:26:15 +00:00
|
|
|
|
{
|
|
|
|
|
TextWriter tw = new StreamWriter(s);
|
|
|
|
|
callback(tw);
|
|
|
|
|
tw.Flush();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-11 21:02:36 +00:00
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
2013-10-27 17:07:37 +00:00
|
|
|
|
Dispose(true);
|
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
|
|
|
{
|
2013-12-30 01:58:44 +00:00
|
|
|
|
if (!_isDisposed)
|
2013-08-11 21:02:36 +00:00
|
|
|
|
{
|
2013-12-30 01:58:44 +00:00
|
|
|
|
_isDisposed = true;
|
2013-10-27 17:07:37 +00:00
|
|
|
|
|
|
|
|
|
if (disposing)
|
|
|
|
|
{
|
2014-10-09 23:39:13 +00:00
|
|
|
|
_zip.Dispose();
|
2013-10-27 17:07:37 +00:00
|
|
|
|
}
|
2013-08-11 21:02:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|