Cleanup Util

This commit is contained in:
YoshiRulz 2020-01-23 10:22:54 +10:00
parent 8de0355228
commit ff2efca658
No known key found for this signature in database
GPG Key ID: C4DE31C245353FB7
8 changed files with 378 additions and 523 deletions

View File

@ -261,7 +261,7 @@ namespace BizHawk.Client.Common
if (blob[0] == '0' && (blob[1] == 'x' || blob[1] == 'X'))
{
// hex
return Util.HexStringToBytes(blob.Substring(2));
return blob.Substring(2).HexStringToBytes();
}
// base64

View File

@ -1,7 +1,6 @@
using System;
using System.IO;
using BizHawk.Common;
using BizHawk.Emulation.Common.IEmulatorExtensions;
namespace BizHawk.Client.Common
@ -388,4 +387,36 @@ namespace BizHawk.Client.Common
}
}
}
public static class VLInteger
{
public static void WriteUnsigned(uint value, byte[] data, ref int index)
{
// This is optimized for good performance on both the x86 and x64 JITs. Don't change anything without benchmarking.
do
{
var x = value & 0x7FU;
value >>= 7;
data[index++] = (byte)((value != 0U ? 0x80U : 0U) | x);
}
while (value != 0U);
}
public static uint ReadUnsigned(byte[] data, ref int index)
{
// This is optimized for good performance on both the x86 and x64 JITs. Don't change anything without benchmarking.
var value = 0U;
var shiftCount = 0;
bool isLastByte; // Negating the comparison and moving it earlier in the loop helps a lot on x86 for some reason
do
{
var x = (uint)data[index++];
isLastByte = (x & 0x80U) == 0U;
value |= (x & 0x7FU) << shiftCount;
shiftCount += 7;
}
while (!isLastByte);
return value;
}
}
}

View File

@ -10,14 +10,14 @@ namespace BizHawk.Client.EmuHawk
{
public Type GetTool(string name)
{
var toolType = ReflectionUtil.GetTypeByName(name).FirstOrDefault(x => typeof(IToolForm).IsAssignableFrom(x) && !x.IsInterface);
var toolType = Util.GetTypeByName(name).FirstOrDefault(x => typeof(IToolForm).IsAssignableFrom(x) && !x.IsInterface);
if (toolType != null) GlobalWin.Tools.Load(toolType);
return GlobalWin.Tools.AvailableTools.FirstOrDefault(tool => tool.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase));
}
public object CreateInstance(string name)
{
var found = ReflectionUtil.GetTypeByName(name).FirstOrDefault();
var found = Util.GetTypeByName(name).FirstOrDefault();
return found != null ? Activator.CreateInstance(found) : null;
}

View File

@ -14,5 +14,6 @@
<Compile Include="../Version/svnrev.cs" />
<Compile Include="../Version/VersionInfo.cs" />
<Compile Remove="Extensions/BinaryReaderExtensions.cs" />
<Compile Remove="SuperGloballyUniqueID.cs" />
</ItemGroup>
</Project>

View File

@ -184,11 +184,11 @@ namespace BizHawk.Common
}
else if (IsReader)
{
val = Util.ReadByteBuffer(_br, useNull);
val = _br.ReadByteBuffer(useNull);
}
else
{
Util.WriteByteBuffer(_bw, val);
_bw.WriteByteBuffer(val);
}
}
@ -198,7 +198,7 @@ namespace BizHawk.Common
{
if (Present(name))
{
val = Util.HexStringToBytes(Item(name));
val = Item(name).HexStringToBytes();
}
if (val != null && val.Length == 0 && useNull)
@ -221,7 +221,7 @@ namespace BizHawk.Common
}
else if (IsReader)
{
val = Util.ByteBufferToBoolBuffer(Util.ReadByteBuffer(_br, false));
val = _br.ReadByteBuffer(false).ToBoolBuffer();
if (val == null && !useNull)
{
val = new bool[0];
@ -229,7 +229,7 @@ namespace BizHawk.Common
}
else
{
Util.WriteByteBuffer(_bw, Util.BoolBufferToByteBuffer(val));
_bw.WriteByteBuffer(val.ToUByteBuffer());
}
}
@ -239,8 +239,8 @@ namespace BizHawk.Common
{
if (Present(name))
{
var bytes = Util.HexStringToBytes(Item(name));
val = Util.ByteBufferToBoolBuffer(bytes);
var bytes = Item(name).HexStringToBytes();
val = bytes.ToBoolBuffer();
}
if (val != null && val.Length == 0 && useNull)
@ -251,7 +251,7 @@ namespace BizHawk.Common
else
{
var temp = val ?? new bool[0];
_tw.WriteLine("{0} {1}", name, Util.BoolBufferToByteBuffer(temp).BytesToHexString());
_tw.WriteLine("{0} {1}", name, temp.ToUByteBuffer().BytesToHexString());
}
}
public void Sync(string name, ref short[] val, bool useNull)
@ -262,7 +262,7 @@ namespace BizHawk.Common
}
else if (IsReader)
{
val = Util.ByteBufferToShortBuffer(Util.ReadByteBuffer(_br, false));
val = _br.ReadByteBuffer(false).ToShortBuffer();
if (val == null && !useNull)
{
val = new short[0];
@ -270,7 +270,7 @@ namespace BizHawk.Common
}
else
{
Util.WriteByteBuffer(_bw, Util.ShortBufferToByteBuffer(val));
_bw.WriteByteBuffer(val.ToUByteBuffer());
}
}
@ -282,7 +282,7 @@ namespace BizHawk.Common
}
else if (IsReader)
{
val = Util.ByteBufferToUshortBuffer(Util.ReadByteBuffer(_br, false));
val = _br.ReadByteBuffer(false).ToUShortBuffer();
if (val == null && !useNull)
{
val = new ushort[0];
@ -290,7 +290,7 @@ namespace BizHawk.Common
}
else
{
Util.WriteByteBuffer(_bw, Util.UshortBufferToByteBuffer(val));
_bw.WriteByteBuffer(val.ToUByteBuffer());
}
}
@ -300,8 +300,8 @@ namespace BizHawk.Common
{
if (Present(name))
{
var bytes = Util.HexStringToBytes(Item(name));
val = Util.ByteBufferToShortBuffer(bytes);
var bytes = Item(name).HexStringToBytes();
val = bytes.ToShortBuffer();
}
if (val != null && val.Length == 0 && useNull)
@ -312,7 +312,7 @@ namespace BizHawk.Common
else
{
var temp = val ?? new short[0];
_tw.WriteLine("{0} {1}", name, Util.ShortBufferToByteBuffer(temp).BytesToHexString());
_tw.WriteLine("{0} {1}", name, temp.ToUByteBuffer().BytesToHexString());
}
}
@ -322,8 +322,8 @@ namespace BizHawk.Common
{
if (Present(name))
{
var bytes = Util.HexStringToBytes(Item(name));
val = Util.ByteBufferToUshortBuffer(bytes);
var bytes = Item(name).HexStringToBytes();
val = bytes.ToUShortBuffer();
}
if (val != null && val.Length == 0 && useNull)
@ -334,7 +334,7 @@ namespace BizHawk.Common
else
{
var temp = val ?? new ushort[0];
_tw.WriteLine("{0} {1}", name, Util.UshortBufferToByteBuffer(temp).BytesToHexString());
_tw.WriteLine("{0} {1}", name, temp.ToUByteBuffer().BytesToHexString());
}
}
@ -346,7 +346,7 @@ namespace BizHawk.Common
}
else if (IsReader)
{
val = Util.ByteBufferToIntBuffer(Util.ReadByteBuffer(_br, false));
val = _br.ReadByteBuffer(false).ToIntBuffer();
if (val == null && !useNull)
{
val = new int[0];
@ -354,7 +354,7 @@ namespace BizHawk.Common
}
else
{
Util.WriteByteBuffer(_bw, Util.IntBufferToByteBuffer(val));
_bw.WriteByteBuffer(val.ToUByteBuffer());
}
}
@ -364,8 +364,8 @@ namespace BizHawk.Common
{
if (Present(name))
{
var bytes = Util.HexStringToBytes(Item(name));
val = Util.ByteBufferToIntBuffer(bytes);
var bytes = Item(name).HexStringToBytes();
val = bytes.ToIntBuffer();
}
if (val != null && val.Length == 0 && useNull)
@ -376,7 +376,7 @@ namespace BizHawk.Common
else
{
var temp = val ?? new int[0];
_tw.WriteLine("{0} {1}", name, Util.IntBufferToByteBuffer(temp).BytesToHexString());
_tw.WriteLine("{0} {1}", name, temp.ToUByteBuffer().BytesToHexString());
}
}
@ -388,7 +388,7 @@ namespace BizHawk.Common
}
else if (IsReader)
{
val = Util.ByteBufferToUintBuffer(Util.ReadByteBuffer(_br, false));
val = _br.ReadByteBuffer(false).ToUIntBuffer();
if (val == null && !useNull)
{
val = new uint[0];
@ -396,7 +396,7 @@ namespace BizHawk.Common
}
else
{
Util.WriteByteBuffer(_bw, Util.UintBufferToByteBuffer(val));
_bw.WriteByteBuffer(val.ToUByteBuffer());
}
}
@ -406,8 +406,8 @@ namespace BizHawk.Common
{
if (Present(name))
{
var bytes = Util.HexStringToBytes(Item(name));
val = Util.ByteBufferToUintBuffer(bytes);
var bytes = Item(name).HexStringToBytes();
val = bytes.ToUIntBuffer();
}
if (val != null && val.Length == 0 && useNull)
@ -418,7 +418,7 @@ namespace BizHawk.Common
else
{
var temp = val ?? new uint[0];
_tw.WriteLine("{0} {1}", name, Util.UintBufferToByteBuffer(temp).BytesToHexString());
_tw.WriteLine("{0} {1}", name, temp.ToUByteBuffer().BytesToHexString());
}
}
@ -430,7 +430,7 @@ namespace BizHawk.Common
}
else if (IsReader)
{
val = Util.ByteBufferToFloatBuffer(Util.ReadByteBuffer(_br, false));
val = _br.ReadByteBuffer(false).ToFloatBuffer();
if (val == null && !useNull)
{
val = new float[0];
@ -438,7 +438,7 @@ namespace BizHawk.Common
}
else
{
Util.WriteByteBuffer(_bw, Util.FloatBufferToByteBuffer(val));
_bw.WriteByteBuffer(val.ToUByteBuffer());
}
}
@ -448,8 +448,8 @@ namespace BizHawk.Common
{
if (Present(name))
{
var bytes = Util.HexStringToBytes(Item(name));
val = Util.ByteBufferToFloatBuffer(bytes);
var bytes = Item(name).HexStringToBytes();
val = bytes.ToFloatBuffer();
}
if (val != null && val.Length == 0 && useNull)
@ -460,7 +460,7 @@ namespace BizHawk.Common
else
{
var temp = val ?? new float[0];
_tw.WriteLine("{0} {1}", name, Util.FloatBufferToByteBuffer(temp).BytesToHexString());
_tw.WriteLine("{0} {1}", name, temp.ToUByteBuffer().BytesToHexString());
}
}
@ -472,7 +472,7 @@ namespace BizHawk.Common
}
else if (IsReader)
{
val = Util.ByteBufferToDoubleBuffer(Util.ReadByteBuffer(_br, false));
val = _br.ReadByteBuffer(false).ToDoubleBuffer();
if (val == null && !useNull)
{
val = new double[0];
@ -480,7 +480,7 @@ namespace BizHawk.Common
}
else
{
Util.WriteByteBuffer(_bw, Util.DoubleBufferToByteBuffer(val));
_bw.WriteByteBuffer(val.ToUByteBuffer());
}
}
@ -490,8 +490,8 @@ namespace BizHawk.Common
{
if (Present(name))
{
var bytes = Util.HexStringToBytes(Item(name));
val = Util.ByteBufferToDoubleBuffer(bytes);
var bytes = Item(name).HexStringToBytes();
val = bytes.ToDoubleBuffer();
}
if (val != null && val.Length == 0 && useNull)
@ -502,7 +502,7 @@ namespace BizHawk.Common
else
{
var temp = val ?? new double[0];
_tw.WriteLine("{0} {1}", name, Util.DoubleBufferToByteBuffer(temp).BytesToHexString());
_tw.WriteLine("{0} {1}", name, temp.ToUByteBuffer().BytesToHexString());
}
}

View File

@ -0,0 +1,19 @@
namespace BizHawk.Common
{
using System;
using System.Diagnostics;
internal static class SuperGloballyUniqueID
{
private static readonly string StaticPart = $"bizhawk-{Process.GetCurrentProcess().Id}-{Guid.NewGuid()}";
private static int ctr;
public static string Next()
{
int myctr;
lock (typeof(SuperGloballyUniqueID)) myctr = ctr++;
return $"{StaticPart}-{myctr}";
}
}
}

View File

@ -1,140 +1,325 @@
#nullable disable
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Reflection;
using System.Text;
namespace BizHawk.Common
namespace BizHawk.Common
{
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Threading;
public static unsafe class Util
{
public static void CopyStream(Stream src, Stream dest, long len)
{
const int size = 0x2000;
byte[] buffer = new byte[size];
var buffer = new byte[size];
while (len > 0)
{
long todo = len;
if (len > size) todo = size;
int n = src.Read(buffer, 0, (int)todo);
var todo = Math.Min(len, size);
var n = src.Read(buffer, 0, (int) todo);
dest.Write(buffer, 0, n);
len -= n;
}
}
/// <summary>
/// Waits 250ms for a file to vanish. Returns whether it succeeded
/// </summary>
public static bool TryWaitForFileToVanish(string path)
/// <exception cref="InvalidOperationException">issues with parsing <paramref name="src"/></exception>
/// <remarks>TODO use <see cref="MemoryStream(int)"/> and <see cref="MemoryStream.ToArray"/> instead of using <see cref="MemoryStream(byte[])"/> and keeping a reference to the array? --yoshi</remarks>
public static byte[] DecompressGzipFile(Stream src)
{
for (int i = 0; i < 25; i++) // 250ms
{
if (!File.Exists(path))
{
return true;
}
System.Threading.Thread.Sleep(10);
}
return false;
var tmp = new byte[4];
if (src.Read(tmp, 0, 2) != 2) throw new InvalidOperationException("Unexpected end of stream");
if (tmp[0] != 0x1F || tmp[1] != 0x8B) throw new InvalidOperationException("GZIP header not present");
src.Seek(-4, SeekOrigin.End);
src.Read(tmp, 0, 4);
src.Seek(0, SeekOrigin.Begin);
using var gs = new GZipStream(src, CompressionMode.Decompress, true);
var data = new byte[BitConverter.ToInt32(tmp, 0)];
using var ms = new MemoryStream(data);
gs.CopyTo(ms);
return data;
}
/// <summary>
/// Tries to moves `pathWant` out of the way to `pathBackup`, delaying as needed to accomodate filesystem being sucky.
/// `pathWant` might not be removed after all, in case it's snagged by something.
/// </summary>
public static bool TryMoveBackupFile(string pathWant, string pathBackup)
/// <remarks>adapted from https://stackoverflow.com/a/3928856/7467292, values are compared using <see cref="EqualityComparer.Default">EqualityComparer.Default</see></remarks>
public static bool DictionaryEqual<TKey, TValue>(IDictionary<TKey, TValue> a, IDictionary<TKey, TValue> b)
where TKey : notnull
{
// If the path we want is available we dont actually have to make a backup
if (!File.Exists(pathWant))
if (a == b) return true;
if (a.Count != b.Count) return false;
var comparer = EqualityComparer<TValue>.Default;
return a.All(kvp => b.TryGetValue(kvp.Key, out var bVal) && comparer.Equals(kvp.Value, bVal));
}
/// <param name="filesize">in bytes</param>
/// <returns>human-readable filesize (converts units up to tebibytes)</returns>
public static string FormatFileSize(long filesize)
{
if (filesize < 1024) return $"{filesize} B";
if (filesize < 1048576) return $"{filesize / 1024.0:.##} KiB";
if (filesize < 1073741824) return $"{filesize / 1048576.0:.##} MiB";
if (filesize < 1099511627776) return $"{filesize / 1073741824.0:.##} GiB";
return $"{filesize / 1099511627776.0:.##} TiB";
}
/// <returns>all <see cref="Type">Types</see> with the name <paramref name="className"/></returns>
/// <remarks>adapted from https://stackoverflow.com/a/13727044/7467292</remarks>
public static IList<Type> GetTypeByName(string className) => AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(asm => asm.GetTypes().Where(type => className.Equals(type.Name, StringComparison.InvariantCultureIgnoreCase))).ToList();
/// <exception cref="ArgumentException"><paramref name="str"/> has an odd number of chars or contains a char not in <c>[0-9A-Fa-f]</c></exception>
public static byte[] HexStringToBytes(this string str)
{
if (str.Length % 2 != 0) throw new ArgumentException();
static int CharToNybble(char c)
{
return true;
if ('0' <= c && c <= '9') return c - 0x30;
if ('A' <= c && c <= 'F') return c - 0x37;
if ('a' <= c && c <= 'f') return c - 0x57;
throw new ArgumentException();
}
using var ms = new MemoryStream();
for (int i = 0, l = str.Length / 2; i != l; i++) ms.WriteByte((byte) ((CharToNybble(str[2 * i]) << 4) + CharToNybble(str[2 * i + 1])));
return ms.ToArray();
}
public static int Memcmp(void* a, void* b, int len)
{
var ba = (byte*) a;
var bb = (byte*) b;
for (var i = 0; i != len; i++)
{
var _a = ba[i];
var _b = bb[i];
var c = _a - _b;
if (c != 0) return c;
}
return 0;
}
public static void Memset(void* ptr, int val, int len)
{
var bptr = (byte*) ptr;
for (var i = 0; i != len; i++) bptr[i] = (byte) val;
}
public static byte[]? ReadByteBuffer(this BinaryReader br, bool returnNull)
{
var len = br.ReadInt32();
if (len == 0 && returnNull) return null;
var ret = new byte[len];
var ofs = 0;
while (len > 0)
{
var done = br.Read(ret, ofs, len);
ofs += done;
len -= done;
}
return ret;
}
/// <remarks>Any non-zero element is interpreted as <see langword="true"/>.</remarks>
public static bool[] ToBoolBuffer(this byte[] buf)
{
var ret = new bool[buf.Length];
for (int i = 0, len = buf.Length; i != len; i++) ret[i] = buf[i] != 0;
return ret;
}
public static double[] ToDoubleBuffer(this byte[] buf)
{
var len = buf.Length;
var ret = new double[len / 8];
Buffer.BlockCopy(buf, 0, ret, 0, len);
return ret;
}
public static float[] ToFloatBuffer(this byte[] buf)
{
var len = buf.Length / 4;
var ret = new float[len];
Buffer.BlockCopy(buf, 0, ret, 0, len); //TODO bug? the last arg should be in bytes
return ret;
}
/// <remarks>Each set of 4 elements in <paramref name="buf"/> becomes 1 element in the returned buffer. The first of each set is interpreted as the LSB, with the 4th being the MSB. Elements are used as raw bits without regard for sign.</remarks>
public static int[] ToIntBuffer(this byte[] buf)
{
var len = buf.Length / 4;
var ret = new int[len];
unchecked
{
for (var i = 0; i != len; i++) ret[i] = (buf[4 * i + 3] << 24) | (buf[4 * i + 2] << 16) | (buf[4 * i + 1] << 8) | buf[4 * i];
}
return ret;
}
/// <remarks>Each pair of elements in <paramref name="buf"/> becomes 1 element in the returned buffer. The first of each pair is interpreted as the LSB. Elements are used as raw bits without regard for sign.</remarks>
public static short[] ToShortBuffer(this byte[] buf)
{
var len = buf.Length / 2;
var ret = new short[len];
unchecked
{
for (var i = 0; i != len; i++) ret[i] = (short) ((buf[2 * i + 1] << 8) | buf[2 * i]);
}
return ret;
}
public static byte[] ToUByteBuffer(this bool[] buf)
{
var ret = new byte[buf.Length];
for (int i = 0, len = buf.Length; i != len; i++) ret[i] = buf[i] ? (byte) 1 : (byte) 0;
return ret;
}
public static byte[] ToUByteBuffer(this double[] buf)
{
var len = buf.Length * 8;
var ret = new byte[len];
Buffer.BlockCopy(buf, 0, ret, 0, len);
return ret;
}
public static byte[] ToUByteBuffer(this float[] buf)
{
var len = buf.Length * 4;
var ret = new byte[len];
Buffer.BlockCopy(buf, 0, ret, 0, len);
return ret;
}
/// <remarks>Each element of <paramref name="buf"/> becomes 4 elements in the returned buffer, with the LSB coming first. Elements are used as raw bits without regard for sign.</remarks>
public static byte[] ToUByteBuffer(this int[] buf)
{
var len = buf.Length;
var ret = new byte[4 * len];
unchecked
{
for (var i = 0; i != len; i++)
{
ret[4 * i] = (byte) buf[i];
ret[4 * i + 1] = (byte) (buf[i] >> 8);
ret[4 * i + 2] = (byte) (buf[i] >> 16);
ret[4 * i + 3] = (byte) (buf[i] >> 24);
}
}
return ret;
}
/// <remarks>Each element of <paramref name="buf"/> becomes 2 elements in the returned buffer, with the LSB coming first. Elements are used as raw bits without regard for sign.</remarks>
public static byte[] ToUByteBuffer(this short[] buf)
{
var len = buf.Length;
var ret = new byte[2 * len];
unchecked
{
for (var i = 0; i != len; i++)
{
ret[2 * i] = (byte) buf[i];
ret[2 * i + 1] = (byte) (buf[i] >> 8);
}
}
return ret;
}
/// <inheritdoc cref="ToUByteBuffer(int[])"/>
public static byte[] ToUByteBuffer(this uint[] buf)
{
var len = buf.Length;
var ret = new byte[4 * len];
unchecked
{
for (var i = 0; i != len; i++)
{
ret[4 * i] = (byte) buf[i];
ret[4 * i + 1] = (byte) (buf[i] >> 8);
ret[4 * i + 2] = (byte) (buf[i] >> 16);
ret[4 * i + 3] = (byte) (buf[i] >> 24);
}
}
return ret;
}
/// <inheritdoc cref="ToUByteBuffer(short[])"/>
public static byte[] ToUByteBuffer(this ushort[] buf)
{
var len = buf.Length;
var ret = new byte[2 * len];
unchecked
{
for (var i = 0; i != len; i++)
{
ret[2 * i] = (byte) buf[i];
ret[2 * i + 1] = (byte) (buf[i] >> 8);
}
}
return ret;
}
/// <inheritdoc cref="ToIntBuffer"/>
public static uint[] ToUIntBuffer(this byte[] buf)
{
var len = buf.Length / 4;
var ret = new uint[len];
unchecked
{
for (var i = 0; i != len; i++) ret[i] = (uint) ((buf[4 * i + 3] << 24) | (buf[4 * i + 2] << 16) | (buf[4 * i + 1] << 8) | buf[4 * i]);
}
return ret;
}
/// <inheritdoc cref="ToShortBuffer"/>
public static ushort[] ToUShortBuffer(this byte[] buf)
{
var len = buf.Length / 2;
var ret = new ushort[len];
unchecked
{
for (var i = 0; i != len; i++) ret[i] = (ushort) ((buf[2 * i + 1] << 8) | buf[2 * i]);
}
return ret;
}
/// <summary>Tries really hard to keep the contents of <paramref name="desiredPath"/> saved (as <paramref name="backupPath"/>) while freeing that path to be used for a new file.</summary>
/// <remarks>If both <paramref name="desiredPath"/> and <paramref name="backupPath"/> exist, <paramref name="backupPath"/> is always deleted.</remarks>
public static bool TryMoveBackupFile(string desiredPath, string backupPath)
{
if (!File.Exists(desiredPath)) return true; // desired path already free
// delete any existing backup
try
{
if (File.Exists(pathBackup))
{
File.Delete(pathBackup);
}
if (File.Exists(backupPath)) File.Delete(backupPath);
}
catch
{
// just give up on the whole thing in case of exceptions. pathWant will get overwritten by the caller.
return false;
return false; // if Exists or Delete threw, there's not much we can do -- the caller will either overwrite the file or fail itself
}
// deletes are asynchronous, need to wait for it to be gone
if(!TryWaitForFileToVanish(pathBackup))
// deletions are asynchronous, so wait for a while and then give up
static bool TryWaitForFileToVanish(string path)
{
// gave up waiting for existing backup to be gone. the whole thing's a total loss
for (var i = 25; i != 0; i--)
{
if (!File.Exists(path)) return true;
Thread.Sleep(10);
}
return false;
}
if (!TryWaitForFileToVanish(backupPath)) return false;
// the backup path is available now, so perform the backup and then wait for it to finish
try
{
// actually move pathWant out of the way to pathBackup now that pathBackup is free
File.Move(pathWant, pathBackup);
File.Move(desiredPath, backupPath);
return TryWaitForFileToVanish(desiredPath);
}
catch
{
// Eat it, this will happen rarely and the user will rarely need the file, so the odds of simply not making the backup is very unlikely
return false;
return false; // this will be hit in the unlikely event that something else wrote to the backup path after we checked it was okay
}
// hmm these might be asynchronous too
// wait for the move to complete, at least enough for pathWant to be cleared up
return TryWaitForFileToVanish(pathWant);
}
/// <exception cref="ArgumentException"><paramref name="str"/> has an odd number of chars or contains a char not in <c>[0-9A-Fa-f]</c></exception>
/// <remarks>could be extension method</remarks>
public static byte[] HexStringToBytes(string str)
{
var ms = new MemoryStream();
if (str.Length % 2 != 0)
{
throw new ArgumentException();
}
int len = str.Length / 2;
for (int i = 0; i < len; i++)
{
int d = 0;
for (int j = 0; j < 2; j++)
{
var c = char.ToLower(str[(i * 2) + j]);
if (c >= '0' && c <= '9')
{
d += c - '0';
}
else if (c >= 'a' && c <= 'f')
{
d += (c - 'a') + 10;
}
else
{
throw new ArgumentException();
}
if (j == 0)
{
d <<= 4;
}
}
ms.WriteByte((byte)d);
}
return ms.ToArray();
}
// Could be extension method
public static void WriteByteBuffer(BinaryWriter bw, byte[] data)
public static void WriteByteBuffer(this BinaryWriter bw, byte[]? data)
{
if (data == null)
{
@ -146,388 +331,5 @@ namespace BizHawk.Common
bw.Write(data);
}
}
public static bool[] ByteBufferToBoolBuffer(byte[] buf)
{
var ret = new bool[buf.Length];
for (int i = 0; i < buf.Length; i++)
{
ret[i] = buf[i] != 0;
}
return ret;
}
public static byte[] BoolBufferToByteBuffer(bool[] buf)
{
var ret = new byte[buf.Length];
for (int i = 0; i < buf.Length; i++)
{
ret[i] = (byte)(buf[i] ? 1 : 0);
}
return ret;
}
public static short[] ByteBufferToShortBuffer(byte[] buf)
{
int num = buf.Length / 2;
var ret = new short[num];
for (int i = 0; i < num; i++)
{
ret[i] = (short)(buf[i * 2] | (buf[i * 2 + 1] << 8));
}
return ret;
}
public static byte[] ShortBufferToByteBuffer(short[] buf)
{
int num = buf.Length;
var ret = new byte[num * 2];
for (int i = 0; i < num; i++)
{
ret[i * 2 + 0] = (byte)(buf[i] & 0xFF);
ret[i * 2 + 1] = (byte)((buf[i] >> 8) & 0xFF);
}
return ret;
}
public static ushort[] ByteBufferToUshortBuffer(byte[] buf)
{
int num = buf.Length / 2;
var ret = new ushort[num];
for (int i = 0; i < num; i++)
{
ret[i] = (ushort)(buf[i * 2] | (buf[i * 2 + 1] << 8));
}
return ret;
}
public static byte[] UshortBufferToByteBuffer(ushort[] buf)
{
int num = buf.Length;
var ret = new byte[num * 2];
for (int i = 0; i < num; i++)
{
ret[i * 2 + 0] = (byte)(buf[i] & 0xFF);
ret[i * 2 + 1] = (byte)((buf[i] >> 8) & 0xFF);
}
return ret;
}
public static uint[] ByteBufferToUintBuffer(byte[] buf)
{
int num = buf.Length / 4;
var ret = new uint[num];
for (int i = 0; i < num; i++)
{
ret[i] = (uint)(buf[i * 4] | (buf[i * 4 + 1] << 8) | (buf[i * 4 + 2] << 16) | (buf[i * 4 + 3] << 24));
}
return ret;
}
public static byte[] UintBufferToByteBuffer(uint[] buf)
{
int num = buf.Length;
var ret = new byte[num * 4];
for (int i = 0; i < num; i++)
{
ret[i * 4 + 0] = (byte)(buf[i] & 0xFF);
ret[i * 4 + 1] = (byte)((buf[i] >> 8) & 0xFF);
ret[i * 4 + 2] = (byte)((buf[i] >> 16) & 0xFF);
ret[i * 4 + 3] = (byte)((buf[i] >> 24) & 0xFF);
}
return ret;
}
public static int[] ByteBufferToIntBuffer(byte[] buf)
{
int num = buf.Length / 4;
var ret = new int[num];
for (int i = 0; i < num; i++)
{
ret[i] = buf[(i * 4) + 3];
ret[i] <<= 8;
ret[i] |= buf[(i * 4) + 2];
ret[i] <<= 8;
ret[i] |= buf[(i * 4) + 1];
ret[i] <<= 8;
ret[i] |= buf[(i * 4)];
}
return ret;
}
public static byte[] IntBufferToByteBuffer(int[] buf)
{
int num = buf.Length;
var ret = new byte[num * 4];
for (int i = 0; i < num; i++)
{
ret[i * 4 + 0] = (byte)(buf[i] & 0xFF);
ret[i * 4 + 1] = (byte)((buf[i] >> 8) & 0xFF);
ret[i * 4 + 2] = (byte)((buf[i] >> 16) & 0xFF);
ret[i * 4 + 3] = (byte)((buf[i] >> 24) & 0xFF);
}
return ret;
}
public static float[] ByteBufferToFloatBuffer(byte[] buf)
{
int num = buf.Length / sizeof(float);
var ret = new float[num];
Buffer.BlockCopy(buf, 0, ret, 0, num);
return ret;
}
public static byte[] FloatBufferToByteBuffer(float[] buf)
{
int num = buf.Length;
var ret = new byte[num * sizeof(float)];
Buffer.BlockCopy(buf, 0, ret, 0, ret.Length);
return ret;
}
public static double[] ByteBufferToDoubleBuffer(byte[] buf)
{
int num = buf.Length;
var ret = new double[num / sizeof(double)];
Buffer.BlockCopy(buf, 0, ret, 0, num);
return ret;
}
public static byte[] DoubleBufferToByteBuffer(double[] buf)
{
int num = buf.Length;
var ret = new byte[num * sizeof(double)];
Buffer.BlockCopy(buf, 0, ret, 0, ret.Length);
return ret;
}
public static byte[] ReadByteBuffer(BinaryReader br, bool returnNull)
{
int len = br.ReadInt32();
if (len == 0 && returnNull)
{
return null;
}
var ret = new byte[len];
int ofs = 0;
while (len > 0)
{
int done = br.Read(ret, ofs, len);
ofs += done;
len -= done;
}
return ret;
}
public static int Memcmp(void* a, void* b, int len)
{
var ba = (byte*)a;
var bb = (byte*)b;
for (int i = 0; i < len; i++)
{
byte _a = ba[i];
byte _b = bb[i];
int c = _a - _b;
if (c != 0)
{
return c;
}
}
return 0;
}
public static void Memset(void* ptr, int val, int len)
{
var bptr = (byte*)ptr;
for (int i = 0; i < len; i++)
{
bptr[i] = (byte)val;
}
}
public static string FormatFileSize(long filesize)
{
decimal size = filesize;
string suffix;
if (size > 1024 * 1024 * 1024)
{
size /= 1024 * 1024 * 1024;
suffix = "GB";
}
else if (size > 1024 * 1024)
{
size /= 1024 * 1024;
suffix = "MB";
}
else if (size > 1024)
{
size /= 1024;
suffix = "KB";
}
else
{
suffix = "B";
}
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;
}
var comparer = EqualityComparer<TValue>.Default;
foreach (var kvp in first)
{
if (!second.TryGetValue(kvp.Key, out var secondValue))
{
return false;
}
if (!comparer.Equals(kvp.Value, secondValue))
{
return false;
}
}
return true;
}
/// <exception cref="InvalidOperationException">issues with parsing <paramref name="src"/></exception>
public static byte[] DecompressGzipFile(Stream src)
{
var tmp = new byte[4];
if (src.Read(tmp, 0, 2) != 2)
throw new InvalidOperationException("Unexpected end of stream");
if (tmp[0] != 0x1f || tmp[1] != 0x8b)
throw new InvalidOperationException("GZIP header not present");
src.Seek(-4, SeekOrigin.End);
src.Read(tmp, 0, 4);
int size = BitConverter.ToInt32(tmp, 0);
var data = new byte[size];
var ms = new MemoryStream(data);
src.Seek(0, SeekOrigin.Begin);
using (var gs = new GZipStream(src, CompressionMode.Decompress, true))
gs.CopyTo(ms);
return data;
}
}
public static class VLInteger
{
public static void WriteUnsigned(uint value, byte[] data, ref int index)
{
// This is optimized for good performance on both the x86 and x64 JITs. Don't change anything without benchmarking.
do
{
uint x = value & 0x7FU;
value >>= 7;
data[index++] = (byte)((value != 0U ? 0x80U : 0U) | x);
}
while (value != 0U);
}
public static uint ReadUnsigned(byte[] data, ref int index)
{
// This is optimized for good performance on both the x86 and x64 JITs. Don't change anything without benchmarking.
uint value = 0U;
int shiftCount = 0;
bool isLastByte; // Negating the comparison and moving it earlier in the loop helps a lot on x86 for some reason
do
{
uint x = (uint)data[index++];
isLastByte = (x & 0x80U) == 0U;
value |= (x & 0x7FU) << shiftCount;
shiftCount += 7;
}
while (!isLastByte);
return value;
}
}
[Serializable]
public class NotTestedException : Exception
{
}
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;
lock (typeof(SuperGloballyUniqueID))
{
myctr = ctr++;
}
return $"{StaticPart}-{myctr}";
}
}
public static class ReflectionUtil
{
// http://stackoverflow.com/questions/9273629/avoid-giving-namespace-name-in-type-gettype
/// <summary>
/// Gets a all Type instances matching the specified class name with just non-namespace qualified class name.
/// </summary>
/// <param name="className">Name of the class sought.</param>
/// <returns>Types that have the class name specified. They may not be in the same namespace.</returns>
public static Type[] GetTypeByName(string className)
{
var returnVal = new List<Type>();
foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
{
Type[] assemblyTypes = a.GetTypes();
for (int j = 0; j < assemblyTypes.Length; j++)
{
if (assemblyTypes[j].Name.ToLower() == className.ToLower())
{
returnVal.Add(assemblyTypes[j]);
}
}
}
return returnVal.ToArray();
}
}
}

View File

@ -3,6 +3,8 @@ using BizHawk.Common.NumberExtensions;
namespace BizHawk.Emulation.Cores.Atari.Atari2600
{
using System;
/*
* Spectravideo Compumate Add-on Kevtris Documentation
@ -275,7 +277,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
}
// Attempting to read while in write mode
throw new NotTestedException();
throw new Exception("this hasn't been tested");
}
public override byte ReadMemory(ushort addr)