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
|
||||
{
|
||||
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue