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(this IList list, Func keySelector, TKey key) where TKey : IComparable { 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(this IList list, Func keySelector, TKey key) where TKey : IComparable { 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 options, string str) { return options.Any(opt => opt.StartsWith(str)); } public static string GetOptionValue(this IEnumerable 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(); } } }