147 lines
4.1 KiB
C#
147 lines
4.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Reflection;
|
|
using HarmonyLib;
|
|
|
|
namespace NzbDrone.RuntimePatches
|
|
{
|
|
public abstract class RuntimePatchBase
|
|
{
|
|
private Harmony _harmony;
|
|
|
|
internal static bool IsDebug;
|
|
|
|
public virtual bool ShouldPatch() => true;
|
|
protected abstract void Patch();
|
|
|
|
public void Patch(Harmony harmony)
|
|
{
|
|
_harmony = harmony;
|
|
|
|
if (ShouldPatch())
|
|
{
|
|
Patch();
|
|
}
|
|
}
|
|
|
|
protected const BindingFlags DefaultBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
|
|
|
|
protected static MethodInfo FindMethod(Type type, string methodName, params string[] paramTypes)
|
|
{
|
|
foreach (var methodInfo in type.GetMethods(DefaultBindingFlags))
|
|
{
|
|
if (methodInfo.Name != methodName)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var parameters = methodInfo.GetParameters();
|
|
|
|
if (parameters.Length != paramTypes.Length)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var parametersMatch = true;
|
|
for (var i = 0; i < parameters.Length; i++)
|
|
{
|
|
if (parameters[i].ParameterType.Name != paramTypes[i] &&
|
|
parameters[i].ParameterType.FullName != paramTypes[i] &&
|
|
parameters[i].ParameterType.GetSimplifiedName() != paramTypes[i] &&
|
|
parameters[i].ParameterType.GetSimplifiedName(true) != paramTypes[i])
|
|
{
|
|
parametersMatch = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!parametersMatch)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
return methodInfo;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
protected void PatchMethod(MethodInfo methodInfo)
|
|
{
|
|
var prefix = GetPatchMethod("Prefix_" + methodInfo.Name);
|
|
var postfix = GetPatchMethod("Postfix_" + methodInfo.Name);
|
|
var transpiler = GetPatchMethod("Transpiler_" + methodInfo.Name);
|
|
|
|
_harmony.Patch(methodInfo, prefix, postfix, transpiler);
|
|
}
|
|
|
|
protected void TryPatchMethod(string typeName, string methodName, params string[] paramTypes)
|
|
{
|
|
var type = Type.GetType(typeName);
|
|
|
|
if (type != null)
|
|
{
|
|
TryPatchMethod(type, "GetSslServer");
|
|
}
|
|
else
|
|
{
|
|
Debug($"Skipped patching method {typeName}.{methodName}: Type not found");
|
|
}
|
|
}
|
|
|
|
protected void TryPatchMethod(Type type, string methodName, params string[] paramTypes)
|
|
{
|
|
var methodInfo = FindMethod(type, methodName, paramTypes);
|
|
if (methodInfo != null)
|
|
{
|
|
PatchMethod(methodInfo);
|
|
}
|
|
else
|
|
{
|
|
Debug($"Skipped patching method {type.GetSimplifiedName()}.{methodName}: Method not found");
|
|
}
|
|
}
|
|
|
|
private HarmonyMethod GetPatchMethod(string name)
|
|
{
|
|
var patch = GetType().GetMethod(name, DefaultBindingFlags);
|
|
if (patch != null)
|
|
{
|
|
return new HarmonyMethod(patch);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
protected void DebugOpcodes(string prefix, List<CodeInstruction> codes)
|
|
{
|
|
if (IsDebug)
|
|
{
|
|
Log($"Opcodes {prefix}:");
|
|
foreach (var code in codes)
|
|
{
|
|
Console.WriteLine($" {code}");
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void Debug(string log)
|
|
{
|
|
if (IsDebug)
|
|
{
|
|
Log(log);
|
|
}
|
|
}
|
|
|
|
protected void Error(string log)
|
|
{
|
|
Log(log);
|
|
}
|
|
|
|
protected virtual void Log(string log)
|
|
{
|
|
Console.WriteLine($"RuntimePatch {GetType().Name}: {log}");
|
|
}
|
|
}
|
|
}
|