BizHawk/BizHawk.Common/Extensions/BufferExtensions.cs

136 lines
3.3 KiB
C#

using System;
using System.Globalization;
using System.IO;
using System.Text;
using System.Security.Cryptography;
namespace BizHawk.Common.BufferExtensions
{
public static class BufferExtensions
{
private static readonly char[] HexConvArr = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
public static unsafe void SaveAsHexFast(this byte[] buffer, TextWriter writer)
{
fixed (char* table = HexConvArr)
{
if (buffer.Length > 0)
{
int len = buffer.Length;
fixed (byte* src = buffer)
for (int i = 0; i < len; i++)
{
writer.Write(table[src[i] >> 4]);
writer.Write(table[src[i] & 15]);
}
}
}
writer.WriteLine();
}
/// <exception cref="Exception"><paramref name="hex"/> has an odd number of chars</exception>
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++)
{
var bytehex = hex[i * 2].ToString() + hex[(i * 2) + 1];
buffer[i] = byte.Parse(bytehex, NumberStyles.HexNumber);
}
}
/// <exception cref="Exception"><paramref name="buffer"/> can't hold the same number of bytes as <paramref name="hex"/></exception>
public static unsafe void ReadFromHexFast(this byte[] buffer, string hex)
{
if (buffer.Length * 2 != hex.Length)
{
throw new Exception("Data size mismatch");
}
int count = buffer.Length;
fixed (byte* _dst = buffer)
fixed (char* _src = hex)
{
byte* dst = _dst;
char* src = _src;
while (count > 0)
{
// in my tests, replacing Hex2Int() with a 256 entry LUT slowed things down slightly
*dst++ = (byte)(Hex2Int(*src++) << 4 | Hex2Int(*src++));
count--;
}
}
}
/// <summary>
/// Converts bytes to an uppercase string of hex numbers in upper case without any spacing or anything
/// </summary>
public static string BytesToHexString(this byte[] bytes)
{
var sb = new StringBuilder();
foreach (var b in bytes)
{
sb.AppendFormat("{0:X2}", b);
}
return sb.ToString();
}
public static bool FindBytes(this byte[] array, byte[] pattern)
{
var fidx = 0;
int result = Array.FindIndex(array, 0, array.Length, (byte b) =>
{
fidx = (b == pattern[fidx]) ? fidx + 1 : 0;
return fidx == pattern.Length;
});
return result >= pattern.Length - 1;
}
public static string HashMD5(this byte[] data, int offset, int len)
{
using var md5 = MD5.Create();
md5.ComputeHash(data, offset, len);
return md5.Hash.BytesToHexString();
}
public static string HashMD5(this byte[] data)
{
return HashMD5(data, 0, data.Length);
}
public static string HashSHA1(this byte[] data, int offset, int len)
{
using var sha1 = SHA1.Create();
sha1.ComputeHash(data, offset, len);
return sha1.Hash.BytesToHexString();
}
public static string HashSHA1(this byte[] data)
{
return HashSHA1(data, 0, data.Length);
}
private static int Hex2Int(char c)
{
if (c <= '9')
{
return c - '0';
}
if (c <= 'F')
{
return c - '7';
}
return c - 'W';
}
}
}