some minor code cleanups in BizHawk.Common

This commit is contained in:
adelikat 2014-02-04 21:15:33 +00:00
parent 8439d13236
commit e71d729626
8 changed files with 392 additions and 322 deletions

View File

@ -52,8 +52,8 @@ namespace BizHawk.Client.Common
var ai = new HawkFileArchiveItem
{
name = HawkFile.Util_FixArchiveFilename(afd.FileName),
size = (long)afd.Size, archiveIndex = i, index = ret.Count
Name = HawkFile.Util_FixArchiveFilename(afd.FileName),
Size = (long)afd.Size, ArchiveIndex = i, Index = ret.Count
};
ret.Add(ai);

View File

@ -993,9 +993,9 @@ namespace BizHawk.Client.Common
string platform = "SNES";
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();
string authors = Encoding.UTF8.GetString(Util.ReadAllBytes(stream));
string author_list = "";
@ -1028,25 +1028,25 @@ namespace BizHawk.Client.Common
m.Header[HeaderKeys.AUTHOR] = author_list;
hf.Unbind();
}
else if (item.name == "coreversion")
else if (item.Name == "coreversion")
{
hf.BindArchiveMember(item.index);
hf.BindArchiveMember(item.Index);
var stream = hf.GetStream();
string coreversion = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
m.Header.Comments.Add(COREORIGIN + " " + coreversion);
hf.Unbind();
}
else if (item.name == "gamename")
else if (item.Name == "gamename")
{
hf.BindArchiveMember(item.index);
hf.BindArchiveMember(item.Index);
var stream = hf.GetStream();
string gamename = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
m.Header[HeaderKeys.GAMENAME] = gamename;
hf.Unbind();
}
else if (item.name == "gametype")
else if (item.Name == "gametype")
{
hf.BindArchiveMember(item.index);
hf.BindArchiveMember(item.Index);
var stream = hf.GetStream();
string gametype = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
// TODO: Handle the other types.
@ -1069,9 +1069,9 @@ namespace BizHawk.Client.Common
m.Header[HeaderKeys.PAL] = pal.ToString();
hf.Unbind();
}
else if (item.name == "input")
else if (item.Name == "input")
{
hf.BindArchiveMember(item.index);
hf.BindArchiveMember(item.Index);
var stream = hf.GetStream();
string input = Encoding.UTF8.GetString(Util.ReadAllBytes(stream));
int lineNum = 0;
@ -1095,9 +1095,9 @@ namespace BizHawk.Client.Common
}
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();
byte[] moviesram = Util.ReadAllBytes(stream);
if (moviesram.Length != 0)
@ -1108,33 +1108,33 @@ namespace BizHawk.Client.Common
}
hf.Unbind();
}
else if (item.name == "port1")
else if (item.Name == "port1")
{
hf.BindArchiveMember(item.index);
hf.BindArchiveMember(item.Index);
var stream = hf.GetStream();
string port1 = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
m.Header[PORT1] = port1;
hf.Unbind();
}
else if (item.name == "port2")
else if (item.Name == "port2")
{
hf.BindArchiveMember(item.index);
hf.BindArchiveMember(item.Index);
var stream = hf.GetStream();
string port2 = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
m.Header[PORT2] = port2;
hf.Unbind();
}
else if (item.name == "projectid")
else if (item.Name == "projectid")
{
hf.BindArchiveMember(item.index);
hf.BindArchiveMember(item.Index);
var stream = hf.GetStream();
string projectid = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
m.Header[PROJECTID] = projectid;
hf.Unbind();
}
else if (item.name == "rerecords")
else if (item.Name == "rerecords")
{
hf.BindArchiveMember(item.index);
hf.BindArchiveMember(item.Index);
var stream = hf.GetStream();
string rerecords = Encoding.UTF8.GetString(Util.ReadAllBytes(stream));
int rerecordCount;
@ -1150,24 +1150,24 @@ namespace BizHawk.Client.Common
m.Header.Rerecords = (ulong)rerecordCount;
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();
string rom = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
int pos = item.name.LastIndexOf(".sha256");
string name = item.name.Substring(0, pos);
int pos = item.Name.LastIndexOf(".sha256");
string name = item.Name.Substring(0, pos);
m.Header[SHA256 + "_" + name] = rom;
hf.Unbind();
}
else if (item.name == "savestate")
else if (item.Name == "savestate")
{
errorMsg = "Movies that begin with a savestate are not supported.";
return null;
}
else if (item.name == "subtitles")
else if (item.Name == "subtitles")
{
hf.BindArchiveMember(item.index);
hf.BindArchiveMember(item.Index);
var stream = hf.GetStream();
string subtitles = Encoding.UTF8.GetString(Util.ReadAllBytes(stream));
using (StringReader reader = new StringReader(subtitles))
@ -1178,25 +1178,25 @@ namespace BizHawk.Client.Common
}
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();
string startSecond = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
m.Header[STARTSECOND] = startSecond;
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();
string startSubSecond = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
m.Header[STARTSUBSECOND] = startSubSecond;
hf.Unbind();
}
else if (item.name == "systemid")
else if (item.Name == "systemid")
{
hf.BindArchiveMember(item.index);
hf.BindArchiveMember(item.Index);
var stream = hf.GetStream();
string systemid = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
m.Header.Comments.Add(EMULATIONORIGIN + " " + systemid);

View File

@ -36,9 +36,9 @@ namespace BizHawk.Client.EmuHawk
var item = items[i];
var lvi = new ListViewItem { Tag = i };
lvi.SubItems.Add(new ListViewItem.ListViewSubItem());
lvi.Text = item.name;
long size = item.size;
var extension = Path.GetExtension(item.name);
lvi.Text = item.Name;
long size = item.Size;
var extension = Path.GetExtension(item.Name);
if (extension != null && (size % 1024 == 16 && extension.ToUpper() == ".NES"))
size -= 16;
lvi.SubItems[1].Text = Util.FormatFileSize(size);

View File

@ -3,15 +3,29 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
//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.
//Also, we want to be able to use HawkFiles in BizHawk.Common withuot bringing in a large 7-zip dependency
// 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.
// Also, we want to be able to use HawkFiles in BizHawk.Common withuot bringing in a large 7-zip dependency
namespace BizHawk.Common
{
//todo:
//split into "bind" and "open (the bound thing)"
//scan archive to flatten interior directories down to a path (maintain our own archive item list)
// TODO:
// split into "bind" and "open (the bound thing)"
// 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>
/// 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>
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>
/// Set this with an instance which can construct archive handlers as necessary for archive handling.
/// </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>
/// 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))
{
if (!file.Exists) throw new FileNotFoundException(path);
if (!file.Exists)
{
throw new FileNotFoundException(path);
}
using (Stream stream = file.GetStream())
{
MemoryStream ms = new MemoryStream((int)stream.Length);
var ms = new MemoryStream((int)stream.Length);
stream.CopyTo(ms);
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>
/// these extensions won't even be tried as archives (removes spurious archive detects since some of the signatures are pretty damn weak)
/// </summary>
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)
{
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;
bool isArchivePath = IsCanonicalArchivePath(path);
if (isArchivePath)
{
string[] parts = path.Split('|');
var parts = path.Split('|');
path = parts[0];
autobind = parts[1];
}
var fi = new FileInfo(path);
rootExists = fi.Exists;
_rootExists = fi.Exists;
if (fi.Exists == false)
{
return;
}
rootPath = path;
exists = true;
_rootPath = path;
_exists = true;
AnalyzeArchive(path);
if (extractor == null)
if (_extractor == null)
{
rootStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
//we could autobind here, but i dont want to
//bind it later with the desired extensions.
_rootStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
// we could autobind here, but i dont want to
// bind it later with the desired extensions.
}
if (autobind == null)
{
//non-archive files can be automatically bound this way
// non-archive files can be automatically bound this way
if (!isArchivePath)
{
BindRoot();
}
}
else
{
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++)
{
if (scanResults[i].name.ToUpperInvariant() == autobind)
if (scanResults[i].Name.ToUpperInvariant() == autobind)
{
BindArchiveMember(i);
return;
@ -199,7 +218,7 @@ namespace BizHawk.Common
}
}
exists = false;
_exists = false;
}
}
@ -211,13 +230,12 @@ namespace BizHawk.Common
Open(path);
}
/// <summary>
/// binds the specified ArchiveItem which you should have gotten by interrogating an archive hawkfile
/// </summary>
public HawkFile BindArchiveMember(HawkFileArchiveItem item)
{
return BindArchiveMember(item.archiveIndex);
return BindArchiveMember(item.ArchiveIndex);
}
/// <summary>
@ -225,7 +243,7 @@ namespace BizHawk.Common
/// </summary>
public HawkFileArchiveItem FindArchiveMember(string name)
{
return ArchiveItems.FirstOrDefault(ai => ai.name == name);
return ArchiveItems.FirstOrDefault(ai => ai.Name == name);
}
/// <summary>
@ -234,8 +252,12 @@ namespace BizHawk.Common
public HawkFile BindArchiveMember(string name)
{
var ai = FindArchiveMember(name);
if (ai == null) return null;
else return BindArchiveMember(ai);
if (ai == null)
{
return null;
}
return BindArchiveMember(ai);
}
/// <summary>
@ -243,16 +265,23 @@ namespace BizHawk.Common
/// </summary>
public HawkFile BindArchiveMember(int index)
{
if (!rootExists) return this;
if (boundStream != null) throw new InvalidOperationException("stream already bound!");
if (!_rootExists)
{
return this;
}
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..
if (_boundStream != null)
{
throw new InvalidOperationException("stream already bound!");
}
_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);
BoundIndex = archiveIndex;
_boundIndex = archiveIndex;
return this;
}
@ -261,18 +290,22 @@ namespace BizHawk.Common
/// </summary>
public void Unbind()
{
if (boundStream != null && boundStream != rootStream) boundStream.Close();
boundStream = null;
memberPath = null;
BoundIndex = null;
if (_boundStream != null && _boundStream != _rootStream)
{
_boundStream.Close();
}
_boundStream = null;
_memberPath = null;
_boundIndex = null;
}
/// <summary>
/// causes the root to be bound (in the case of non-archive files)
/// </summary>
void BindRoot()
private void BindRoot()
{
boundStream = rootStream;
_boundStream = _rootStream;
Console.WriteLine("HawkFile bound " + CanonicalFullPath);
}
@ -295,34 +328,42 @@ namespace BizHawk.Common
/// <summary>
/// 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>
public HawkFile BindFirstOf(params string[] 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 (boundStream != null) throw new InvalidOperationException("stream already bound!");
if (extractor == null)
if (!_rootExists)
{
//open uncompressed file
string extension = Path.GetExtension(rootPath).Substring(1).ToUpperInvariant();
return this;
}
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))
{
BindRoot();
}
return this;
}
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 extension = Path.GetExtension(e.name).ToUpperInvariant();
var e = _archiveItems[i];
var extension = Path.GetExtension(e.Name).ToUpperInvariant();
extension = extension.TrimStart('.');
if (extensions.Length == 0 || extension.In(extensions))
{
@ -331,24 +372,31 @@ namespace BizHawk.Common
BindArchiveMember(i);
return this;
}
candidates.Add(i);
}
}
if (candidates.Count == 1)
{
BindArchiveMember(candidates[0]);
}
return this;
}
void ScanArchive()
private void ScanArchive()
{
archiveItems = extractor.Scan();
_archiveItems = _extractor.Scan();
}
private void AnalyzeArchive(string path)
{
//no archive handler == no analysis
// no archive handler == no analysis
if (ArchiveHandlerFactory == null)
{
return;
}
int offset;
bool isExecutable;
@ -359,16 +407,16 @@ namespace BizHawk.Common
if (ArchiveHandlerFactory.CheckSignature(path, out offset, out isExecutable))
{
extractor = ArchiveHandlerFactory.Construct(path);
_extractor = ArchiveHandlerFactory.Construct(path);
try
{
ScanArchive();
}
catch
{
extractor.Dispose();
extractor = null;
archiveItems = null;
_extractor.Dispose();
_extractor = null;
_archiveItems = null;
}
}
}
@ -377,11 +425,18 @@ namespace BizHawk.Common
{
Unbind();
if (extractor != null) extractor.Dispose();
if (rootStream != null) rootStream.Dispose();
if (_extractor != null)
{
_extractor.Dispose();
}
extractor = null;
rootStream = null;
if (_rootStream != null)
{
_rootStream.Dispose();
}
_extractor = null;
_rootStream = null;
}
/// <summary>
@ -389,7 +444,7 @@ namespace BizHawk.Common
/// </summary>
static bool IsCanonicalArchivePath(string path)
{
return (path.IndexOf('|') != -1);
return path.IndexOf('|') != -1;
}
/// <summary>
@ -405,7 +460,7 @@ namespace BizHawk.Common
/// </summary>
static string GetBoundNameFromCanonical(string canonical)
{
string[] parts = canonical.Split('|');
var parts = canonical.Split('|');
return parts[parts.Length - 1];
}
@ -414,27 +469,14 @@ namespace BizHawk.Common
/// </summary>
string MakeCanonicalName(string root, string member)
{
if (member == null) return root;
else return string.Format("{0}|{1}", root, member);
if (member == null)
{
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>
/// Members returned by IHawkFileArchiveHandler
@ -442,25 +484,24 @@ namespace BizHawk.Common
public class HawkFileArchiveItem
{
/// <summary>
/// member name
/// Gets or sets the member name
/// </summary>
public string name;
public string Name { get; set; }
/// <summary>
/// size of member file
/// Gets or sets the size of member file
/// </summary>
public long size;
public long Size { get; set; }
/// <summary>
/// the index of this archive item
/// Gets or sets the index of this archive item
/// </summary>
public int index;
public int Index { get; set; }
/// <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>
public int archiveIndex;
public int ArchiveIndex { get; set; }
}
} //namespace BizHawk.Common
}

View File

@ -2,52 +2,61 @@
{
public class MruStack<T>
{
private readonly T[] store;
private int count;
private int head;
public int Count { get { return count; } }
private readonly T[] _store;
private int _count;
private int _head;
public MruStack(int capacity)
{
store = new T[capacity];
_store = new T[capacity];
Clear();
}
public int Count { get { return _count; } }
public void Clear()
{
head = 0;
count = 0;
for (int i = 0; i < store.Length; i++)
store[i] = default(T);
_head = 0;
_count = 0;
for (int i = 0; i < _store.Length; i++)
{
_store[i] = default(T);
}
}
public void Push(T value)
{
store[head] = value;
head = (head + 1) % store.Length;
_store[_head] = value;
_head = (_head + 1) % _store.Length;
if (count < store.Length)
count++;
if (_count < _store.Length)
{
_count++;
}
}
public T Pop()
{
if (count == 0)
if (_count == 0)
{
return default(T);
}
head--;
if (head < 0)
head = store.Length - 1;
count--;
T value = store[head];
store[head] = default(T);
_head--;
if (_head < 0)
{
_head = _store.Length - 1;
}
_count--;
T value = _store[_head];
_store[_head] = default(T);
return value;
}
public bool HasElements()
{
return count > 0;
return _count > 0;
}
}
}

View File

@ -1,4 +1,3 @@
using System;
using System.IO;
namespace BizHawk.Common
@ -12,56 +11,60 @@ namespace BizHawk.Common
/// </summary>
public class SwitcherStream : Stream
{
//switchstream method? flush old stream?
Stream CurrStream = null;
public void SetCurrStream(Stream str) { CurrStream = str; }
// switchstream method? flush old stream?
private Stream _currStream;
public SwitcherStream()
{
}
public override bool CanRead { get { return CurrStream.CanRead; } }
public override bool CanSeek { get { return CurrStream.CanSeek; } }
public override bool CanWrite { get { return CurrStream.CanWrite; } }
public override void Flush()
{
CurrStream.Flush();
}
public override bool CanRead { get { return _currStream.CanRead; } }
public override bool CanSeek { get { return _currStream.CanSeek; } }
public override bool CanWrite { get { return _currStream.CanWrite; } }
public override long Length { get { return CurrStream.Length; } }
public override long Length { get { return _currStream.Length; } }
public override long Position
{
get
{
return CurrStream.Position;
return _currStream.Position;
}
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)
{
return CurrStream.Read(buffer, offset, count);
return _currStream.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return CurrStream.Seek(offset, origin);
return _currStream.Seek(offset, origin);
}
public override void SetLength(long value)
{
CurrStream.SetLength(value);
_currStream.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
CurrStream.Write(buffer, offset, count);
_currStream.Write(buffer, offset, count);
}
}
}

View File

@ -6,9 +6,7 @@ namespace BizHawk.Common
public class UndoHistory<T>
{
private List<List<T>> _history = new List<List<T>>();
private int curPos; //1-based
public bool Enabled { get; private set; }
private int _curPos; // 1-based
public UndoHistory(bool enabled)
{
@ -21,20 +19,16 @@ namespace BizHawk.Common
Enabled = enabled;
}
public void Clear()
{
_history = new List<List<T>>();
curPos = 0;
}
public bool Enabled { get; private set; }
public bool CanUndo
{
get { return Enabled && curPos > 1; }
get { return Enabled && _curPos > 1; }
}
public bool CanRedo
{
get { return Enabled && curPos < _history.Count; }
get { return Enabled && _curPos < _history.Count; }
}
public bool HasHistory
@ -42,20 +36,26 @@ namespace BizHawk.Common
get { return Enabled && _history.Any(); }
}
public void Clear()
{
_history = new List<List<T>>();
_curPos = 0;
}
public void AddState(IEnumerable<T> newState)
{
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.Add(newState.ToList());
curPos = _history.Count;
_curPos = _history.Count;
}
}
@ -63,26 +63,22 @@ namespace BizHawk.Common
{
if (CanUndo && Enabled)
{
curPos--;
return _history[curPos - 1];
}
else
{
return null;
_curPos--;
return _history[_curPos - 1];
}
return Enumerable.Empty<T>();
}
public IEnumerable<T> Redo()
{
if (CanRedo && Enabled)
{
curPos++;
return _history[curPos - 1];
}
else
{
return null;
_curPos++;
return _history[_curPos - 1];
}
return Enumerable.Empty<T>();
}
}
}

View File

@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Collections.Generic;
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 System.Runtime.InteropServices.GCHandle HexConvHandle;
public static char* HexConvPtr { get; set; }
static Util()
{
HexConvHandle = System.Runtime.InteropServices.GCHandle.Alloc(HexConvArr, System.Runtime.InteropServices.GCHandleType.Pinned);
HexConvPtr = (char*)HexConvHandle.AddrOfPinnedObject().ToPointer();
}
public static char* HexConvPtr { get; set; }
public static string Hash_MD5(byte[] data, int offset, int len)
{
using (var md5 = System.Security.Cryptography.MD5.Create())
@ -58,11 +58,11 @@ namespace BizHawk.Common
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)
{
var read = new byte[bytes];
for (int b = 0; b < bytes; b++)
for (var b = 0; b < bytes; b++)
{
read[b] = r.ReadByte();
}
@ -84,7 +84,7 @@ namespace BizHawk.Common
public static string ReadStringAsciiZ(this BinaryReader r)
{
var sb = new StringBuilder();
for (; ; )
for (;;)
{
int b = r.ReadByte();
if (b <= 0)
@ -128,7 +128,7 @@ namespace BizHawk.Common
int d = 0;
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')
{
d += c - '0';
@ -146,11 +146,11 @@ namespace BizHawk.Common
{
d <<= 4;
}
}
ms.WriteByte((byte)d);
}
return ms.ToArray();
}
@ -346,11 +346,11 @@ namespace BizHawk.Common
public static string FormatFileSize(long filesize)
{
Decimal size = filesize;
decimal size = filesize;
Decimal OneKiloByte = 1024M;
Decimal OneMegaByte = OneKiloByte * 1024M;
Decimal OneGigaByte = OneMegaByte * 1024M;
const decimal OneKiloByte = 1024M;
const decimal OneMegaByte = OneKiloByte * 1024M;
decimal OneGigaByte = OneMegaByte * 1024M;
string suffix;
if (size > 1024 * 1024 * 1024)
@ -373,26 +373,45 @@ namespace BizHawk.Common
suffix = " B";
}
var precision = "2";
return String.Format("{0:N" + precision + "}{1}", size, suffix);
const string precision = "2";
return string.Format("{0:N" + precision + "}{1}", size, suffix);
}
// http://stackoverflow.com/questions/3928822/comparing-2-dictionarystring-string-instances
public static bool DictionaryEqual<TKey, TValue>(
IDictionary<TKey, TValue> first, IDictionary<TKey, TValue> second)
{
if (first == second) return true;
if ((first == null) || (second == null)) return false;
if (first.Count != second.Count) return false;
if (first == second)
{
return true;
}
if ((first == null) || (second == null))
{
return false;
}
if (first.Count != second.Count)
{
return false;
}
var comparer = EqualityComparer<TValue>.Default;
foreach (KeyValuePair<TKey, TValue> kvp in first)
foreach (var kvp in first)
{
TValue secondValue;
if (!second.TryGetValue(kvp.Key, out secondValue)) return false;
if (!comparer.Equals(kvp.Value, secondValue)) return false;
if (!second.TryGetValue(kvp.Key, out secondValue))
{
return false;
}
if (!comparer.Equals(kvp.Value, secondValue))
{
return false;
}
}
return true;
}
@ -407,9 +426,11 @@ namespace BizHawk.Common
{
TValue ret;
if (!dict.TryGetValue(key, out ret))
{
return defaultvalue;
else
return ret;
}
return ret;
}
}
@ -420,6 +441,14 @@ namespace BizHawk.Common
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()
{
int myctr;
@ -430,13 +459,5 @@ namespace BizHawk.Common
return StaticPart + "-" + myctr;
}
static SuperGloballyUniqueID()
{
StaticPart = "bizhawk-" + System.Diagnostics.Process.GetCurrentProcess().Id + "-" + Guid.NewGuid();
}
private static readonly string StaticPart;
private static int ctr;
}
}