about summary refs log tree commit diff
path: root/pkgs/games/build-support/monogame-patcher/src/patcher.cs
diff options
context:
space:
mode:
authoraszlig <aszlig@nix.build>2018-07-17 06:13:35 +0200
committeraszlig <aszlig@nix.build>2018-07-19 06:35:15 +0200
commit19408db5a4eaa309d3f84f6a2d056c5b8b7c8fcb (patch)
treee660ddbc789361e0a650b2a44893083b9bbfe20e /pkgs/games/build-support/monogame-patcher/src/patcher.cs
parent2d3dabe8af2ea4abc51f68891741db360ad11c75 (diff)
monogame-patcher: Refactor method ref finding
So far we have searched for methods in two steps: First get all the
types and then find all of the constructors or method definitions.

The match for the actual method definition was done first for the type
and then again for the full definition of the method/constructor.

For the replace-call subcommand this also means that we don't have a
very good way to find the type, because if we wanted to keep doing this
in two steps we would need to parse the type name out of the one given
as the replacement string in replace-call.

So now we recurse through *all* the constructors and methods and do a
full match against the specified replacement string, both for
replace-call and for fix-filestreams.

Compared to the implementation so far we also do this just once instead
of every time we find a call or FileStream constructor.

I also overhauled the way we do testing, because in the end writing
tests using NUnit would introduce a lot of code churn because we need to
make a lot of external calls. The shell is especially useful for exactly
that and our tests are now just a plain shell script.

Signed-off-by: aszlig <aszlig@nix.build>
Diffstat (limited to 'pkgs/games/build-support/monogame-patcher/src/patcher.cs')
-rw-r--r--pkgs/games/build-support/monogame-patcher/src/patcher.cs62
1 files changed, 29 insertions, 33 deletions
diff --git a/pkgs/games/build-support/monogame-patcher/src/patcher.cs b/pkgs/games/build-support/monogame-patcher/src/patcher.cs
index 794db98e..c9046f0a 100644
--- a/pkgs/games/build-support/monogame-patcher/src/patcher.cs
+++ b/pkgs/games/build-support/monogame-patcher/src/patcher.cs
@@ -27,6 +27,24 @@ class Command {
         this.module = ModuleDefinition.ReadModule(this.infile, rp);
     }
 
+    protected MethodReference find_method_ref(string fullSig) {
+        foreach (var aref in this.module.AssemblyReferences) {
+            var resolved = this.module.AssemblyResolver.Resolve(aref);
+            foreach (var type in resolved.MainModule.Types) {
+                foreach (var ctor in type.GetConstructors()) {
+                    if (ctor.ToString() != fullSig) continue;
+                    return this.module.ImportReference(ctor);
+                }
+                foreach (var meth in type.GetMethods()) {
+                    if (meth.ToString() != fullSig) continue;
+                    return this.module.ImportReference(meth);
+                }
+            }
+        }
+
+        throw new Exception($"Method reference for {fullSig} not found.");
+    }
+
     public void save() {
         if (this.outfile == this.infile)
             this.module.Write();
@@ -36,10 +54,17 @@ class Command {
 }
 
 class FixFileStreams : Command {
+    private MethodReference betterFileStream;
+
     public FixFileStreams(FixFileStreamsCmd options) : base(options) {
         var filtered = this.module.Types
             .Where(p => options.typesToPatch.Contains(p.Name));
 
+        this.betterFileStream = this.find_method_ref(
+            "System.Void System.IO.FileStream::.ctor" +
+            "(System.String,System.IO.FileMode,System.IO.FileAccess)"
+        );
+
         foreach (var toPatch in filtered)
             patch_type(toPatch);
 
@@ -57,24 +82,7 @@ class FixFileStreams : Command {
         foreach (Instruction i in fileStreams.ToList()) {
             var fileAccessRead = il.Create(OpCodes.Ldc_I4_1);
             il.InsertBefore(i, fileAccessRead);
-
-            var ctorType = this.module.AssemblyReferences.Select(
-                x => new {
-                    type = this.module.AssemblyResolver.Resolve(x)
-                        .MainModule.GetType("System.IO.FileStream")
-                }
-            ).Where(x => x.type != null).Select(x => x.type).First();
-
-            string wantedCtor = "System.Void System.IO.FileStream"
-                              + "::.ctor(System.String,"
-                              + "System.IO.FileMode,"
-                              + "System.IO.FileAccess)";
-
-            var newCtor = ctorType.GetConstructors()
-                .Single(x => x.ToString() == wantedCtor);
-
-            var refCtor = this.module.ImportReference(newCtor);
-            il.Replace(i, il.Create(OpCodes.Newobj, refCtor));
+            il.Replace(i, il.Create(OpCodes.Newobj, this.betterFileStream));
         }
     }
 
@@ -86,11 +94,11 @@ class FixFileStreams : Command {
 
 class ReplaceCall : Command {
     private string search;
-    private string replace;
+    private MethodReference replace;
 
     public ReplaceCall(ReplaceCallCmd options) : base(options) {
         this.search = options.replaceCall.ToList()[0];
-        this.replace = options.replaceCall.ToList()[1];
+        this.replace = this.find_method_ref(options.replaceCall.ToList()[1]);
 
         var filtered = this.module.Types
             .Where(p => options.typesToPatch.Contains(p.Name));
@@ -108,20 +116,8 @@ class ReplaceCall : Command {
             .Where(i => i.OpCode == OpCodes.Call)
             .Where(i => i.Operand.ToString() == this.search);
 
-        var ctorType = this.module.AssemblyReferences.Select(
-            x => new {
-                // XXX: Don't hardcode UnityEngine.Application!
-                type = this.module.AssemblyResolver.Resolve(x)
-                    .MainModule.GetType("UnityEngine.Application")
-            }
-        ).Where(x => x.type != null).Select(x => x.type).First();
-
-        var newMethod = ctorType.GetMethods()
-            .Single(x => x.ToString() == this.replace);
-        var refMethod = this.module.ImportReference(newMethod);
-
         foreach (Instruction i in found.ToList())
-            il.Replace(i, il.Create(OpCodes.Call, refMethod));
+            il.Replace(i, il.Create(OpCodes.Call, this.replace));
     }
 
     private void patch_type(TypeDefinition td) {