2013-11-04 00:36:15 +00:00
|
|
|
|
using System;
|
2014-02-04 21:15:33 +00:00
|
|
|
|
using System.Collections.Generic;
|
2013-11-04 00:36:15 +00:00
|
|
|
|
using System.IO;
|
2017-07-01 13:06:04 +00:00
|
|
|
|
using System.IO.Compression;
|
2015-04-12 17:37:06 +00:00
|
|
|
|
using System.Reflection;
|
2017-04-13 18:57:58 +00:00
|
|
|
|
using System.Text;
|
2014-07-03 19:05:56 +00:00
|
|
|
|
|
2013-11-04 00:36:15 +00:00
|
|
|
|
namespace BizHawk.Common
|
2013-10-27 22:07:40 +00:00
|
|
|
|
{
|
2015-11-08 10:57:28 +00:00
|
|
|
|
public static unsafe partial class Util
|
2013-10-27 22:07:40 +00:00
|
|
|
|
{
|
2014-10-26 14:22:26 +00:00
|
|
|
|
public static void CopyStream(Stream src, Stream dest, long len)
|
|
|
|
|
{
|
|
|
|
|
const int size = 0x2000;
|
|
|
|
|
byte[] buffer = new byte[size];
|
|
|
|
|
while (len > 0)
|
|
|
|
|
{
|
|
|
|
|
long todo = len;
|
|
|
|
|
if (len > size) todo = size;
|
|
|
|
|
int n = src.Read(buffer, 0, (int)todo);
|
|
|
|
|
dest.Write(buffer, 0, n);
|
|
|
|
|
len -= n;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-28 02:23:31 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Waits 250ms for a file to vanish. Returns whether it succeeded
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static bool TryWaitForFileToVanish(string path)
|
|
|
|
|
{
|
2017-04-13 18:57:58 +00:00
|
|
|
|
for (int i = 0; i < 25; i++) // 250ms
|
2016-02-28 02:23:31 +00:00
|
|
|
|
{
|
|
|
|
|
if (!File.Exists(path))
|
2017-04-13 18:57:58 +00:00
|
|
|
|
{
|
2016-02-28 02:23:31 +00:00
|
|
|
|
return true;
|
2017-04-13 18:57:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-02-28 02:23:31 +00:00
|
|
|
|
System.Threading.Thread.Sleep(10);
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-27 22:19:33 +00:00
|
|
|
|
/// <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)
|
|
|
|
|
{
|
2017-04-13 18:57:58 +00:00
|
|
|
|
// If the path we want is available we dont actually have to make a backup
|
2016-02-27 22:19:33 +00:00
|
|
|
|
if (!File.Exists(pathWant))
|
2017-04-13 18:57:58 +00:00
|
|
|
|
{
|
2016-02-27 22:19:33 +00:00
|
|
|
|
return true;
|
2017-04-13 18:57:58 +00:00
|
|
|
|
}
|
2016-02-27 22:19:33 +00:00
|
|
|
|
|
2017-04-13 18:57:58 +00:00
|
|
|
|
// delete any existing backup
|
2016-02-27 22:19:33 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (File.Exists(pathBackup))
|
2017-04-13 18:57:58 +00:00
|
|
|
|
{
|
2016-02-27 22:19:33 +00:00
|
|
|
|
File.Delete(pathBackup);
|
2017-04-13 18:57:58 +00:00
|
|
|
|
}
|
2016-02-27 22:19:33 +00:00
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
2017-04-13 18:57:58 +00:00
|
|
|
|
// just give up on the whole thing in case of exceptions. pathWant will get overwritten by the caller.
|
2016-02-27 22:19:33 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-13 18:57:58 +00:00
|
|
|
|
// deletes are asynchronous, need to wait for it to be gone
|
2016-02-28 02:23:31 +00:00
|
|
|
|
if(!TryWaitForFileToVanish(pathBackup))
|
|
|
|
|
{
|
2017-04-13 18:57:58 +00:00
|
|
|
|
// gave up waiting for existing backup to be gone. the whole thing's a total loss
|
2016-02-28 02:23:31 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2016-02-27 22:19:33 +00:00
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2017-04-13 18:57:58 +00:00
|
|
|
|
// actually move pathWant out of the way to pathBackup now that pathBackup is free
|
2016-02-27 22:19:33 +00:00
|
|
|
|
File.Move(pathWant, pathBackup);
|
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-13 18:57:58 +00:00
|
|
|
|
// hmm these might be asynchronous too
|
|
|
|
|
// wait for the move to complete, at least enough for pathWant to be cleared up
|
2016-02-28 02:23:31 +00:00
|
|
|
|
return TryWaitForFileToVanish(pathWant);
|
2016-02-27 22:19:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-11-04 00:36:15 +00:00
|
|
|
|
public static bool IsPowerOfTwo(int x)
|
|
|
|
|
{
|
2013-12-14 00:03:03 +00:00
|
|
|
|
if (x == 0 || x == 1)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-04 00:36:15 +00:00
|
|
|
|
return (x & (x - 1)) == 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-14 00:03:03 +00:00
|
|
|
|
public static int SaveRamBytesUsed(byte[] saveRam)
|
2013-11-04 00:36:15 +00:00
|
|
|
|
{
|
2014-02-04 21:15:33 +00:00
|
|
|
|
for (var i = saveRam.Length - 1; i >= 0; i--)
|
2013-12-14 00:03:03 +00:00
|
|
|
|
{
|
2014-02-04 21:15:33 +00:00
|
|
|
|
if (saveRam[i] != 0)
|
2013-12-14 00:03:03 +00:00
|
|
|
|
{
|
2014-02-04 21:15:33 +00:00
|
|
|
|
return i + 1;
|
2013-12-14 00:03:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-04 00:36:15 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-14 00:03:03 +00:00
|
|
|
|
// Could be extension method
|
2013-11-04 00:36:15 +00:00
|
|
|
|
public static byte[] HexStringToBytes(string str)
|
|
|
|
|
{
|
2013-12-14 00:03:03 +00:00
|
|
|
|
var ms = new MemoryStream();
|
|
|
|
|
if (str.Length % 2 != 0)
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentException();
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-04 00:36:15 +00:00
|
|
|
|
int len = str.Length / 2;
|
|
|
|
|
for (int i = 0; i < len; i++)
|
|
|
|
|
{
|
|
|
|
|
int d = 0;
|
|
|
|
|
for (int j = 0; j < 2; j++)
|
|
|
|
|
{
|
2014-02-04 21:15:33 +00:00
|
|
|
|
var c = char.ToLower(str[(i * 2) + j]);
|
2013-11-04 00:36:15 +00:00
|
|
|
|
if (c >= '0' && c <= '9')
|
2013-12-14 00:03:03 +00:00
|
|
|
|
{
|
|
|
|
|
d += c - '0';
|
|
|
|
|
}
|
2013-11-04 00:36:15 +00:00
|
|
|
|
else if (c >= 'a' && c <= 'f')
|
2013-12-14 00:03:03 +00:00
|
|
|
|
{
|
2013-11-04 00:36:15 +00:00
|
|
|
|
d += (c - 'a') + 10;
|
2013-12-14 00:03:03 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentException();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (j == 0)
|
|
|
|
|
{
|
|
|
|
|
d <<= 4;
|
|
|
|
|
}
|
2013-11-04 00:36:15 +00:00
|
|
|
|
}
|
2013-12-14 00:03:03 +00:00
|
|
|
|
|
2013-11-04 00:36:15 +00:00
|
|
|
|
ms.WriteByte((byte)d);
|
|
|
|
|
}
|
2014-02-04 21:15:33 +00:00
|
|
|
|
|
2013-11-04 00:36:15 +00:00
|
|
|
|
return ms.ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-14 00:03:03 +00:00
|
|
|
|
// Could be extension method
|
2013-11-04 00:36:15 +00:00
|
|
|
|
public static void WriteByteBuffer(BinaryWriter bw, byte[] data)
|
|
|
|
|
{
|
2013-12-14 00:03:03 +00:00
|
|
|
|
if (data == null)
|
|
|
|
|
{
|
|
|
|
|
bw.Write(0);
|
|
|
|
|
}
|
2013-11-04 00:36:15 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bw.Write(data.Length);
|
|
|
|
|
bw.Write(data);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-06 16:00:24 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
2017-04-13 18:57:58 +00:00
|
|
|
|
|
2014-10-06 16:00:24 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
2017-04-13 18:57:58 +00:00
|
|
|
|
|
2014-10-06 16:00:24 +00:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-04 00:36:15 +00:00
|
|
|
|
public static short[] ByteBufferToShortBuffer(byte[] buf)
|
|
|
|
|
{
|
|
|
|
|
int num = buf.Length / 2;
|
2013-12-14 00:03:03 +00:00
|
|
|
|
var ret = new short[num];
|
2013-11-04 00:36:15 +00:00
|
|
|
|
for (int i = 0; i < num; i++)
|
|
|
|
|
{
|
|
|
|
|
ret[i] = (short)(buf[i * 2] | (buf[i * 2 + 1] << 8));
|
|
|
|
|
}
|
2013-12-14 00:03:03 +00:00
|
|
|
|
|
2013-11-04 00:36:15 +00:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static byte[] ShortBufferToByteBuffer(short[] buf)
|
|
|
|
|
{
|
|
|
|
|
int num = buf.Length;
|
2013-12-14 00:03:03 +00:00
|
|
|
|
var ret = new byte[num * 2];
|
2013-11-04 00:36:15 +00:00
|
|
|
|
for (int i = 0; i < num; i++)
|
|
|
|
|
{
|
|
|
|
|
ret[i * 2 + 0] = (byte)(buf[i] & 0xFF);
|
|
|
|
|
ret[i * 2 + 1] = (byte)((buf[i] >> 8) & 0xFF);
|
|
|
|
|
}
|
2013-12-14 00:03:03 +00:00
|
|
|
|
|
2013-11-04 00:36:15 +00:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-07 04:50:19 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-04 00:36:15 +00:00
|
|
|
|
public static uint[] ByteBufferToUintBuffer(byte[] buf)
|
|
|
|
|
{
|
|
|
|
|
int num = buf.Length / 4;
|
2013-12-14 00:03:03 +00:00
|
|
|
|
var ret = new uint[num];
|
2013-11-04 00:36:15 +00:00
|
|
|
|
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));
|
|
|
|
|
}
|
2013-12-14 00:03:03 +00:00
|
|
|
|
|
2013-11-04 00:36:15 +00:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static byte[] UintBufferToByteBuffer(uint[] buf)
|
|
|
|
|
{
|
|
|
|
|
int num = buf.Length;
|
2013-12-14 00:03:03 +00:00
|
|
|
|
var ret = new byte[num * 4];
|
2013-11-04 00:36:15 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
2013-12-14 00:03:03 +00:00
|
|
|
|
|
2013-11-04 00:36:15 +00:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static int[] ByteBufferToIntBuffer(byte[] buf)
|
|
|
|
|
{
|
|
|
|
|
int num = buf.Length / 4;
|
2013-12-14 00:03:03 +00:00
|
|
|
|
var ret = new int[num];
|
2013-11-04 00:36:15 +00:00
|
|
|
|
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)];
|
|
|
|
|
}
|
2013-12-14 00:03:03 +00:00
|
|
|
|
|
2013-11-04 00:36:15 +00:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static byte[] IntBufferToByteBuffer(int[] buf)
|
|
|
|
|
{
|
|
|
|
|
int num = buf.Length;
|
2013-12-14 00:03:03 +00:00
|
|
|
|
var ret = new byte[num * 4];
|
2013-11-04 00:36:15 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
2013-12-14 00:03:03 +00:00
|
|
|
|
|
2013-11-04 00:36:15 +00:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-14 00:03:03 +00:00
|
|
|
|
public static byte[] ReadByteBuffer(BinaryReader br, bool returnNull)
|
2013-11-04 00:36:15 +00:00
|
|
|
|
{
|
|
|
|
|
int len = br.ReadInt32();
|
2013-12-14 00:03:03 +00:00
|
|
|
|
if (len == 0 && returnNull)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var ret = new byte[len];
|
2013-11-04 00:36:15 +00:00
|
|
|
|
int ofs = 0;
|
|
|
|
|
while (len > 0)
|
|
|
|
|
{
|
|
|
|
|
int done = br.Read(ret, ofs, len);
|
|
|
|
|
ofs += done;
|
|
|
|
|
len -= done;
|
|
|
|
|
}
|
2013-12-14 00:03:03 +00:00
|
|
|
|
|
2013-11-04 00:36:15 +00:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-14 00:03:03 +00:00
|
|
|
|
public static int Memcmp(void* a, string b, int len)
|
2013-11-04 00:36:15 +00:00
|
|
|
|
{
|
2013-11-04 03:12:50 +00:00
|
|
|
|
fixed (byte* bp = Encoding.ASCII.GetBytes(b))
|
2013-12-14 00:03:03 +00:00
|
|
|
|
return Memcmp(a, bp, len);
|
2013-11-04 00:36:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-14 00:03:03 +00:00
|
|
|
|
public static int Memcmp(void* a, void* b, int len)
|
2013-11-04 00:36:15 +00:00
|
|
|
|
{
|
2013-12-14 00:03:03 +00:00
|
|
|
|
var ba = (byte*)a;
|
|
|
|
|
var bb = (byte*)b;
|
2013-11-04 00:36:15 +00:00
|
|
|
|
for (int i = 0; i < len; i++)
|
|
|
|
|
{
|
|
|
|
|
byte _a = ba[i];
|
|
|
|
|
byte _b = bb[i];
|
|
|
|
|
int c = _a - _b;
|
2013-12-14 00:03:03 +00:00
|
|
|
|
if (c != 0)
|
|
|
|
|
{
|
|
|
|
|
return c;
|
|
|
|
|
}
|
2013-11-04 00:36:15 +00:00
|
|
|
|
}
|
2013-12-14 00:03:03 +00:00
|
|
|
|
|
2013-11-04 00:36:15 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-14 00:03:03 +00:00
|
|
|
|
public static void Memset(void* ptr, int val, int len)
|
2013-11-04 00:36:15 +00:00
|
|
|
|
{
|
2013-12-14 00:03:03 +00:00
|
|
|
|
var bptr = (byte*)ptr;
|
2013-11-04 00:36:15 +00:00
|
|
|
|
for (int i = 0; i < len; i++)
|
2013-12-14 00:03:03 +00:00
|
|
|
|
{
|
2013-11-04 00:36:15 +00:00
|
|
|
|
bptr[i] = (byte)val;
|
2013-12-14 00:03:03 +00:00
|
|
|
|
}
|
2013-11-04 00:36:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-14 00:03:03 +00:00
|
|
|
|
public static void Memset32(void* ptr, int val, int len)
|
2013-11-04 00:36:15 +00:00
|
|
|
|
{
|
|
|
|
|
System.Diagnostics.Debug.Assert(len % 4 == 0);
|
|
|
|
|
int dwords = len / 4;
|
|
|
|
|
int* dwptr = (int*)ptr;
|
|
|
|
|
for (int i = 0; i < dwords; i++)
|
2013-12-14 00:03:03 +00:00
|
|
|
|
{
|
2013-11-04 00:36:15 +00:00
|
|
|
|
dwptr[i] = val;
|
2013-12-14 00:03:03 +00:00
|
|
|
|
}
|
2013-11-04 00:36:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static string FormatFileSize(long filesize)
|
|
|
|
|
{
|
2014-02-04 21:15:33 +00:00
|
|
|
|
decimal size = filesize;
|
2013-11-04 00:36:15 +00:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
{
|
2014-04-08 02:25:46 +00:00
|
|
|
|
suffix = "B";
|
2013-11-04 00:36:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-04 21:15:33 +00:00
|
|
|
|
const string precision = "2";
|
|
|
|
|
return string.Format("{0:N" + precision + "}{1}", size, suffix);
|
2013-11-04 00:36:15 +00:00
|
|
|
|
}
|
2014-01-01 03:03:10 +00:00
|
|
|
|
|
|
|
|
|
// http://stackoverflow.com/questions/3928822/comparing-2-dictionarystring-string-instances
|
|
|
|
|
public static bool DictionaryEqual<TKey, TValue>(
|
|
|
|
|
IDictionary<TKey, TValue> first, IDictionary<TKey, TValue> second)
|
|
|
|
|
{
|
2014-02-04 21:15:33 +00:00
|
|
|
|
if (first == second)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((first == null) || (second == null))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (first.Count != second.Count)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-01-01 03:03:10 +00:00
|
|
|
|
|
|
|
|
|
var comparer = EqualityComparer<TValue>.Default;
|
|
|
|
|
|
2014-02-04 21:15:33 +00:00
|
|
|
|
foreach (var kvp in first)
|
2014-01-01 03:03:10 +00:00
|
|
|
|
{
|
|
|
|
|
TValue secondValue;
|
2014-02-04 21:15:33 +00:00
|
|
|
|
if (!second.TryGetValue(kvp.Key, out secondValue))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!comparer.Equals(kvp.Value, secondValue))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-01-01 03:03:10 +00:00
|
|
|
|
}
|
2014-02-04 21:15:33 +00:00
|
|
|
|
|
2014-01-01 03:03:10 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
2017-07-01 13:06:04 +00:00
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
2013-11-04 00:36:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-01-17 06:19:13 +00:00
|
|
|
|
public static class BitConverterLE
|
|
|
|
|
{
|
2015-01-17 19:16:22 +00:00
|
|
|
|
public static void WriteBytes(ushort value, byte[] dst, int index)
|
2015-01-17 06:19:13 +00:00
|
|
|
|
{
|
2015-01-17 19:16:22 +00:00
|
|
|
|
dst[index ] = (byte)(value );
|
|
|
|
|
dst[index + 1] = (byte)(value >> 8);
|
2015-01-17 06:19:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-01-17 19:16:22 +00:00
|
|
|
|
public static void WriteBytes(uint value, byte[] dst, int index)
|
2015-01-17 06:19:13 +00:00
|
|
|
|
{
|
2015-01-17 19:16:22 +00:00
|
|
|
|
dst[index ] = (byte)(value );
|
|
|
|
|
dst[index + 1] = (byte)(value >> 8);
|
|
|
|
|
dst[index + 2] = (byte)(value >> 16);
|
|
|
|
|
dst[index + 3] = (byte)(value >> 24);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
2015-01-17 06:19:13 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-15 00:22:08 +00:00
|
|
|
|
[Serializable]
|
|
|
|
|
public class NotTestedException : Exception
|
|
|
|
|
{
|
|
|
|
|
}
|
2013-11-22 09:33:56 +00:00
|
|
|
|
|
2013-12-14 00:03:03 +00:00
|
|
|
|
internal class SuperGloballyUniqueID
|
2013-11-22 09:33:56 +00:00
|
|
|
|
{
|
2014-02-04 21:15:33 +00:00
|
|
|
|
private static readonly string StaticPart;
|
|
|
|
|
private static int ctr;
|
|
|
|
|
|
|
|
|
|
static SuperGloballyUniqueID()
|
|
|
|
|
{
|
|
|
|
|
StaticPart = "bizhawk-" + System.Diagnostics.Process.GetCurrentProcess().Id + "-" + Guid.NewGuid();
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-22 09:33:56 +00:00
|
|
|
|
public static string Next()
|
|
|
|
|
{
|
|
|
|
|
int myctr;
|
|
|
|
|
lock (typeof(SuperGloballyUniqueID))
|
2013-12-14 00:03:03 +00:00
|
|
|
|
{
|
2013-11-22 09:33:56 +00:00
|
|
|
|
myctr = ctr++;
|
2013-12-14 00:03:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return StaticPart + "-" + myctr;
|
2013-11-22 09:33:56 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-04-12 17:37:06 +00:00
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-11-04 00:36:15 +00:00
|
|
|
|
}
|