about summary refs log tree commit diff
path: root/pkgs/games/build-support
diff options
context:
space:
mode:
authoraszlig <aszlig@nix.build>2018-07-18 11:47:03 +0200
committeraszlig <aszlig@nix.build>2018-07-19 06:35:24 +0200
commitec65da1fbc93bd4fcdbdf20cb41c085ece53473c (patch)
treec73242ef0680067486de97f5ddca30fdd06bcc16 /pkgs/games/build-support
parentbe80103bd659e922569deb9c52982a8c081fb698 (diff)
monogame-patcher: Allow specifying extra assembly
If we want to replace a call with one that's not in a module which is
currently referenced by the target file we now have another command line
flag for replace-call (-a) where we can specify the additional DLL file.

Signed-off-by: aszlig <aszlig@nix.build>
Diffstat (limited to 'pkgs/games/build-support')
-rw-r--r--pkgs/games/build-support/monogame-patcher/src/options.cs4
-rw-r--r--pkgs/games/build-support/monogame-patcher/src/patcher.cs47
-rw-r--r--pkgs/games/build-support/monogame-patcher/src/test.sh21
3 files changed, 58 insertions, 14 deletions
diff --git a/pkgs/games/build-support/monogame-patcher/src/options.cs b/pkgs/games/build-support/monogame-patcher/src/options.cs
index 32a8403e..73add8d6 100644
--- a/pkgs/games/build-support/monogame-patcher/src/options.cs
+++ b/pkgs/games/build-support/monogame-patcher/src/options.cs
@@ -27,4 +27,8 @@ class ReplaceCallCmd : GenericOptions {
 
     [Value(2, Required=true, MetaName = "type", HelpText = "Types to patch.")]
     public IEnumerable<string> typesToPatch { get; set; }
+
+    [Option('a', "assembly",
+            HelpText="Look up replacement from the specified assembly.")]
+    public string assemblyFile { get; set; }
 };
diff --git a/pkgs/games/build-support/monogame-patcher/src/patcher.cs b/pkgs/games/build-support/monogame-patcher/src/patcher.cs
index 6aeaa324..961a6b7e 100644
--- a/pkgs/games/build-support/monogame-patcher/src/patcher.cs
+++ b/pkgs/games/build-support/monogame-patcher/src/patcher.cs
@@ -21,28 +21,36 @@ class Command {
             this.outfile = options.outputFile;
         this.infile = options.inputFile;
 
+        var readOnly = this.infile != this.outfile;
+        this.module = this.read_module(this.infile, readOnly);
+    }
+
+    protected ModuleDefinition read_module(string path, bool readOnly) {
         var resolver = new DefaultAssemblyResolver();
-        resolver.AddSearchDirectory(Path.GetDirectoryName(this.infile));
+        resolver.AddSearchDirectory(Path.GetDirectoryName(path));
 
         var rp = new ReaderParameters {
-            ReadWrite = this.infile == this.outfile,
+            ReadWrite = !readOnly,
             AssemblyResolver = resolver
         };
-        this.module = ModuleDefinition.ReadModule(this.infile, rp);
+        return ModuleDefinition.ReadModule(path, rp);
+    }
+
+    protected virtual IEnumerable<TypeDefinition> get_assembly_types() {
+        return this.module.AssemblyReferences
+            .Select(a => this.module.AssemblyResolver.Resolve(a))
+            .SelectMany(r => r.MainModule.Types);
     }
 
     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);
-                }
+        foreach (var type in this.get_assembly_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);
             }
         }
 
@@ -99,8 +107,12 @@ class FixFileStreams : Command {
 class ReplaceCall : Command {
     private string search;
     private MethodReference replace;
+    private ModuleDefinition targetModule;
 
     public ReplaceCall(ReplaceCallCmd options) : base(options) {
+        if (options.assemblyFile != null)
+            this.targetModule = this.read_module(options.assemblyFile, true);
+
         this.search = options.replaceMethod;
         this.replace = this.find_method_ref(options.replacementMethod);
 
@@ -113,6 +125,13 @@ class ReplaceCall : Command {
         this.save();
     }
 
+    protected override IEnumerable<TypeDefinition> get_assembly_types() {
+        if (this.targetModule != null)
+            return this.targetModule.Types;
+        else
+            return base.get_assembly_types();
+    }
+
     private void patch_method(MethodDefinition md) {
         var il = md.Body.GetILProcessor();
 
diff --git a/pkgs/games/build-support/monogame-patcher/src/test.sh b/pkgs/games/build-support/monogame-patcher/src/test.sh
index b19457d4..a4f65aef 100644
--- a/pkgs/games/build-support/monogame-patcher/src/test.sh
+++ b/pkgs/games/build-support/monogame-patcher/src/test.sh
@@ -34,6 +34,19 @@ public class b {
 }
 EOF
 
+cat > "c.cs" <<EOF
+using System;
+
+public class c {
+    public static string anotherReplacement(string foobar) {
+        if (foobar == "nope")
+            return "nope";
+        Console.WriteLine("foobar called: " + foobar);
+        return "foobar";
+    }
+}
+EOF
+
 cat > "test1.cs" <<EOF
 class test1 {
     public static void Main() {
@@ -54,6 +67,7 @@ EOF
 mkdir subdir
 mcs a.cs -target:library -out:subdir/a.dll
 mcs b.cs -target:library -out:subdir/b.dll
+mcs c.cs -target:library -out:subdir/c.dll
 
 mcs test1.cs -r:subdir/a -r:subdir/b -out:subdir/test1.exe
 mcs test2.cs -r:subdir/a -r:subdir/b -out:subdir/test2.exe
@@ -70,6 +84,13 @@ mcs test2.cs -r:subdir/a -r:subdir/b -out:subdir/test2.exe
 
 test "$(mono subdir/test1.exe)" = "bar called: xxx"
 
+"$out/bin/monogame-patcher" replace-call -i subdir/test1.exe -a subdir/c.dll \
+    "System.String b::replacement(System.String)" \
+    "System.String c::anotherReplacement(System.String)" \
+    test1
+
+test "$(mono subdir/test1.exe)" = "foobar called: xxx"
+
 echo foo > write_test.txt
 
 test "$(mono subdir/test2.exe)" = "can write"