"Correct" IPS applier to resize file if it tries to write off end. I'm not sure what the spec behavior is, but this works for at least one file in the wild.

This commit is contained in:
goyuken 2015-04-19 13:55:47 +00:00
parent 5d5a4d10f2
commit c4f608a39b
2 changed files with 15 additions and 7 deletions

View File

@ -5,7 +5,7 @@ namespace BizHawk.Client.Common
{ {
public static class IPS public static class IPS
{ {
public static void Patch(byte[] rom, Stream patch) public static byte[] Patch(byte[] rom, Stream patch)
{ {
var ipsHeader = new byte[5]; var ipsHeader = new byte[5];
patch.Read(ipsHeader, 0, 5); patch.Read(ipsHeader, 0, 5);
@ -16,32 +16,40 @@ namespace BizHawk.Client.Common
if (ipsHeader[i] != header[i]) if (ipsHeader[i] != header[i])
{ {
Console.WriteLine("Patch file specified is invalid."); Console.WriteLine("Patch file specified is invalid.");
return; return null;
} }
} }
// header verified, loop over patch entries // header verified, loop over patch entries
uint EOF = ('E' * 0x10000 + 'O' * 0x100 + 'F'); uint EOF = ('E' * 0x10000 + 'O' * 0x100 + 'F');
var ret = new MemoryStream(rom.Length);
ret.Write(rom, 0, rom.Length);
while (true) while (true)
{ {
uint offset = Read24(patch); uint offset = Read24(patch);
if (offset == EOF) return; if (offset == EOF)
return ret.ToArray();
ushort size = Read16(patch); ushort size = Read16(patch);
ret.Seek(offset, SeekOrigin.Begin);
if (size != 0) // non-RLE patch if (size != 0) // non-RLE patch
{ {
var patchData = new byte[size]; var patchData = new byte[size];
patch.Read(patchData, 0, size); patch.Read(patchData, 0, size);
for (int i = 0; i < size; i++)
rom[offset++] = patchData[i]; ret.Write(patchData, 0, patchData.Length);
} }
else // RLE patch else // RLE patch
{ {
size = Read16(patch); size = Read16(patch);
byte value = (byte)patch.ReadByte(); byte value = (byte)patch.ReadByte();
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
rom[offset++] = value; {
ret.WriteByte(value);
}
} }
} }
} }

View File

@ -90,7 +90,7 @@ namespace BizHawk.Client.Common
patchFile.BindFirstOf("IPS"); patchFile.BindFirstOf("IPS");
if (patchFile.IsBound) if (patchFile.IsBound)
{ {
IPS.Patch(RomData, patchFile.GetStream()); RomData = IPS.Patch(RomData, patchFile.GetStream());
} }
} }
} }