405 lines
9.5 KiB
C#
405 lines
9.5 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Text;
|
|
|
|
namespace BizHawk.Common
|
|
{
|
|
public static class Extensions
|
|
{
|
|
public static string GetDirectory(this Assembly asm)
|
|
{
|
|
string codeBase = asm.CodeBase;
|
|
UriBuilder uri = new UriBuilder(codeBase);
|
|
string path = Uri.UnescapeDataString(uri.Path);
|
|
return Path.GetDirectoryName(path);
|
|
}
|
|
|
|
public static int LowerBoundBinarySearch<T, TKey>(this IList<T> list, Func<T, TKey> keySelector, TKey key) where TKey : IComparable<TKey>
|
|
{
|
|
int min = 0;
|
|
int max = list.Count;
|
|
int mid;
|
|
TKey midKey;
|
|
while (min < max)
|
|
{
|
|
mid = (max + min) / 2;
|
|
T midItem = list[mid];
|
|
midKey = keySelector(midItem);
|
|
int comp = midKey.CompareTo(key);
|
|
if (comp < 0)
|
|
{
|
|
min = mid + 1;
|
|
}
|
|
else if (comp > 0)
|
|
{
|
|
max = mid - 1;
|
|
}
|
|
else
|
|
{
|
|
return mid;
|
|
}
|
|
}
|
|
|
|
//did we find it exactly?
|
|
if (min == max && keySelector(list[min]).CompareTo(key) == 0)
|
|
{
|
|
return min;
|
|
}
|
|
|
|
mid = min;
|
|
|
|
//we didnt find it. return something corresponding to lower_bound semantics
|
|
|
|
if (mid == list.Count)
|
|
return max; //had to go all the way to max before giving up; lower bound is max
|
|
if (mid == 0)
|
|
return -1; //had to go all the way to min before giving up; lower bound is min
|
|
|
|
midKey = keySelector(list[mid]);
|
|
if (midKey.CompareTo(key) >= 0) return mid - 1;
|
|
else return mid;
|
|
}
|
|
|
|
public static string ToHexString(this int n, int numdigits)
|
|
{
|
|
return String.Format("{0:X" + numdigits + "}", n);
|
|
}
|
|
|
|
public static string ToHexString(this uint n, int numdigits)
|
|
{
|
|
return String.Format("{0:X" + numdigits + "}", n);
|
|
}
|
|
|
|
public static string ToHexString(this byte n, int numdigits)
|
|
{
|
|
return String.Format("{0:X" + numdigits + "}", n);
|
|
}
|
|
|
|
public static string ToHexString(this ushort n, int numdigits)
|
|
{
|
|
return String.Format("{0:X" + numdigits + "}", n);
|
|
}
|
|
|
|
// http://stackoverflow.com/questions/1766328/can-linq-use-binary-search-when-the-collection-is-ordered
|
|
public static T BinarySearch<T, TKey>(this IList<T> list, Func<T, TKey> keySelector, TKey key)
|
|
where TKey : IComparable<TKey>
|
|
{
|
|
int min = 0;
|
|
int max = list.Count;
|
|
while (min < max)
|
|
{
|
|
int mid = (max + min) / 2;
|
|
T midItem = list[mid];
|
|
TKey midKey = keySelector(midItem);
|
|
int comp = midKey.CompareTo(key);
|
|
if (comp < 0)
|
|
{
|
|
min = mid + 1;
|
|
}
|
|
else if (comp > 0)
|
|
{
|
|
max = mid - 1;
|
|
}
|
|
else
|
|
{
|
|
return midItem;
|
|
}
|
|
}
|
|
if (min == max &&
|
|
keySelector(list[min]).CompareTo(key) == 0)
|
|
{
|
|
return list[min];
|
|
}
|
|
|
|
throw new InvalidOperationException("Item not found");
|
|
}
|
|
|
|
public static void CopyTo(this Stream src, Stream dest)
|
|
{
|
|
int size = (src.CanSeek) ? Math.Min((int)(src.Length - src.Position), 0x2000) : 0x2000;
|
|
byte[] buffer = new byte[size];
|
|
int n;
|
|
do
|
|
{
|
|
n = src.Read(buffer, 0, buffer.Length);
|
|
dest.Write(buffer, 0, n);
|
|
} while (n != 0);
|
|
}
|
|
|
|
public static void CopyTo(this MemoryStream src, Stream dest)
|
|
{
|
|
dest.Write(src.GetBuffer(), (int)src.Position, (int)(src.Length - src.Position));
|
|
}
|
|
|
|
public static void CopyTo(this Stream src, MemoryStream dest)
|
|
{
|
|
if (src.CanSeek)
|
|
{
|
|
int pos = (int)dest.Position;
|
|
int length = (int)(src.Length - src.Position) + pos;
|
|
dest.SetLength(length);
|
|
|
|
while (pos < length)
|
|
pos += src.Read(dest.GetBuffer(), pos, length - pos);
|
|
}
|
|
else
|
|
src.CopyTo(dest);
|
|
}
|
|
|
|
public static bool Bit(this byte b, int index)
|
|
{
|
|
return (b & (1 << index)) != 0;
|
|
}
|
|
|
|
public static bool Bit(this int b, int index)
|
|
{
|
|
return (b & (1 << index)) != 0;
|
|
}
|
|
|
|
public static bool Bit(this ushort b, int index)
|
|
{
|
|
return (b & (1 << index)) != 0;
|
|
}
|
|
|
|
public static bool In(this int i, params int[] options)
|
|
{
|
|
return options.Any(j => i == j);
|
|
}
|
|
|
|
public static bool ContainsStartsWith(this IEnumerable<string> options, string str)
|
|
{
|
|
return options.Any(opt => opt.StartsWith(str));
|
|
}
|
|
|
|
public static string GetOptionValue(this IEnumerable<string> options, string str)
|
|
{
|
|
try
|
|
{
|
|
foreach (string opt in options)
|
|
{
|
|
if (opt.StartsWith(str))
|
|
{
|
|
return opt.Split('=')[1];
|
|
}
|
|
}
|
|
}
|
|
catch (Exception) { }
|
|
return null;
|
|
}
|
|
|
|
public static void SaveAsHex(this byte[] buffer, TextWriter writer)
|
|
{
|
|
foreach (byte b in buffer)
|
|
{
|
|
writer.Write("{0:X2}", b);
|
|
}
|
|
writer.WriteLine();
|
|
}
|
|
|
|
public unsafe static void SaveAsHexFast(this byte[] buffer, TextWriter writer)
|
|
{
|
|
char* table = Util.HexConvPtr;
|
|
if (buffer.Length > 0)
|
|
{
|
|
int len = buffer.Length;
|
|
fixed (byte* src = &buffer[0])
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
writer.Write(table[src[i] >> 4]);
|
|
writer.Write(table[src[i] & 15]);
|
|
}
|
|
}
|
|
writer.WriteLine();
|
|
}
|
|
|
|
public static void SaveAsHex(this byte[] buffer, TextWriter writer, int length)
|
|
{
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
writer.Write("{0:X2}", buffer[i]);
|
|
}
|
|
writer.WriteLine();
|
|
}
|
|
|
|
public static void SaveAsHex(this short[] buffer, TextWriter writer)
|
|
{
|
|
foreach (short b in buffer)
|
|
{
|
|
writer.Write("{0:X4}", b);
|
|
}
|
|
writer.WriteLine();
|
|
}
|
|
|
|
public static void SaveAsHex(this ushort[] buffer, TextWriter writer)
|
|
{
|
|
foreach (ushort b in buffer)
|
|
{
|
|
writer.Write("{0:X4}", b);
|
|
}
|
|
writer.WriteLine();
|
|
}
|
|
|
|
public static void SaveAsHex(this int[] buffer, TextWriter writer)
|
|
{
|
|
foreach (int b in buffer)
|
|
{
|
|
writer.Write("{0:X8}", b);
|
|
}
|
|
writer.WriteLine();
|
|
}
|
|
|
|
public static void SaveAsHex(this uint[] buffer, TextWriter writer)
|
|
{
|
|
foreach (uint b in buffer)
|
|
{
|
|
writer.Write("{0:X8}", b);
|
|
}
|
|
writer.WriteLine();
|
|
}
|
|
|
|
public static void Write(this BinaryWriter bw, int[] buffer)
|
|
{
|
|
foreach (int b in buffer)
|
|
{
|
|
bw.Write(b);
|
|
}
|
|
}
|
|
|
|
public static void Write(this BinaryWriter bw, uint[] buffer)
|
|
{
|
|
foreach (uint b in buffer)
|
|
{
|
|
bw.Write(b);
|
|
}
|
|
}
|
|
|
|
public static void Write(this BinaryWriter bw, short[] buffer)
|
|
{
|
|
foreach (short b in buffer)
|
|
{
|
|
bw.Write(b);
|
|
}
|
|
}
|
|
|
|
public static void Write(this BinaryWriter bw, ushort[] buffer)
|
|
{
|
|
foreach (ushort t in buffer)
|
|
{
|
|
bw.Write(t);
|
|
}
|
|
}
|
|
|
|
public static int[] ReadInt32s(this BinaryReader br, int num)
|
|
{
|
|
int[] ret = new int[num];
|
|
for (int i = 0; i < num; i++)
|
|
{
|
|
ret[i] = br.ReadInt32();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
public static short[] ReadInt16s(this BinaryReader br, int num)
|
|
{
|
|
short[] ret = new short[num];
|
|
for (int i = 0; i < num; i++)
|
|
{
|
|
ret[i] = br.ReadInt16();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
public static ushort[] ReadUInt16s(this BinaryReader br, int num)
|
|
{
|
|
ushort[] ret = new ushort[num];
|
|
for (int i = 0; i < num; i++)
|
|
{
|
|
ret[i] = br.ReadUInt16();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
public static void ReadFromHex(this byte[] buffer, string hex)
|
|
{
|
|
if (hex.Length%2 != 0)
|
|
{
|
|
throw new Exception("Hex value string does not appear to be properly formatted.");
|
|
}
|
|
|
|
for (int i = 0; i < buffer.Length && i * 2 < hex.Length; i++)
|
|
{
|
|
string bytehex = "" + hex[i * 2] + hex[i * 2 + 1];
|
|
buffer[i] = byte.Parse(bytehex, NumberStyles.HexNumber);
|
|
}
|
|
}
|
|
|
|
private static int Hex2Int(char c)
|
|
{
|
|
if (c <= '9')
|
|
{
|
|
return c - '0';
|
|
}
|
|
else if (c <= 'F')
|
|
{
|
|
return c - '7';
|
|
}
|
|
else
|
|
{
|
|
return c - 'W';
|
|
}
|
|
}
|
|
|
|
public static void ReadFromHexFast(this byte[] buffer, string hex)
|
|
{
|
|
for (int i = 0; i < buffer.Length && i * 2 < hex.Length; i++)
|
|
{
|
|
buffer[i] = (byte)(Hex2Int(hex[i * 2]) * 16 + Hex2Int(hex[i * 2 + 1]));
|
|
}
|
|
}
|
|
|
|
public static void ReadFromHex(this short[] buffer, string hex)
|
|
{
|
|
if (hex.Length % 4 != 0)
|
|
throw new Exception("Hex value string does not appear to be properly formatted.");
|
|
for (int i = 0; i < buffer.Length && i * 4 < hex.Length; i++)
|
|
{
|
|
string shorthex = "" + hex[i * 4] + hex[(i * 4) + 1] + hex[(i * 4) + 2] + hex[(i * 4) + 3];
|
|
buffer[i] = short.Parse(shorthex, NumberStyles.HexNumber);
|
|
}
|
|
}
|
|
|
|
public static void ReadFromHex(this ushort[] buffer, string hex)
|
|
{
|
|
if (hex.Length % 4 != 0)
|
|
throw new Exception("Hex value string does not appear to be properly formatted.");
|
|
for (int i = 0; i < buffer.Length && i * 4 < hex.Length; i++)
|
|
{
|
|
string ushorthex = "" + hex[i * 4] + hex[(i * 4) + 1] + hex[(i * 4) + 2] + hex[(i * 4) + 3];
|
|
buffer[i] = ushort.Parse(ushorthex, NumberStyles.HexNumber);
|
|
}
|
|
}
|
|
|
|
public static void ReadFromHex(this int[] buffer, string hex)
|
|
{
|
|
if (hex.Length % 8 != 0)
|
|
{
|
|
throw new Exception("Hex value string does not appear to be properly formatted.");
|
|
}
|
|
|
|
for (int i = 0; i < buffer.Length && i * 8 < hex.Length; i++)
|
|
{
|
|
//string inthex = "" + hex[i * 8] + hex[(i * 8) + 1] + hex[(i * 4) + 2] + hex[(i * 4) + 3] + hex[(i*4
|
|
string inthex = hex.Substring(i * 8, 8);
|
|
buffer[i] = int.Parse(inthex, NumberStyles.HexNumber);
|
|
}
|
|
}
|
|
|
|
//these don't work??? they dont get chosen by compiler
|
|
public static void WriteBit(this BinaryWriter bw, Bit bit) { bw.Write((bool)bit); }
|
|
public static Bit ReadBit(this BinaryReader br) { return br.ReadBoolean(); }
|
|
}
|
|
} |