IPSPatcher.cs 3.1 KB

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