some minor code cleanups in BizHawk.Common
This commit is contained in:
parent
8439d13236
commit
e71d729626
|
@ -52,8 +52,8 @@ namespace BizHawk.Client.Common
|
||||||
|
|
||||||
var ai = new HawkFileArchiveItem
|
var ai = new HawkFileArchiveItem
|
||||||
{
|
{
|
||||||
name = HawkFile.Util_FixArchiveFilename(afd.FileName),
|
Name = HawkFile.Util_FixArchiveFilename(afd.FileName),
|
||||||
size = (long)afd.Size, archiveIndex = i, index = ret.Count
|
Size = (long)afd.Size, ArchiveIndex = i, Index = ret.Count
|
||||||
};
|
};
|
||||||
|
|
||||||
ret.Add(ai);
|
ret.Add(ai);
|
||||||
|
|
|
@ -993,9 +993,9 @@ namespace BizHawk.Client.Common
|
||||||
string platform = "SNES";
|
string platform = "SNES";
|
||||||
foreach (var item in hf.ArchiveItems)
|
foreach (var item in hf.ArchiveItems)
|
||||||
{
|
{
|
||||||
if (item.name == "authors")
|
if (item.Name == "authors")
|
||||||
{
|
{
|
||||||
hf.BindArchiveMember(item.index);
|
hf.BindArchiveMember(item.Index);
|
||||||
var stream = hf.GetStream();
|
var stream = hf.GetStream();
|
||||||
string authors = Encoding.UTF8.GetString(Util.ReadAllBytes(stream));
|
string authors = Encoding.UTF8.GetString(Util.ReadAllBytes(stream));
|
||||||
string author_list = "";
|
string author_list = "";
|
||||||
|
@ -1028,25 +1028,25 @@ namespace BizHawk.Client.Common
|
||||||
m.Header[HeaderKeys.AUTHOR] = author_list;
|
m.Header[HeaderKeys.AUTHOR] = author_list;
|
||||||
hf.Unbind();
|
hf.Unbind();
|
||||||
}
|
}
|
||||||
else if (item.name == "coreversion")
|
else if (item.Name == "coreversion")
|
||||||
{
|
{
|
||||||
hf.BindArchiveMember(item.index);
|
hf.BindArchiveMember(item.Index);
|
||||||
var stream = hf.GetStream();
|
var stream = hf.GetStream();
|
||||||
string coreversion = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
|
string coreversion = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
|
||||||
m.Header.Comments.Add(COREORIGIN + " " + coreversion);
|
m.Header.Comments.Add(COREORIGIN + " " + coreversion);
|
||||||
hf.Unbind();
|
hf.Unbind();
|
||||||
}
|
}
|
||||||
else if (item.name == "gamename")
|
else if (item.Name == "gamename")
|
||||||
{
|
{
|
||||||
hf.BindArchiveMember(item.index);
|
hf.BindArchiveMember(item.Index);
|
||||||
var stream = hf.GetStream();
|
var stream = hf.GetStream();
|
||||||
string gamename = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
|
string gamename = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
|
||||||
m.Header[HeaderKeys.GAMENAME] = gamename;
|
m.Header[HeaderKeys.GAMENAME] = gamename;
|
||||||
hf.Unbind();
|
hf.Unbind();
|
||||||
}
|
}
|
||||||
else if (item.name == "gametype")
|
else if (item.Name == "gametype")
|
||||||
{
|
{
|
||||||
hf.BindArchiveMember(item.index);
|
hf.BindArchiveMember(item.Index);
|
||||||
var stream = hf.GetStream();
|
var stream = hf.GetStream();
|
||||||
string gametype = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
|
string gametype = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
|
||||||
// TODO: Handle the other types.
|
// TODO: Handle the other types.
|
||||||
|
@ -1069,9 +1069,9 @@ namespace BizHawk.Client.Common
|
||||||
m.Header[HeaderKeys.PAL] = pal.ToString();
|
m.Header[HeaderKeys.PAL] = pal.ToString();
|
||||||
hf.Unbind();
|
hf.Unbind();
|
||||||
}
|
}
|
||||||
else if (item.name == "input")
|
else if (item.Name == "input")
|
||||||
{
|
{
|
||||||
hf.BindArchiveMember(item.index);
|
hf.BindArchiveMember(item.Index);
|
||||||
var stream = hf.GetStream();
|
var stream = hf.GetStream();
|
||||||
string input = Encoding.UTF8.GetString(Util.ReadAllBytes(stream));
|
string input = Encoding.UTF8.GetString(Util.ReadAllBytes(stream));
|
||||||
int lineNum = 0;
|
int lineNum = 0;
|
||||||
|
@ -1095,9 +1095,9 @@ namespace BizHawk.Client.Common
|
||||||
}
|
}
|
||||||
hf.Unbind();
|
hf.Unbind();
|
||||||
}
|
}
|
||||||
else if (item.name.StartsWith("moviesram."))
|
else if (item.Name.StartsWith("moviesram."))
|
||||||
{
|
{
|
||||||
hf.BindArchiveMember(item.index);
|
hf.BindArchiveMember(item.Index);
|
||||||
var stream = hf.GetStream();
|
var stream = hf.GetStream();
|
||||||
byte[] moviesram = Util.ReadAllBytes(stream);
|
byte[] moviesram = Util.ReadAllBytes(stream);
|
||||||
if (moviesram.Length != 0)
|
if (moviesram.Length != 0)
|
||||||
|
@ -1108,33 +1108,33 @@ namespace BizHawk.Client.Common
|
||||||
}
|
}
|
||||||
hf.Unbind();
|
hf.Unbind();
|
||||||
}
|
}
|
||||||
else if (item.name == "port1")
|
else if (item.Name == "port1")
|
||||||
{
|
{
|
||||||
hf.BindArchiveMember(item.index);
|
hf.BindArchiveMember(item.Index);
|
||||||
var stream = hf.GetStream();
|
var stream = hf.GetStream();
|
||||||
string port1 = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
|
string port1 = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
|
||||||
m.Header[PORT1] = port1;
|
m.Header[PORT1] = port1;
|
||||||
hf.Unbind();
|
hf.Unbind();
|
||||||
}
|
}
|
||||||
else if (item.name == "port2")
|
else if (item.Name == "port2")
|
||||||
{
|
{
|
||||||
hf.BindArchiveMember(item.index);
|
hf.BindArchiveMember(item.Index);
|
||||||
var stream = hf.GetStream();
|
var stream = hf.GetStream();
|
||||||
string port2 = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
|
string port2 = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
|
||||||
m.Header[PORT2] = port2;
|
m.Header[PORT2] = port2;
|
||||||
hf.Unbind();
|
hf.Unbind();
|
||||||
}
|
}
|
||||||
else if (item.name == "projectid")
|
else if (item.Name == "projectid")
|
||||||
{
|
{
|
||||||
hf.BindArchiveMember(item.index);
|
hf.BindArchiveMember(item.Index);
|
||||||
var stream = hf.GetStream();
|
var stream = hf.GetStream();
|
||||||
string projectid = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
|
string projectid = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
|
||||||
m.Header[PROJECTID] = projectid;
|
m.Header[PROJECTID] = projectid;
|
||||||
hf.Unbind();
|
hf.Unbind();
|
||||||
}
|
}
|
||||||
else if (item.name == "rerecords")
|
else if (item.Name == "rerecords")
|
||||||
{
|
{
|
||||||
hf.BindArchiveMember(item.index);
|
hf.BindArchiveMember(item.Index);
|
||||||
var stream = hf.GetStream();
|
var stream = hf.GetStream();
|
||||||
string rerecords = Encoding.UTF8.GetString(Util.ReadAllBytes(stream));
|
string rerecords = Encoding.UTF8.GetString(Util.ReadAllBytes(stream));
|
||||||
int rerecordCount;
|
int rerecordCount;
|
||||||
|
@ -1150,24 +1150,24 @@ namespace BizHawk.Client.Common
|
||||||
m.Header.Rerecords = (ulong)rerecordCount;
|
m.Header.Rerecords = (ulong)rerecordCount;
|
||||||
hf.Unbind();
|
hf.Unbind();
|
||||||
}
|
}
|
||||||
else if (item.name.EndsWith(".sha256"))
|
else if (item.Name.EndsWith(".sha256"))
|
||||||
{
|
{
|
||||||
hf.BindArchiveMember(item.index);
|
hf.BindArchiveMember(item.Index);
|
||||||
var stream = hf.GetStream();
|
var stream = hf.GetStream();
|
||||||
string rom = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
|
string rom = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
|
||||||
int pos = item.name.LastIndexOf(".sha256");
|
int pos = item.Name.LastIndexOf(".sha256");
|
||||||
string name = item.name.Substring(0, pos);
|
string name = item.Name.Substring(0, pos);
|
||||||
m.Header[SHA256 + "_" + name] = rom;
|
m.Header[SHA256 + "_" + name] = rom;
|
||||||
hf.Unbind();
|
hf.Unbind();
|
||||||
}
|
}
|
||||||
else if (item.name == "savestate")
|
else if (item.Name == "savestate")
|
||||||
{
|
{
|
||||||
errorMsg = "Movies that begin with a savestate are not supported.";
|
errorMsg = "Movies that begin with a savestate are not supported.";
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
else if (item.name == "subtitles")
|
else if (item.Name == "subtitles")
|
||||||
{
|
{
|
||||||
hf.BindArchiveMember(item.index);
|
hf.BindArchiveMember(item.Index);
|
||||||
var stream = hf.GetStream();
|
var stream = hf.GetStream();
|
||||||
string subtitles = Encoding.UTF8.GetString(Util.ReadAllBytes(stream));
|
string subtitles = Encoding.UTF8.GetString(Util.ReadAllBytes(stream));
|
||||||
using (StringReader reader = new StringReader(subtitles))
|
using (StringReader reader = new StringReader(subtitles))
|
||||||
|
@ -1178,25 +1178,25 @@ namespace BizHawk.Client.Common
|
||||||
}
|
}
|
||||||
hf.Unbind();
|
hf.Unbind();
|
||||||
}
|
}
|
||||||
else if (item.name == "starttime.second")
|
else if (item.Name == "starttime.second")
|
||||||
{
|
{
|
||||||
hf.BindArchiveMember(item.index);
|
hf.BindArchiveMember(item.Index);
|
||||||
var stream = hf.GetStream();
|
var stream = hf.GetStream();
|
||||||
string startSecond = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
|
string startSecond = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
|
||||||
m.Header[STARTSECOND] = startSecond;
|
m.Header[STARTSECOND] = startSecond;
|
||||||
hf.Unbind();
|
hf.Unbind();
|
||||||
}
|
}
|
||||||
else if (item.name == "starttime.subsecond")
|
else if (item.Name == "starttime.subsecond")
|
||||||
{
|
{
|
||||||
hf.BindArchiveMember(item.index);
|
hf.BindArchiveMember(item.Index);
|
||||||
var stream = hf.GetStream();
|
var stream = hf.GetStream();
|
||||||
string startSubSecond = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
|
string startSubSecond = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
|
||||||
m.Header[STARTSUBSECOND] = startSubSecond;
|
m.Header[STARTSUBSECOND] = startSubSecond;
|
||||||
hf.Unbind();
|
hf.Unbind();
|
||||||
}
|
}
|
||||||
else if (item.name == "systemid")
|
else if (item.Name == "systemid")
|
||||||
{
|
{
|
||||||
hf.BindArchiveMember(item.index);
|
hf.BindArchiveMember(item.Index);
|
||||||
var stream = hf.GetStream();
|
var stream = hf.GetStream();
|
||||||
string systemid = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
|
string systemid = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
|
||||||
m.Header.Comments.Add(EMULATIONORIGIN + " " + systemid);
|
m.Header.Comments.Add(EMULATIONORIGIN + " " + systemid);
|
||||||
|
|
|
@ -36,9 +36,9 @@ namespace BizHawk.Client.EmuHawk
|
||||||
var item = items[i];
|
var item = items[i];
|
||||||
var lvi = new ListViewItem { Tag = i };
|
var lvi = new ListViewItem { Tag = i };
|
||||||
lvi.SubItems.Add(new ListViewItem.ListViewSubItem());
|
lvi.SubItems.Add(new ListViewItem.ListViewSubItem());
|
||||||
lvi.Text = item.name;
|
lvi.Text = item.Name;
|
||||||
long size = item.size;
|
long size = item.Size;
|
||||||
var extension = Path.GetExtension(item.name);
|
var extension = Path.GetExtension(item.Name);
|
||||||
if (extension != null && (size % 1024 == 16 && extension.ToUpper() == ".NES"))
|
if (extension != null && (size % 1024 == 16 && extension.ToUpper() == ".NES"))
|
||||||
size -= 16;
|
size -= 16;
|
||||||
lvi.SubItems[1].Text = Util.FormatFileSize(size);
|
lvi.SubItems[1].Text = Util.FormatFileSize(size);
|
||||||
|
|
|
@ -3,15 +3,29 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
//the HawkFile class is excessively engineered with the IHawkFileArchiveHandler to decouple the archive handling from the basic file handling.
|
// the HawkFile class is excessively engineered with the IHawkFileArchiveHandler to decouple the archive handling from the basic file handling.
|
||||||
//This is so we could drop in an unamanged dearchiver library optionally later as a performance optimization without ruining the portability of the code.
|
// This is so we could drop in an unamanged dearchiver library optionally later as a performance optimization without ruining the portability of the code.
|
||||||
//Also, we want to be able to use HawkFiles in BizHawk.Common withuot bringing in a large 7-zip dependency
|
// Also, we want to be able to use HawkFiles in BizHawk.Common withuot bringing in a large 7-zip dependency
|
||||||
|
|
||||||
namespace BizHawk.Common
|
namespace BizHawk.Common
|
||||||
{
|
{
|
||||||
//todo:
|
// TODO:
|
||||||
//split into "bind" and "open (the bound thing)"
|
// split into "bind" and "open (the bound thing)"
|
||||||
//scan archive to flatten interior directories down to a path (maintain our own archive item list)
|
// scan archive to flatten interior directories down to a path (maintain our own archive item list)
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Bridge between HawkFile and the frontend's implementation of archive management
|
||||||
|
/// </summary>
|
||||||
|
public interface IHawkFileArchiveHandler : IDisposable
|
||||||
|
{
|
||||||
|
// TODO - could this receive a hawkfile itself? possibly handy, in very clever scenarios of mounting fake files
|
||||||
|
bool CheckSignature(string fileName, out int offset, out bool isExecutable);
|
||||||
|
|
||||||
|
List<HawkFileArchiveItem> Scan();
|
||||||
|
|
||||||
|
IHawkFileArchiveHandler Construct(string path);
|
||||||
|
|
||||||
|
void ExtractFile(int index, Stream stream);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// HawkFile allows a variety of objects (actual files, archive members) to be treated as normal filesystem objects to be opened, closed, and read.
|
/// HawkFile allows a variety of objects (actual files, archive members) to be treated as normal filesystem objects to be opened, closed, and read.
|
||||||
|
@ -21,10 +35,92 @@ namespace BizHawk.Common
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class HawkFile : IDisposable
|
public sealed class HawkFile : IDisposable
|
||||||
{
|
{
|
||||||
|
private bool _exists;
|
||||||
|
private bool _rootExists;
|
||||||
|
private string _rootPath;
|
||||||
|
private string _memberPath;
|
||||||
|
private Stream _rootStream, _boundStream;
|
||||||
|
private IHawkFileArchiveHandler _extractor;
|
||||||
|
private List<HawkFileArchiveItem> _archiveItems;
|
||||||
|
private int? _boundIndex;
|
||||||
|
|
||||||
|
public HawkFile() { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this with an instance which can construct archive handlers as necessary for archive handling.
|
/// Set this with an instance which can construct archive handlers as necessary for archive handling.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IHawkFileArchiveHandler ArchiveHandlerFactory;
|
public static IHawkFileArchiveHandler ArchiveHandlerFactory { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether a bound file exists. if there is no bound file, it can't exist
|
||||||
|
/// </summary>
|
||||||
|
public bool Exists { get { return _exists; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the directory containing the root
|
||||||
|
/// </summary>
|
||||||
|
public string Directory { get { return Path.GetDirectoryName(_rootPath); } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this instance is bound
|
||||||
|
/// </summary>
|
||||||
|
public bool IsBound { get { return _boundStream != null; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// returns the complete canonical full path ("c:\path\to\archive|member") of the bound file
|
||||||
|
/// </summary>
|
||||||
|
public string CanonicalFullPath { get { return MakeCanonicalName(_rootPath, _memberPath); } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// returns the complete canonical name ("archive|member") of the bound file
|
||||||
|
/// </summary>
|
||||||
|
public string CanonicalName { get { return MakeCanonicalName(Path.GetFileName(_rootPath), _memberPath); } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// returns the virtual name of the bound file (disregarding the archive)
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get { return GetBoundNameFromCanonical(MakeCanonicalName(_rootPath, _memberPath)); } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// returns the extension of Name
|
||||||
|
/// </summary>
|
||||||
|
public string Extension { get { return Path.GetExtension(Name).ToUpper(); } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates whether this file is an archive
|
||||||
|
/// </summary>
|
||||||
|
public bool IsArchive { get { return _extractor != null; } }
|
||||||
|
|
||||||
|
public IList<HawkFileArchiveItem> ArchiveItems
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!IsArchive)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Cant get archive items from non-archive");
|
||||||
|
}
|
||||||
|
|
||||||
|
return _archiveItems;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// returns a stream for the currently bound file
|
||||||
|
/// </summary>
|
||||||
|
public Stream GetStream()
|
||||||
|
{
|
||||||
|
if (_boundStream == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("HawkFile: Can't call GetStream() before youve successfully bound something!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return _boundStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int? GetBoundIndex()
|
||||||
|
{
|
||||||
|
return _boundIndex;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Utility: Uses full HawkFile processing to determine whether a file exists at the provided path
|
/// Utility: Uses full HawkFile processing to determine whether a file exists at the provided path
|
||||||
|
@ -44,154 +140,77 @@ namespace BizHawk.Common
|
||||||
{
|
{
|
||||||
using (var file = new HawkFile(path))
|
using (var file = new HawkFile(path))
|
||||||
{
|
{
|
||||||
if (!file.Exists) throw new FileNotFoundException(path);
|
if (!file.Exists)
|
||||||
|
{
|
||||||
|
throw new FileNotFoundException(path);
|
||||||
|
}
|
||||||
|
|
||||||
using (Stream stream = file.GetStream())
|
using (Stream stream = file.GetStream())
|
||||||
{
|
{
|
||||||
MemoryStream ms = new MemoryStream((int)stream.Length);
|
var ms = new MemoryStream((int)stream.Length);
|
||||||
stream.CopyTo(ms);
|
stream.CopyTo(ms);
|
||||||
return ms.GetBuffer();
|
return ms.GetBuffer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// returns whether a bound file exists. if there is no bound file, it can't exist
|
|
||||||
/// </summary>
|
|
||||||
public bool Exists { get { return exists; } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// gets the directory containing the root
|
|
||||||
/// </summary>
|
|
||||||
public string Directory { get { return Path.GetDirectoryName(rootPath); } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// returns a stream for the currently bound file
|
|
||||||
/// </summary>
|
|
||||||
public Stream GetStream()
|
|
||||||
{
|
|
||||||
if (boundStream == null)
|
|
||||||
throw new InvalidOperationException("HawkFile: Can't call GetStream() before youve successfully bound something!");
|
|
||||||
return boundStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// indicates whether this instance is bound
|
|
||||||
/// </summary>
|
|
||||||
public bool IsBound { get { return boundStream != null; } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// returns the complete canonical full path ("c:\path\to\archive|member") of the bound file
|
|
||||||
/// </summary>
|
|
||||||
public string CanonicalFullPath { get { return MakeCanonicalName(rootPath, memberPath); } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// returns the complete canonical name ("archive|member") of the bound file
|
|
||||||
/// </summary>
|
|
||||||
public string CanonicalName { get { return MakeCanonicalName(Path.GetFileName(rootPath), memberPath); } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// returns the virtual name of the bound file (disregarding the archive)
|
|
||||||
/// </summary>
|
|
||||||
public string Name { get { return GetBoundNameFromCanonical(MakeCanonicalName(rootPath, memberPath)); } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// returns the extension of Name
|
|
||||||
/// </summary>
|
|
||||||
public string Extension { get { return Path.GetExtension(Name).ToUpper(); } }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates whether this file is an archive
|
|
||||||
/// </summary>
|
|
||||||
public bool IsArchive { get { return extractor != null; } }
|
|
||||||
|
|
||||||
int? BoundIndex;
|
|
||||||
|
|
||||||
public int? GetBoundIndex()
|
|
||||||
{
|
|
||||||
return BoundIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//public class ArchiveItem
|
|
||||||
//{
|
|
||||||
// public string name;
|
|
||||||
// public long size;
|
|
||||||
// public int index;
|
|
||||||
//}
|
|
||||||
|
|
||||||
public IList<HawkFileArchiveItem> ArchiveItems
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (!IsArchive) throw new InvalidOperationException("Cant get archive items from non-archive");
|
|
||||||
return archiveItems;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// these extensions won't even be tried as archives (removes spurious archive detects since some of the signatures are pretty damn weak)
|
/// these extensions won't even be tried as archives (removes spurious archive detects since some of the signatures are pretty damn weak)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string[] NonArchiveExtensions = new string[] { };
|
public string[] NonArchiveExtensions = new string[] { };
|
||||||
|
|
||||||
//---
|
|
||||||
bool exists;
|
|
||||||
bool rootExists;
|
|
||||||
string rootPath;
|
|
||||||
string memberPath;
|
|
||||||
Stream rootStream, boundStream;
|
|
||||||
IHawkFileArchiveHandler extractor;
|
|
||||||
List<HawkFileArchiveItem> archiveItems;
|
|
||||||
|
|
||||||
public HawkFile()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Open(string path)
|
public void Open(string path)
|
||||||
{
|
{
|
||||||
if (rootPath != null) throw new InvalidOperationException("Don't reopen a HawkFile.");
|
if (_rootPath != null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Don't reopen a HawkFile.");
|
||||||
|
}
|
||||||
|
|
||||||
string autobind = null;
|
string autobind = null;
|
||||||
bool isArchivePath = IsCanonicalArchivePath(path);
|
bool isArchivePath = IsCanonicalArchivePath(path);
|
||||||
if (isArchivePath)
|
if (isArchivePath)
|
||||||
{
|
{
|
||||||
string[] parts = path.Split('|');
|
var parts = path.Split('|');
|
||||||
path = parts[0];
|
path = parts[0];
|
||||||
autobind = parts[1];
|
autobind = parts[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
var fi = new FileInfo(path);
|
var fi = new FileInfo(path);
|
||||||
|
|
||||||
rootExists = fi.Exists;
|
_rootExists = fi.Exists;
|
||||||
if (fi.Exists == false)
|
if (fi.Exists == false)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
rootPath = path;
|
_rootPath = path;
|
||||||
exists = true;
|
_exists = true;
|
||||||
|
|
||||||
AnalyzeArchive(path);
|
AnalyzeArchive(path);
|
||||||
if (extractor == null)
|
if (_extractor == null)
|
||||||
{
|
{
|
||||||
rootStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
|
_rootStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||||
//we could autobind here, but i dont want to
|
// we could autobind here, but i dont want to
|
||||||
//bind it later with the desired extensions.
|
// bind it later with the desired extensions.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (autobind == null)
|
if (autobind == null)
|
||||||
{
|
{
|
||||||
//non-archive files can be automatically bound this way
|
// non-archive files can be automatically bound this way
|
||||||
if (!isArchivePath)
|
if (!isArchivePath)
|
||||||
|
{
|
||||||
BindRoot();
|
BindRoot();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
autobind = autobind.ToUpperInvariant();
|
autobind = autobind.ToUpperInvariant();
|
||||||
if (extractor != null)
|
if (_extractor != null)
|
||||||
{
|
{
|
||||||
var scanResults = extractor.Scan();
|
var scanResults = _extractor.Scan();
|
||||||
for (int i = 0; i < scanResults.Count; i++)
|
for (int i = 0; i < scanResults.Count; i++)
|
||||||
{
|
{
|
||||||
if (scanResults[i].name.ToUpperInvariant() == autobind)
|
if (scanResults[i].Name.ToUpperInvariant() == autobind)
|
||||||
{
|
{
|
||||||
BindArchiveMember(i);
|
BindArchiveMember(i);
|
||||||
return;
|
return;
|
||||||
|
@ -199,7 +218,7 @@ namespace BizHawk.Common
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exists = false;
|
_exists = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,13 +230,12 @@ namespace BizHawk.Common
|
||||||
Open(path);
|
Open(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// binds the specified ArchiveItem which you should have gotten by interrogating an archive hawkfile
|
/// binds the specified ArchiveItem which you should have gotten by interrogating an archive hawkfile
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public HawkFile BindArchiveMember(HawkFileArchiveItem item)
|
public HawkFile BindArchiveMember(HawkFileArchiveItem item)
|
||||||
{
|
{
|
||||||
return BindArchiveMember(item.archiveIndex);
|
return BindArchiveMember(item.ArchiveIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -225,7 +243,7 @@ namespace BizHawk.Common
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public HawkFileArchiveItem FindArchiveMember(string name)
|
public HawkFileArchiveItem FindArchiveMember(string name)
|
||||||
{
|
{
|
||||||
return ArchiveItems.FirstOrDefault(ai => ai.name == name);
|
return ArchiveItems.FirstOrDefault(ai => ai.Name == name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -234,8 +252,12 @@ namespace BizHawk.Common
|
||||||
public HawkFile BindArchiveMember(string name)
|
public HawkFile BindArchiveMember(string name)
|
||||||
{
|
{
|
||||||
var ai = FindArchiveMember(name);
|
var ai = FindArchiveMember(name);
|
||||||
if (ai == null) return null;
|
if (ai == null)
|
||||||
else return BindArchiveMember(ai);
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BindArchiveMember(ai);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -243,16 +265,23 @@ namespace BizHawk.Common
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public HawkFile BindArchiveMember(int index)
|
public HawkFile BindArchiveMember(int index)
|
||||||
{
|
{
|
||||||
if (!rootExists) return this;
|
if (!_rootExists)
|
||||||
if (boundStream != null) throw new InvalidOperationException("stream already bound!");
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
boundStream = new MemoryStream();
|
if (_boundStream != null)
|
||||||
int archiveIndex = archiveItems[index].archiveIndex;
|
{
|
||||||
extractor.ExtractFile(archiveIndex, boundStream);
|
throw new InvalidOperationException("stream already bound!");
|
||||||
boundStream.Position = 0;
|
}
|
||||||
memberPath = archiveItems[index].name; //TODO - maybe go through our own list of names? maybe not, its indexes dont match..
|
|
||||||
|
_boundStream = new MemoryStream();
|
||||||
|
int archiveIndex = _archiveItems[index].ArchiveIndex;
|
||||||
|
_extractor.ExtractFile(archiveIndex, _boundStream);
|
||||||
|
_boundStream.Position = 0;
|
||||||
|
_memberPath = _archiveItems[index].Name; // TODO - maybe go through our own list of names? maybe not, its indexes dont match..
|
||||||
Console.WriteLine("HawkFile bound " + CanonicalFullPath);
|
Console.WriteLine("HawkFile bound " + CanonicalFullPath);
|
||||||
BoundIndex = archiveIndex;
|
_boundIndex = archiveIndex;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,18 +290,22 @@ namespace BizHawk.Common
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Unbind()
|
public void Unbind()
|
||||||
{
|
{
|
||||||
if (boundStream != null && boundStream != rootStream) boundStream.Close();
|
if (_boundStream != null && _boundStream != _rootStream)
|
||||||
boundStream = null;
|
{
|
||||||
memberPath = null;
|
_boundStream.Close();
|
||||||
BoundIndex = null;
|
}
|
||||||
|
|
||||||
|
_boundStream = null;
|
||||||
|
_memberPath = null;
|
||||||
|
_boundIndex = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// causes the root to be bound (in the case of non-archive files)
|
/// causes the root to be bound (in the case of non-archive files)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void BindRoot()
|
private void BindRoot()
|
||||||
{
|
{
|
||||||
boundStream = rootStream;
|
_boundStream = _rootStream;
|
||||||
Console.WriteLine("HawkFile bound " + CanonicalFullPath);
|
Console.WriteLine("HawkFile bound " + CanonicalFullPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,34 +328,42 @@ namespace BizHawk.Common
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Binds the first item in the archive (or the file itself) if the extension matches one of the supplied templates.
|
/// Binds the first item in the archive (or the file itself) if the extension matches one of the supplied templates.
|
||||||
/// You probably should not use this. use BindSoleItemOf or the archive chooser instead
|
/// You probably should not use use BindSoleItemOf or the archive chooser instead
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public HawkFile BindFirstOf(params string[] extensions)
|
public HawkFile BindFirstOf(params string[] extensions)
|
||||||
{
|
{
|
||||||
return BindByExtensionCore(true, extensions);
|
return BindByExtensionCore(true, extensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
HawkFile BindByExtensionCore(bool first, params string[] extensions)
|
private HawkFile BindByExtensionCore(bool first, params string[] extensions)
|
||||||
{
|
{
|
||||||
if (!rootExists) return this;
|
if (!_rootExists)
|
||||||
if (boundStream != null) throw new InvalidOperationException("stream already bound!");
|
|
||||||
|
|
||||||
if (extractor == null)
|
|
||||||
{
|
{
|
||||||
//open uncompressed file
|
return this;
|
||||||
string extension = Path.GetExtension(rootPath).Substring(1).ToUpperInvariant();
|
}
|
||||||
|
|
||||||
|
if (_boundStream != null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("stream already bound!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_extractor == null)
|
||||||
|
{
|
||||||
|
// open uncompressed file
|
||||||
|
var extension = Path.GetExtension(_rootPath).Substring(1).ToUpperInvariant();
|
||||||
if (extensions.Length == 0 || extension.In(extensions))
|
if (extensions.Length == 0 || extension.In(extensions))
|
||||||
{
|
{
|
||||||
BindRoot();
|
BindRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
var candidates = new List<int>();
|
var candidates = new List<int>();
|
||||||
for (int i = 0; i < archiveItems.Count; i++)
|
for (int i = 0; i < _archiveItems.Count; i++)
|
||||||
{
|
{
|
||||||
var e = archiveItems[i];
|
var e = _archiveItems[i];
|
||||||
var extension = Path.GetExtension(e.name).ToUpperInvariant();
|
var extension = Path.GetExtension(e.Name).ToUpperInvariant();
|
||||||
extension = extension.TrimStart('.');
|
extension = extension.TrimStart('.');
|
||||||
if (extensions.Length == 0 || extension.In(extensions))
|
if (extensions.Length == 0 || extension.In(extensions))
|
||||||
{
|
{
|
||||||
|
@ -331,24 +372,31 @@ namespace BizHawk.Common
|
||||||
BindArchiveMember(i);
|
BindArchiveMember(i);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
candidates.Add(i);
|
candidates.Add(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (candidates.Count == 1)
|
if (candidates.Count == 1)
|
||||||
|
{
|
||||||
BindArchiveMember(candidates[0]);
|
BindArchiveMember(candidates[0]);
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScanArchive()
|
private void ScanArchive()
|
||||||
{
|
{
|
||||||
archiveItems = extractor.Scan();
|
_archiveItems = _extractor.Scan();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AnalyzeArchive(string path)
|
private void AnalyzeArchive(string path)
|
||||||
{
|
{
|
||||||
//no archive handler == no analysis
|
// no archive handler == no analysis
|
||||||
if (ArchiveHandlerFactory == null)
|
if (ArchiveHandlerFactory == null)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int offset;
|
int offset;
|
||||||
bool isExecutable;
|
bool isExecutable;
|
||||||
|
@ -359,16 +407,16 @@ namespace BizHawk.Common
|
||||||
|
|
||||||
if (ArchiveHandlerFactory.CheckSignature(path, out offset, out isExecutable))
|
if (ArchiveHandlerFactory.CheckSignature(path, out offset, out isExecutable))
|
||||||
{
|
{
|
||||||
extractor = ArchiveHandlerFactory.Construct(path);
|
_extractor = ArchiveHandlerFactory.Construct(path);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ScanArchive();
|
ScanArchive();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
extractor.Dispose();
|
_extractor.Dispose();
|
||||||
extractor = null;
|
_extractor = null;
|
||||||
archiveItems = null;
|
_archiveItems = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -377,11 +425,18 @@ namespace BizHawk.Common
|
||||||
{
|
{
|
||||||
Unbind();
|
Unbind();
|
||||||
|
|
||||||
if (extractor != null) extractor.Dispose();
|
if (_extractor != null)
|
||||||
if (rootStream != null) rootStream.Dispose();
|
{
|
||||||
|
_extractor.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
extractor = null;
|
if (_rootStream != null)
|
||||||
rootStream = null;
|
{
|
||||||
|
_rootStream.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
_extractor = null;
|
||||||
|
_rootStream = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -389,7 +444,7 @@ namespace BizHawk.Common
|
||||||
/// </summary>
|
/// </summary>
|
||||||
static bool IsCanonicalArchivePath(string path)
|
static bool IsCanonicalArchivePath(string path)
|
||||||
{
|
{
|
||||||
return (path.IndexOf('|') != -1);
|
return path.IndexOf('|') != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -405,7 +460,7 @@ namespace BizHawk.Common
|
||||||
/// </summary>
|
/// </summary>
|
||||||
static string GetBoundNameFromCanonical(string canonical)
|
static string GetBoundNameFromCanonical(string canonical)
|
||||||
{
|
{
|
||||||
string[] parts = canonical.Split('|');
|
var parts = canonical.Split('|');
|
||||||
return parts[parts.Length - 1];
|
return parts[parts.Length - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,27 +469,14 @@ namespace BizHawk.Common
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string MakeCanonicalName(string root, string member)
|
string MakeCanonicalName(string root, string member)
|
||||||
{
|
{
|
||||||
if (member == null) return root;
|
if (member == null)
|
||||||
else return string.Format("{0}|{1}", root, member);
|
{
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Format("{0}|{1}", root, member);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} //class HawkFile
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Bridge between HawkFile and the frontend's implementation of archive management
|
|
||||||
/// </summary>
|
|
||||||
public interface IHawkFileArchiveHandler : IDisposable
|
|
||||||
{
|
|
||||||
//todo - could this receive a hawkfile itself? possibly handy, in very clever scenarios of mounting fake files
|
|
||||||
bool CheckSignature(string fileName, out int offset, out bool isExecutable);
|
|
||||||
|
|
||||||
List<HawkFileArchiveItem> Scan();
|
|
||||||
|
|
||||||
IHawkFileArchiveHandler Construct(string path);
|
|
||||||
|
|
||||||
void ExtractFile(int index, Stream stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Members returned by IHawkFileArchiveHandler
|
/// Members returned by IHawkFileArchiveHandler
|
||||||
|
@ -442,25 +484,24 @@ namespace BizHawk.Common
|
||||||
public class HawkFileArchiveItem
|
public class HawkFileArchiveItem
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// member name
|
/// Gets or sets the member name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string name;
|
public string Name { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// size of member file
|
/// Gets or sets the size of member file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public long size;
|
public long Size { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// the index of this archive item
|
/// Gets or sets the index of this archive item
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int index;
|
public int Index { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// the index WITHIN THE ARCHIVE (for internal tracking by a IHawkFileArchiveHandler) of the member
|
/// Gets or sets the index WITHIN THE ARCHIVE (for internal tracking by a IHawkFileArchiveHandler) of the member
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int archiveIndex;
|
public int ArchiveIndex { get; set; }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} //namespace BizHawk.Common
|
|
||||||
|
|
|
@ -2,52 +2,61 @@
|
||||||
{
|
{
|
||||||
public class MruStack<T>
|
public class MruStack<T>
|
||||||
{
|
{
|
||||||
private readonly T[] store;
|
private readonly T[] _store;
|
||||||
private int count;
|
private int _count;
|
||||||
private int head;
|
private int _head;
|
||||||
|
|
||||||
public int Count { get { return count; } }
|
|
||||||
|
|
||||||
public MruStack(int capacity)
|
public MruStack(int capacity)
|
||||||
{
|
{
|
||||||
store = new T[capacity];
|
_store = new T[capacity];
|
||||||
Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int Count { get { return _count; } }
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
head = 0;
|
_head = 0;
|
||||||
count = 0;
|
_count = 0;
|
||||||
for (int i = 0; i < store.Length; i++)
|
for (int i = 0; i < _store.Length; i++)
|
||||||
store[i] = default(T);
|
{
|
||||||
|
_store[i] = default(T);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Push(T value)
|
public void Push(T value)
|
||||||
{
|
{
|
||||||
store[head] = value;
|
_store[_head] = value;
|
||||||
head = (head + 1) % store.Length;
|
_head = (_head + 1) % _store.Length;
|
||||||
|
|
||||||
if (count < store.Length)
|
if (_count < _store.Length)
|
||||||
count++;
|
{
|
||||||
|
_count++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public T Pop()
|
public T Pop()
|
||||||
{
|
{
|
||||||
if (count == 0)
|
if (_count == 0)
|
||||||
|
{
|
||||||
return default(T);
|
return default(T);
|
||||||
|
}
|
||||||
|
|
||||||
head--;
|
_head--;
|
||||||
if (head < 0)
|
if (_head < 0)
|
||||||
head = store.Length - 1;
|
{
|
||||||
count--;
|
_head = _store.Length - 1;
|
||||||
T value = store[head];
|
}
|
||||||
store[head] = default(T);
|
|
||||||
|
_count--;
|
||||||
|
T value = _store[_head];
|
||||||
|
_store[_head] = default(T);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasElements()
|
public bool HasElements()
|
||||||
{
|
{
|
||||||
return count > 0;
|
return _count > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
using System;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace BizHawk.Common
|
namespace BizHawk.Common
|
||||||
|
@ -12,56 +11,60 @@ namespace BizHawk.Common
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SwitcherStream : Stream
|
public class SwitcherStream : Stream
|
||||||
{
|
{
|
||||||
//switchstream method? flush old stream?
|
// switchstream method? flush old stream?
|
||||||
Stream CurrStream = null;
|
private Stream _currStream;
|
||||||
|
|
||||||
public void SetCurrStream(Stream str) { CurrStream = str; }
|
|
||||||
|
|
||||||
public SwitcherStream()
|
public SwitcherStream()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool CanRead { get { return CurrStream.CanRead; } }
|
public override bool CanRead { get { return _currStream.CanRead; } }
|
||||||
public override bool CanSeek { get { return CurrStream.CanSeek; } }
|
public override bool CanSeek { get { return _currStream.CanSeek; } }
|
||||||
public override bool CanWrite { get { return CurrStream.CanWrite; } }
|
public override bool CanWrite { get { return _currStream.CanWrite; } }
|
||||||
public override void Flush()
|
|
||||||
{
|
|
||||||
CurrStream.Flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override long Length { get { return CurrStream.Length; } }
|
public override long Length { get { return _currStream.Length; } }
|
||||||
|
|
||||||
public override long Position
|
public override long Position
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return CurrStream.Position;
|
return _currStream.Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
CurrStream.Position = Position;
|
_currStream.Position = Position;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetCurrStream(Stream str)
|
||||||
|
{
|
||||||
|
_currStream = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Flush()
|
||||||
|
{
|
||||||
|
_currStream.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
public override int Read(byte[] buffer, int offset, int count)
|
public override int Read(byte[] buffer, int offset, int count)
|
||||||
{
|
{
|
||||||
return CurrStream.Read(buffer, offset, count);
|
return _currStream.Read(buffer, offset, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override long Seek(long offset, SeekOrigin origin)
|
public override long Seek(long offset, SeekOrigin origin)
|
||||||
{
|
{
|
||||||
return CurrStream.Seek(offset, origin);
|
return _currStream.Seek(offset, origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void SetLength(long value)
|
public override void SetLength(long value)
|
||||||
{
|
{
|
||||||
CurrStream.SetLength(value);
|
_currStream.SetLength(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Write(byte[] buffer, int offset, int count)
|
public override void Write(byte[] buffer, int offset, int count)
|
||||||
{
|
{
|
||||||
CurrStream.Write(buffer, offset, count);
|
_currStream.Write(buffer, offset, count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -6,9 +6,7 @@ namespace BizHawk.Common
|
||||||
public class UndoHistory<T>
|
public class UndoHistory<T>
|
||||||
{
|
{
|
||||||
private List<List<T>> _history = new List<List<T>>();
|
private List<List<T>> _history = new List<List<T>>();
|
||||||
private int curPos; //1-based
|
private int _curPos; // 1-based
|
||||||
|
|
||||||
public bool Enabled { get; private set; }
|
|
||||||
|
|
||||||
public UndoHistory(bool enabled)
|
public UndoHistory(bool enabled)
|
||||||
{
|
{
|
||||||
|
@ -21,20 +19,16 @@ namespace BizHawk.Common
|
||||||
Enabled = enabled;
|
Enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear()
|
public bool Enabled { get; private set; }
|
||||||
{
|
|
||||||
_history = new List<List<T>>();
|
|
||||||
curPos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanUndo
|
public bool CanUndo
|
||||||
{
|
{
|
||||||
get { return Enabled && curPos > 1; }
|
get { return Enabled && _curPos > 1; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanRedo
|
public bool CanRedo
|
||||||
{
|
{
|
||||||
get { return Enabled && curPos < _history.Count; }
|
get { return Enabled && _curPos < _history.Count; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasHistory
|
public bool HasHistory
|
||||||
|
@ -42,20 +36,26 @@ namespace BizHawk.Common
|
||||||
get { return Enabled && _history.Any(); }
|
get { return Enabled && _history.Any(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
_history = new List<List<T>>();
|
||||||
|
_curPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
public void AddState(IEnumerable<T> newState)
|
public void AddState(IEnumerable<T> newState)
|
||||||
{
|
{
|
||||||
if (Enabled)
|
if (Enabled)
|
||||||
{
|
{
|
||||||
if (curPos < _history.Count)
|
if (_curPos < _history.Count)
|
||||||
{
|
{
|
||||||
for (int i = curPos + 1; i <= _history.Count; i++)
|
for (var i = _curPos + 1; i <= _history.Count; i++)
|
||||||
{
|
{
|
||||||
_history.Remove(_history[i - 1]);
|
_history.Remove(_history[i - 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_history.Add(newState.ToList());
|
_history.Add(newState.ToList());
|
||||||
curPos = _history.Count;
|
_curPos = _history.Count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,26 +63,22 @@ namespace BizHawk.Common
|
||||||
{
|
{
|
||||||
if (CanUndo && Enabled)
|
if (CanUndo && Enabled)
|
||||||
{
|
{
|
||||||
curPos--;
|
_curPos--;
|
||||||
return _history[curPos - 1];
|
return _history[_curPos - 1];
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Enumerable.Empty<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<T> Redo()
|
public IEnumerable<T> Redo()
|
||||||
{
|
{
|
||||||
if (CanRedo && Enabled)
|
if (CanRedo && Enabled)
|
||||||
{
|
{
|
||||||
curPos++;
|
_curPos++;
|
||||||
return _history[curPos - 1];
|
return _history[_curPos - 1];
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Enumerable.Empty<T>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace BizHawk.Common
|
namespace BizHawk.Common
|
||||||
{
|
{
|
||||||
|
@ -10,14 +10,14 @@ namespace BizHawk.Common
|
||||||
private static readonly char[] HexConvArr = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
private static readonly char[] HexConvArr = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||||
private static System.Runtime.InteropServices.GCHandle HexConvHandle;
|
private static System.Runtime.InteropServices.GCHandle HexConvHandle;
|
||||||
|
|
||||||
public static char* HexConvPtr { get; set; }
|
|
||||||
|
|
||||||
static Util()
|
static Util()
|
||||||
{
|
{
|
||||||
HexConvHandle = System.Runtime.InteropServices.GCHandle.Alloc(HexConvArr, System.Runtime.InteropServices.GCHandleType.Pinned);
|
HexConvHandle = System.Runtime.InteropServices.GCHandle.Alloc(HexConvArr, System.Runtime.InteropServices.GCHandleType.Pinned);
|
||||||
HexConvPtr = (char*)HexConvHandle.AddrOfPinnedObject().ToPointer();
|
HexConvPtr = (char*)HexConvHandle.AddrOfPinnedObject().ToPointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static char* HexConvPtr { get; set; }
|
||||||
|
|
||||||
public static string Hash_MD5(byte[] data, int offset, int len)
|
public static string Hash_MD5(byte[] data, int offset, int len)
|
||||||
{
|
{
|
||||||
using (var md5 = System.Security.Cryptography.MD5.Create())
|
using (var md5 = System.Security.Cryptography.MD5.Create())
|
||||||
|
@ -58,11 +58,11 @@ namespace BizHawk.Common
|
||||||
|
|
||||||
public static int SaveRamBytesUsed(byte[] saveRam)
|
public static int SaveRamBytesUsed(byte[] saveRam)
|
||||||
{
|
{
|
||||||
for (int j = saveRam.Length - 1; j >= 0; j--)
|
for (var i = saveRam.Length - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
if (saveRam[j] != 0)
|
if (saveRam[i] != 0)
|
||||||
{
|
{
|
||||||
return j + 1;
|
return i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ namespace BizHawk.Common
|
||||||
public static string ReadStringFixedAscii(this BinaryReader r, int bytes)
|
public static string ReadStringFixedAscii(this BinaryReader r, int bytes)
|
||||||
{
|
{
|
||||||
var read = new byte[bytes];
|
var read = new byte[bytes];
|
||||||
for (int b = 0; b < bytes; b++)
|
for (var b = 0; b < bytes; b++)
|
||||||
{
|
{
|
||||||
read[b] = r.ReadByte();
|
read[b] = r.ReadByte();
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ namespace BizHawk.Common
|
||||||
public static string ReadStringAsciiZ(this BinaryReader r)
|
public static string ReadStringAsciiZ(this BinaryReader r)
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
for (; ; )
|
for (;;)
|
||||||
{
|
{
|
||||||
int b = r.ReadByte();
|
int b = r.ReadByte();
|
||||||
if (b <= 0)
|
if (b <= 0)
|
||||||
|
@ -128,7 +128,7 @@ namespace BizHawk.Common
|
||||||
int d = 0;
|
int d = 0;
|
||||||
for (int j = 0; j < 2; j++)
|
for (int j = 0; j < 2; j++)
|
||||||
{
|
{
|
||||||
var c = char.ToLower(str[i * 2 + j]);
|
var c = char.ToLower(str[(i * 2) + j]);
|
||||||
if (c >= '0' && c <= '9')
|
if (c >= '0' && c <= '9')
|
||||||
{
|
{
|
||||||
d += c - '0';
|
d += c - '0';
|
||||||
|
@ -146,11 +146,11 @@ namespace BizHawk.Common
|
||||||
{
|
{
|
||||||
d <<= 4;
|
d <<= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ms.WriteByte((byte)d);
|
ms.WriteByte((byte)d);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ms.ToArray();
|
return ms.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,11 +346,11 @@ namespace BizHawk.Common
|
||||||
|
|
||||||
public static string FormatFileSize(long filesize)
|
public static string FormatFileSize(long filesize)
|
||||||
{
|
{
|
||||||
Decimal size = filesize;
|
decimal size = filesize;
|
||||||
|
|
||||||
Decimal OneKiloByte = 1024M;
|
const decimal OneKiloByte = 1024M;
|
||||||
Decimal OneMegaByte = OneKiloByte * 1024M;
|
const decimal OneMegaByte = OneKiloByte * 1024M;
|
||||||
Decimal OneGigaByte = OneMegaByte * 1024M;
|
decimal OneGigaByte = OneMegaByte * 1024M;
|
||||||
|
|
||||||
string suffix;
|
string suffix;
|
||||||
if (size > 1024 * 1024 * 1024)
|
if (size > 1024 * 1024 * 1024)
|
||||||
|
@ -373,26 +373,45 @@ namespace BizHawk.Common
|
||||||
suffix = " B";
|
suffix = " B";
|
||||||
}
|
}
|
||||||
|
|
||||||
var precision = "2";
|
const string precision = "2";
|
||||||
return String.Format("{0:N" + precision + "}{1}", size, suffix);
|
return string.Format("{0:N" + precision + "}{1}", size, suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://stackoverflow.com/questions/3928822/comparing-2-dictionarystring-string-instances
|
// http://stackoverflow.com/questions/3928822/comparing-2-dictionarystring-string-instances
|
||||||
public static bool DictionaryEqual<TKey, TValue>(
|
public static bool DictionaryEqual<TKey, TValue>(
|
||||||
IDictionary<TKey, TValue> first, IDictionary<TKey, TValue> second)
|
IDictionary<TKey, TValue> first, IDictionary<TKey, TValue> second)
|
||||||
{
|
{
|
||||||
if (first == second) return true;
|
if (first == second)
|
||||||
if ((first == null) || (second == null)) return false;
|
{
|
||||||
if (first.Count != second.Count) return false;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((first == null) || (second == null))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first.Count != second.Count)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var comparer = EqualityComparer<TValue>.Default;
|
var comparer = EqualityComparer<TValue>.Default;
|
||||||
|
|
||||||
foreach (KeyValuePair<TKey, TValue> kvp in first)
|
foreach (var kvp in first)
|
||||||
{
|
{
|
||||||
TValue secondValue;
|
TValue secondValue;
|
||||||
if (!second.TryGetValue(kvp.Key, out secondValue)) return false;
|
if (!second.TryGetValue(kvp.Key, out secondValue))
|
||||||
if (!comparer.Equals(kvp.Value, secondValue)) return false;
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!comparer.Equals(kvp.Value, secondValue))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,9 +426,11 @@ namespace BizHawk.Common
|
||||||
{
|
{
|
||||||
TValue ret;
|
TValue ret;
|
||||||
if (!dict.TryGetValue(key, out ret))
|
if (!dict.TryGetValue(key, out ret))
|
||||||
|
{
|
||||||
return defaultvalue;
|
return defaultvalue;
|
||||||
else
|
}
|
||||||
return ret;
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,6 +441,14 @@ namespace BizHawk.Common
|
||||||
|
|
||||||
internal class SuperGloballyUniqueID
|
internal class SuperGloballyUniqueID
|
||||||
{
|
{
|
||||||
|
private static readonly string StaticPart;
|
||||||
|
private static int ctr;
|
||||||
|
|
||||||
|
static SuperGloballyUniqueID()
|
||||||
|
{
|
||||||
|
StaticPart = "bizhawk-" + System.Diagnostics.Process.GetCurrentProcess().Id + "-" + Guid.NewGuid();
|
||||||
|
}
|
||||||
|
|
||||||
public static string Next()
|
public static string Next()
|
||||||
{
|
{
|
||||||
int myctr;
|
int myctr;
|
||||||
|
@ -430,13 +459,5 @@ namespace BizHawk.Common
|
||||||
|
|
||||||
return StaticPart + "-" + myctr;
|
return StaticPart + "-" + myctr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SuperGloballyUniqueID()
|
|
||||||
{
|
|
||||||
StaticPart = "bizhawk-" + System.Diagnostics.Process.GetCurrentProcess().Id + "-" + Guid.NewGuid();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly string StaticPart;
|
|
||||||
private static int ctr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue