Skip to content

Commit abeaa2a

Browse files
committed
Be less lazy about N64 header detection in byteswapper
fixes 82c3b47, 9660c16
1 parent 9660c16 commit abeaa2a

File tree

4 files changed

+57
-37
lines changed

4 files changed

+57
-37
lines changed

src/BizHawk.Client.Common/RomGame.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public RomGame(HawkFile file, string patch)
9696
RomData = DeInterleaveSMD(RomData);
9797
}
9898

99-
if (file.Extension is ".n64" or ".v64" or ".z64") N64RomByteswapper.ToZ64Native(RomData); //TODO don't use file extension for N64 rom detection (yes that means detecting all formats before converting to Z64)
99+
if (file.Extension is ".n64" or ".v64" or ".z64") _ = N64RomByteswapper.ToZ64Native(RomData); //TODO don't use file extension for N64 rom detection (yes that means detecting all formats before converting to Z64)
100100

101101
// note: this will be taking several hashes, of a potentially large amount of data.. yikes!
102102
GameInfo = Database.GetGameInfo(RomData, file.Name);

src/BizHawk.Client.EmuHawk/debug/N64RomByteswapToolForm.cs

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,19 +51,12 @@ void DoConvert()
5151
try
5252
{
5353
var rom = File.ReadAllBytes(txtBaseFile.Text);
54-
switch (comboFormats.SelectedIndex) // can't have Action<Span<byte>> (System.Buffers.SpanAction isn't suitable) or I'd be able to have a tiny switch expr >:( --yoshi
54+
_ = comboFormats.SelectedIndex switch
5555
{
56-
case 0:
57-
N64RomByteswapper.ToN64LittleEndian(rom);
58-
break;
59-
case 1:
60-
N64RomByteswapper.ToV64ByteSwapped(rom);
61-
break;
62-
case 2:
63-
default:
64-
N64RomByteswapper.ToZ64Native(rom);
65-
break;
66-
}
56+
0 => N64RomByteswapper.ToN64LittleEndian(rom),
57+
1 => N64RomByteswapper.ToV64ByteSwapped(rom),
58+
_ => N64RomByteswapper.ToZ64Native(rom)
59+
};
6760
File.WriteAllBytes(txtTargetFile.Text, rom);
6861
this.ModalMessageBox($"wrote {txtTargetFile.Text}\n{SHA1Checksum.ComputePrefixedHex(rom)}");
6962
}
Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Runtime.InteropServices;
23

34
using BizHawk.Common;
45

@@ -8,31 +9,67 @@ namespace BizHawk.Emulation.Common
89
/// <remarks>http://n64dev.org/romformats.html</remarks>
910
public static class N64RomByteswapper
1011
{
12+
private static readonly byte[] MAGIC_BYTES_LE = { 0x37, 0x80, 0x40, 0x12 };
13+
1114
/// <remarks>not actually magic, just always the same in commercial carts? https://n64brew.dev/wiki/ROM_Header works all the same</remarks>
12-
private static readonly byte[] MAGIC_BYTES = { 0x80, 0x37, 0x12, 0x40 };
15+
private static readonly byte[] MAGIC_BYTES_NATIVE = { 0x80, 0x37, 0x12, 0x40 };
16+
17+
private static readonly byte[] MAGIC_BYTES_SWAPPED = { 0x40, 0x12, 0x37, 0x80 };
1318

1419
/// <summary>ensures <paramref name="rom"/> is in the rare little-endian (<c>.n64</c>) format, mutating it in-place if necessary</summary>
15-
public static void ToN64LittleEndian(Span<byte> rom)
20+
/// <returns><see langword="true"/> iff <paramref name="rom"/> was one of the 3 valid formats</returns>
21+
public static bool ToN64LittleEndian(Span<byte> rom)
1622
{
17-
if (rom[0] == MAGIC_BYTES[0]) EndiannessUtils.MutatingByteSwap32(rom); // native (.z64)
18-
else if (rom[0] == MAGIC_BYTES[1]) EndiannessUtils.MutatingShortSwap32(rom); // byte-swapped (.v64)
19-
// else already rare little-endian .n64
23+
var romMagicBytes = rom.Slice(start: 0, length: 4);
24+
if (romMagicBytes.SequenceEqual(MAGIC_BYTES_NATIVE))
25+
{
26+
EndiannessUtils.MutatingByteSwap32(rom);
27+
return true;
28+
}
29+
if (romMagicBytes.SequenceEqual(MAGIC_BYTES_SWAPPED))
30+
{
31+
EndiannessUtils.MutatingShortSwap32(rom);
32+
return true;
33+
}
34+
return romMagicBytes.SequenceEqual(MAGIC_BYTES_LE);
2035
}
2136

2237
/// <summary>ensures <paramref name="rom"/> is in the byte-swapped (<c>.v64</c>) format, mutating it in-place if necessary</summary>
23-
public static void ToV64ByteSwapped(Span<byte> rom)
38+
/// <returns><see langword="true"/> iff <paramref name="rom"/> was one of the 3 valid formats</returns>
39+
public static bool ToV64ByteSwapped(Span<byte> rom)
2440
{
25-
if (rom[0] == MAGIC_BYTES[0]) EndiannessUtils.MutatingByteSwap16(rom); // native (.z64)
26-
else if (rom[0] == MAGIC_BYTES[3]) EndiannessUtils.MutatingShortSwap32(rom); // rare little-endian .n64
27-
// else already byte-swapped (.v64)
41+
var romMagicBytes = rom.Slice(start: 0, length: 4);
42+
if (romMagicBytes.SequenceEqual(MAGIC_BYTES_NATIVE))
43+
{
44+
EndiannessUtils.MutatingByteSwap16(rom);
45+
return true;
46+
}
47+
if (romMagicBytes.SequenceEqual(MAGIC_BYTES_SWAPPED)) return true;
48+
if (romMagicBytes.SequenceEqual(MAGIC_BYTES_LE))
49+
{
50+
EndiannessUtils.MutatingShortSwap32(rom);
51+
return true;
52+
}
53+
return false;
2854
}
2955

3056
/// <summary>ensures <paramref name="rom"/> is in the native (<c>.z64</c>) format, mutating it in-place if necessary</summary>
31-
public static void ToZ64Native(Span<byte> rom)
57+
/// <returns><see langword="true"/> iff <paramref name="rom"/> was one of the 3 valid formats</returns>
58+
public static bool ToZ64Native(Span<byte> rom)
3259
{
33-
if (rom[0] == MAGIC_BYTES[1]) EndiannessUtils.MutatingByteSwap16(rom); // byte-swapped (.v64)
34-
else if (rom[0] == MAGIC_BYTES[3]) EndiannessUtils.MutatingByteSwap32(rom); // rare little-endian .n64
35-
// else already native (.z64)
60+
var romMagicBytes = rom.Slice(start: 0, length: 4);
61+
if (romMagicBytes.SequenceEqual(MAGIC_BYTES_NATIVE)) return true;
62+
if (romMagicBytes.SequenceEqual(MAGIC_BYTES_SWAPPED))
63+
{
64+
EndiannessUtils.MutatingByteSwap16(rom);
65+
return true;
66+
}
67+
if (romMagicBytes.SequenceEqual(MAGIC_BYTES_LE))
68+
{
69+
EndiannessUtils.MutatingByteSwap32(rom);
70+
return true;
71+
}
72+
return false;
3673
}
3774
}
3875
}

src/BizHawk.Emulation.Cores/Consoles/Nintendo/Ares64/Ares64.cs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,7 @@ static bool IsGBRom(byte[] rom)
6969
// TODO: this is normally handled frontend side
7070
// except XML files don't go through RomGame
7171
// (probably should, but needs refactoring)
72-
foreach (var d in lp.Roms.Select(static r => r.RomData))
73-
{
74-
// magic N64 rom bytes are 0x80, 0x37, 0x12, 0x40
75-
// this should hopefully only ever detect N64 roms and not other kinds of files sent through here...
76-
if ((d[1] is 0x80 && d[0] is 0x37 && d[3] is 0x12 && d[2] is 0x40) // .v64 byteswapped
77-
|| (d[3] is 0x80 && d[2] is 0x37 && d[1] is 0x12 && d[0] is 0x40) // .n64 little-endian
78-
|| (d[0] is 0x80 && d[1] is 0x37 && d[2] is 0x12 && d[3] is 0x40)) // .z64 native
79-
{
80-
N64RomByteswapper.ToZ64Native(d);
81-
}
82-
}
72+
foreach (var r in lp.Roms) _ = N64RomByteswapper.ToZ64Native(r.RomData); // no-op if N64 magic bytes not present
8373

8474
var gbRoms = lp.Roms.FindAll(r => IsGBRom(r.FileData)).Select(r => r.FileData).ToArray();
8575
var rom = lp.Roms.Find(r => !gbRoms.Contains(r.FileData) && (char)r.RomData[0x3B] is 'N' or 'C')?.RomData;

0 commit comments

Comments
 (0)