XTermFix.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection.Emit;
  5. using HarmonyLib;
  6. using MonoMod.Utils;
  7. namespace BepInEx.Preloader.RuntimeFixes
  8. {
  9. internal static class XTermFix
  10. {
  11. public static void Apply()
  12. {
  13. if (!PlatformHelper.Is(Platform.Linux))
  14. return;
  15. if (AccessTools.Method("System.TermInfoReader:DetermineVersion") != null)
  16. {
  17. // Fix has been applied officially
  18. return;
  19. }
  20. var harmony = new HarmonyLib.Harmony("com.bepinex.xtermfix");
  21. harmony.Patch(AccessTools.Method("System.TermInfoReader:ReadHeader"),
  22. prefix: new HarmonyMethod(typeof(XTermFix), nameof(ReadHeaderPrefix)));
  23. harmony.Patch(AccessTools.Method("System.TermInfoReader:Get", new []{ AccessTools.TypeByName("System.TermInfoNumbers") }),
  24. transpiler: new HarmonyMethod(typeof(XTermFix), nameof(GetTermInfoNumbersTranspiler)));
  25. harmony.Patch(AccessTools.Method("System.TermInfoReader:Get", new []{ AccessTools.TypeByName("System.TermInfoStrings") }),
  26. transpiler: new HarmonyMethod(typeof(XTermFix), nameof(GetTermInfoStringsTranspiler)));
  27. harmony.Patch(AccessTools.Method("System.TermInfoReader:GetStringBytes", new []{ AccessTools.TypeByName("System.TermInfoStrings") }),
  28. transpiler: new HarmonyMethod(typeof(XTermFix), nameof(GetTermInfoStringsTranspiler)));
  29. }
  30. public static int intOffset;
  31. public static int GetInt32(byte[] buffer, int offset)
  32. {
  33. int b1 = buffer[offset];
  34. int b2 = buffer[offset + 1];
  35. int b3 = buffer[offset + 2];
  36. int b4 = buffer[offset + 3];
  37. if (b1 == 255 && b2 == 255 && b3 == 255 && b4 == 255)
  38. return -1;
  39. return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
  40. }
  41. public static short GetInt16(byte[] buffer, int offset)
  42. {
  43. int b1 = buffer[offset];
  44. int b2 = buffer[offset + 1];
  45. if (b1 == 255 && b2 == 255)
  46. return -1;
  47. return (short)(b1 | (b2 << 8));
  48. }
  49. public static int GetInteger(byte[] buffer, int offset)
  50. {
  51. return intOffset == 2
  52. ? GetInt16(buffer, offset)
  53. : GetInt32(buffer, offset);
  54. }
  55. public static void DetermineVersion(short magic)
  56. {
  57. if (magic == 0x11a)
  58. intOffset = 2;
  59. else if (magic == 0x21e)
  60. intOffset = 4;
  61. else
  62. throw new Exception($"Unknown xterm header format: {magic}");
  63. }
  64. public static bool ReadHeaderPrefix(object __instance, byte[] buffer, ref int position, ref short ___boolSize, ref short ___numSize, ref short ___strOffsets)
  65. {
  66. short magic = GetInt16(buffer, position);
  67. position += 2;
  68. DetermineVersion(magic);
  69. // nameSize = GetInt16(buffer, position);
  70. position += 2;
  71. ___boolSize = GetInt16(buffer, position);
  72. position += 2;
  73. ___numSize = GetInt16(buffer, position);
  74. position += 2;
  75. ___strOffsets = GetInt16(buffer, position);
  76. position += 2;
  77. // strSize = GetInt16(buffer, position);
  78. position += 2;
  79. return false;
  80. }
  81. public static IEnumerable<CodeInstruction> GetTermInfoNumbersTranspiler(IEnumerable<CodeInstruction> instructions)
  82. {
  83. // This implementation does not seem to have changed so I will be using indexes like the lazy fuck I am
  84. var list = instructions.ToList();
  85. list[31] = new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(XTermFix), nameof(intOffset)));
  86. list[36] = new CodeInstruction(OpCodes.Nop);
  87. list[39] = new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(XTermFix), nameof(GetInteger)));
  88. return list;
  89. }
  90. public static IEnumerable<CodeInstruction> GetTermInfoStringsTranspiler(IEnumerable<CodeInstruction> instructions)
  91. {
  92. // This implementation does not seem to have changed so I will be using indexes like the lazy fuck I am
  93. var list = instructions.ToList();
  94. list[32] = new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(XTermFix), nameof(intOffset)));
  95. return list;
  96. }
  97. }
  98. }