IPSPatcher.cs
1 using Ryujinx.Common.Logging; 2 using System; 3 using System.IO; 4 5 namespace Ryujinx.HLE.Loaders.Mods 6 { 7 class IpsPatcher 8 { 9 readonly MemPatch _patches; 10 11 public IpsPatcher(BinaryReader reader) 12 { 13 _patches = ParseIps(reader); 14 if (_patches != null) 15 { 16 Logger.Info?.Print(LogClass.ModLoader, "IPS patch loaded successfully"); 17 } 18 } 19 20 private static MemPatch ParseIps(BinaryReader reader) 21 { 22 ReadOnlySpan<byte> ipsHeaderMagic = "PATCH"u8; 23 ReadOnlySpan<byte> ipsTailMagic = "EOF"u8; 24 ReadOnlySpan<byte> ips32HeaderMagic = "IPS32"u8; 25 ReadOnlySpan<byte> ips32TailMagic = "EEOF"u8; 26 27 MemPatch patches = new(); 28 var header = reader.ReadBytes(ipsHeaderMagic.Length).AsSpan(); 29 30 if (header.Length != ipsHeaderMagic.Length) 31 { 32 return null; 33 } 34 35 bool is32; 36 ReadOnlySpan<byte> tailSpan; 37 38 if (header.SequenceEqual(ipsHeaderMagic)) 39 { 40 is32 = false; 41 tailSpan = ipsTailMagic; 42 } 43 else if (header.SequenceEqual(ips32HeaderMagic)) 44 { 45 is32 = true; 46 tailSpan = ips32TailMagic; 47 } 48 else 49 { 50 return null; 51 } 52 53 byte[] buf = new byte[tailSpan.Length]; 54 55 bool ReadNext(int size) => reader.Read(buf, 0, size) != size; 56 57 while (true) 58 { 59 if (ReadNext(buf.Length)) 60 { 61 return null; 62 } 63 64 if (buf.AsSpan().SequenceEqual(tailSpan)) 65 { 66 break; 67 } 68 69 int patchOffset = is32 ? buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] 70 : buf[0] << 16 | buf[1] << 8 | buf[2]; 71 72 if (ReadNext(2)) 73 { 74 return null; 75 } 76 77 int patchSize = buf[0] << 8 | buf[1]; 78 79 if (patchSize == 0) // RLE/Fill mode 80 { 81 if (ReadNext(2)) 82 { 83 return null; 84 } 85 86 int fillLength = buf[0] << 8 | buf[1]; 87 88 if (ReadNext(1)) 89 { 90 return null; 91 } 92 93 patches.AddFill((uint)patchOffset, fillLength, buf[0]); 94 } 95 else // Copy mode 96 { 97 var patch = reader.ReadBytes(patchSize); 98 99 if (patch.Length != patchSize) 100 { 101 return null; 102 } 103 104 patches.Add((uint)patchOffset, patch); 105 } 106 } 107 108 return patches; 109 } 110 111 public void AddPatches(MemPatch patches) 112 { 113 patches.AddFrom(_patches); 114 } 115 } 116 }