75 lines
1.6 KiB
C#
75 lines
1.6 KiB
C#
using System;
|
|
using System.IO;
|
|
|
|
namespace BizHawk.Client.Common
|
|
{
|
|
public static class IPS
|
|
{
|
|
public static byte[] Patch(byte[] rom, Stream patch)
|
|
{
|
|
var ipsHeader = new byte[5];
|
|
patch.Read(ipsHeader, 0, 5);
|
|
|
|
string header = "PATCH";
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
if (ipsHeader[i] != header[i])
|
|
{
|
|
Console.WriteLine("Patch file specified is invalid.");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// header verified, loop over patch entries
|
|
uint eof = ('E' * 0x10000) + ('O' * 0x100) + 'F';
|
|
|
|
var ret = new MemoryStream(rom.Length);
|
|
ret.Write(rom, 0, rom.Length);
|
|
|
|
while (true)
|
|
{
|
|
uint offset = Read24(patch);
|
|
if (offset == eof)
|
|
{
|
|
return ret.ToArray();
|
|
}
|
|
|
|
ushort size = Read16(patch);
|
|
|
|
ret.Seek(offset, SeekOrigin.Begin);
|
|
|
|
if (size != 0) // non-RLE patch
|
|
{
|
|
var patchData = new byte[size];
|
|
patch.Read(patchData, 0, size);
|
|
|
|
ret.Write(patchData, 0, patchData.Length);
|
|
}
|
|
else // RLE patch
|
|
{
|
|
size = Read16(patch);
|
|
byte value = (byte)patch.ReadByte();
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
ret.WriteByte(value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static ushort Read16(Stream patch)
|
|
{
|
|
int upper = patch.ReadByte();
|
|
int lower = patch.ReadByte();
|
|
return (ushort)((upper * 0x100) + lower);
|
|
}
|
|
|
|
private static uint Read24(Stream patch)
|
|
{
|
|
int upper = patch.ReadByte();
|
|
int middle = patch.ReadByte();
|
|
int lower = patch.ReadByte();
|
|
return (uint)((upper * 0x10000) + (middle * 0x100) + lower);
|
|
}
|
|
}
|
|
} |