Extract byte swapping helpers from RomGame, cleanup, and add tests
This commit is contained in:
parent
214f024d86
commit
1f080be047
|
@ -86,7 +86,13 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (file.Extension == ".z64" || file.Extension == ".n64" || file.Extension == ".v64")
|
||||
{
|
||||
RomData = MutateSwapN64(RomData);
|
||||
// Use a simple magic number to detect N64 rom format, then byteswap the ROM to ensure a consistent endianness/order
|
||||
RomData = RomData[0] switch
|
||||
{
|
||||
0x37 => EndiannessUtils.ByteSwap16(RomData), // V64 format (byte swapped)
|
||||
0x40 => EndiannessUtils.ByteSwap32(RomData), // N64 format (word swapped)
|
||||
_ => RomData // Z64 format (no swap), or something unexpected; in either case do nothing
|
||||
};
|
||||
}
|
||||
|
||||
// note: this will be taking several hashes, of a potentially large amount of data.. yikes!
|
||||
|
@ -137,55 +143,6 @@ namespace BizHawk.Client.Common
|
|||
return output;
|
||||
}
|
||||
|
||||
private static unsafe byte[] MutateSwapN64(byte[] source)
|
||||
{
|
||||
// N64 roms are in one of the following formats:
|
||||
// .Z64 = No swapping
|
||||
// .N64 = Word Swapped
|
||||
// .V64 = Byte Swapped
|
||||
|
||||
// File extension does not always match the format
|
||||
int size = source.Length;
|
||||
|
||||
// V64 format
|
||||
fixed (byte* pSource = &source[0])
|
||||
{
|
||||
if (pSource[0] == 0x37)
|
||||
{
|
||||
for (int i = 0; i < size; i += 2)
|
||||
{
|
||||
byte temp = pSource[i];
|
||||
pSource[i] = pSource[i + 1];
|
||||
pSource[i + 1] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
// N64 format
|
||||
else if (pSource[0] == 0x40)
|
||||
{
|
||||
for (int i = 0; i < size; i += 4)
|
||||
{
|
||||
// output[i] = source[i + 3];
|
||||
// output[i + 3] = source[i];
|
||||
// output[i + 1] = source[i + 2];
|
||||
// output[i + 2] = source[i + 1];
|
||||
byte temp = pSource[i];
|
||||
pSource[i] = pSource[i + 3];
|
||||
pSource[i + 3] = temp;
|
||||
|
||||
temp = pSource[i + 1];
|
||||
pSource[i + 1] = pSource[i + 2];
|
||||
pSource[i + 2] = temp;
|
||||
}
|
||||
}
|
||||
else // Z64 format (or some other unknown format)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
private void CheckForPatchOptions()
|
||||
{
|
||||
try
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace BizHawk.Common
|
||||
{
|
||||
public static unsafe class EndiannessUtils
|
||||
{
|
||||
/// <summary>reverses pairs of octets: <c>0xAABBIIJJPPQQYYZZ</c> <=> <c>0xBBAAJJIIQQPPZZYY</c></summary>
|
||||
public static byte[] ByteSwap16(byte[] a)
|
||||
{
|
||||
var l = a.Length;
|
||||
var copy = new byte[l];
|
||||
Array.Copy(a, copy, l);
|
||||
MutatingByteSwap16(copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/// <summary>reverses groups of 4 octets: <c>0xAABBCCDDWWXXYYZZ</c> <=> <c>0xDDCCBBAAZZYYXXWW</c></summary>
|
||||
public static byte[] ByteSwap32(byte[] a)
|
||||
{
|
||||
var l = a.Length;
|
||||
var copy = new byte[l];
|
||||
Array.Copy(a, copy, l);
|
||||
MutatingByteSwap32(copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/// <summary>reverses pairs of octets in-place: <c>0xAABBIIJJPPQQYYZZ</c> <=> <c>0xBBAAJJIIQQPPZZYY</c></summary>
|
||||
public static void MutatingByteSwap16(byte[] a)
|
||||
{
|
||||
var l = a.Length;
|
||||
Debug.Assert(l % 2 == 0);
|
||||
fixed (byte* p = &a[0]) for (var i = 0; i < l; i += 2)
|
||||
{
|
||||
var b = p[i];
|
||||
p[i] = p[i + 1];
|
||||
p[i + 1] = b;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>reverses groups of 4 octets in-place: <c>0xAABBCCDDWWXXYYZZ</c> <=> <c>0xDDCCBBAAZZYYXXWW</c></summary>
|
||||
public static void MutatingByteSwap32(byte[] a)
|
||||
{
|
||||
var l = a.Length;
|
||||
Debug.Assert(l % 4 == 0);
|
||||
fixed (byte* p = &a[0]) for (var i = 0; i < l; i += 4)
|
||||
{
|
||||
var b = p[i];
|
||||
p[i] = p[i + 3];
|
||||
p[i + 3] = b;
|
||||
b = p[i + 1];
|
||||
p[i + 1] = p[i + 2];
|
||||
p[i + 2] = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
using System.Linq;
|
||||
|
||||
using BizHawk.Common;
|
||||
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace BizHawk.Tests.Common
|
||||
{
|
||||
[TestClass]
|
||||
public sealed class EndiannessUtilsTests
|
||||
{
|
||||
private static readonly byte[] expected = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };
|
||||
|
||||
[TestMethod]
|
||||
public void TestByteSwap16()
|
||||
{
|
||||
var a = new byte[] { 0x23, 0x01, 0x67, 0x45, 0xAB, 0x89, 0xEF, 0xCD };
|
||||
EndiannessUtils.MutatingByteSwap16(a);
|
||||
Assert.IsTrue(a.SequenceEqual(expected));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestByteSwap32()
|
||||
{
|
||||
var a = new byte[] { 0x67, 0x45, 0x23, 0x01, 0xEF, 0xCD, 0xAB, 0x89 };
|
||||
EndiannessUtils.MutatingByteSwap32(a);
|
||||
Assert.IsTrue(a.SequenceEqual(expected));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue