refactor: convert Patch to abstract class

BREAKING CHANGE: Patch class is now an abstract class. You must implement it. You can use anonymous implements, like done in the tests.
This commit is contained in:
Lucaskyy 2022-03-20 21:57:20 +01:00 committed by oSumAtrIX
parent 428f7f4dec
commit cb9b1b9416
No known key found for this signature in database
GPG Key ID: A9B3094ACDB604B4
2 changed files with 56 additions and 57 deletions

View File

@ -1,9 +1,5 @@
package net.revanced.patcher.patch package net.revanced.patcher.patch
class Patch(val patchName: String, val fn: () -> PatchResult) { abstract class Patch(val patchName: String) {
fun execute(): PatchResult { abstract fun execute(): PatchResult
return fn()
}
} }

View File

@ -1,6 +1,7 @@
package net.revanced.patcher package net.revanced.patcher
import net.revanced.patcher.patch.Patch import net.revanced.patcher.patch.Patch
import net.revanced.patcher.patch.PatchResult
import net.revanced.patcher.patch.PatchResultSuccess import net.revanced.patcher.patch.PatchResultSuccess
import net.revanced.patcher.signature.Signature import net.revanced.patcher.signature.Signature
import net.revanced.patcher.util.ExtraTypes import net.revanced.patcher.util.ExtraTypes
@ -46,62 +47,64 @@ internal class PatcherTest {
val patcher = Patcher(testData, testSigs) val patcher = Patcher(testData, testSigs)
patcher.addPatches( patcher.addPatches(
Patch ("TestPatch") { object : Patch("TestPatch") {
// Get the method from the resolver cache override fun execute(): PatchResult {
val mainMethod = patcher.cache.methods["mainMethod"] // Get the method from the resolver cache
// Get the instruction list val mainMethod = patcher.cache.methods["mainMethod"]
val instructions = mainMethod.method.instructions!! // Get the instruction list
val instructions = mainMethod.method.instructions!!
// Let's modify it, so it prints "Hello, ReVanced! Editing bytecode." // Let's modify it, so it prints "Hello, ReVanced! Editing bytecode."
// Get the start index of our opcode pattern. // Get the start index of our opcode pattern.
// This will be the index of the LDC instruction. // This will be the index of the LDC instruction.
val startIndex = mainMethod.scanData.startIndex val startIndex = mainMethod.scanData.startIndex
TestUtil.assertNodeEqual(LdcInsnNode("Hello, world!"), instructions[startIndex]!!) TestUtil.assertNodeEqual(LdcInsnNode("Hello, world!"), instructions[startIndex]!!)
// Create a new LDC node and replace the LDC instruction. // Create a new LDC node and replace the LDC instruction.
val stringNode = LdcInsnNode("Hello, ReVanced! Editing bytecode.") val stringNode = LdcInsnNode("Hello, ReVanced! Editing bytecode.")
instructions.setAt(startIndex, stringNode) instructions.setAt(startIndex, stringNode)
// Now lets print our string twice! // Now lets print our string twice!
// Insert our instructions after the second instruction by our pattern. // Insert our instructions after the second instruction by our pattern.
// This will place our instructions after the original INVOKEVIRTUAL call. // This will place our instructions after the original INVOKEVIRTUAL call.
// You could also copy the instructions from the list and then modify the LDC instruction again, // You could also copy the instructions from the list and then modify the LDC instruction again,
// but this is to show a more advanced example of writing bytecode using the patcher and ASM. // but this is to show a more advanced example of writing bytecode using the patcher and ASM.
instructions.insertAt( instructions.insertAt(
startIndex + 1, startIndex + 1,
FieldInsnNode( FieldInsnNode(
GETSTATIC, GETSTATIC,
Type.getInternalName(System::class.java), // "java/io/System" Type.getInternalName(System::class.java), // "java/io/System"
"out", "out",
Type.getInternalName(PrintStream::class.java) // "java.io.PrintStream" Type.getInternalName(PrintStream::class.java) // "java.io.PrintStream"
), ),
LdcInsnNode("Hello, ReVanced! Adding bytecode."), LdcInsnNode("Hello, ReVanced! Adding bytecode."),
MethodInsnNode( MethodInsnNode(
INVOKEVIRTUAL, INVOKEVIRTUAL,
Type.getInternalName(PrintStream::class.java), // "java/io/PrintStream" Type.getInternalName(PrintStream::class.java), // "java/io/PrintStream"
"println", "println",
Type.getMethodDescriptor( Type.getMethodDescriptor(
Type.VOID_TYPE, Type.VOID_TYPE,
Type.getType(String::class.java) Type.getType(String::class.java)
) // "(Ljava/lang/String;)V" ) // "(Ljava/lang/String;)V"
)
) )
)
// Our code now looks like this: // Our code now looks like this:
// public static main(java.lang.String[] arg0) { // Method signature: ([Ljava/lang/String;)V // public static main(java.lang.String[] arg0) { // Method signature: ([Ljava/lang/String;)V
// getstatic java/lang/System.out:java.io.PrintStream // getstatic java/lang/System.out:java.io.PrintStream
// ldc "Hello, ReVanced! Editing bytecode." (java.lang.String) // We overwrote this instruction. // ldc "Hello, ReVanced! Editing bytecode." (java.lang.String) // We overwrote this instruction.
// invokevirtual java/io/PrintStream.println(Ljava/lang/String;)V // invokevirtual java/io/PrintStream.println(Ljava/lang/String;)V
// getstatic java/lang/System.out:java.io.PrintStream // This instruction and the 2 instructions below are written manually. // getstatic java/lang/System.out:java.io.PrintStream // This instruction and the 2 instructions below are written manually.
// ldc "Hello, ReVanced! Adding bytecode." (java.lang.String) // ldc "Hello, ReVanced! Adding bytecode." (java.lang.String)
// invokevirtual java/io/PrintStream.println(Ljava/lang/String;)V // invokevirtual java/io/PrintStream.println(Ljava/lang/String;)V
// return // return
// } // }
// Finally, tell the patcher that this patch was a success. // Finally, tell the patcher that this patch was a success.
// You can also return PatchResultError with a message. // You can also return PatchResultError with a message.
// If an exception is thrown inside this function, // If an exception is thrown inside this function,
// a PatchResultError will be returned with the error message. // a PatchResultError will be returned with the error message.
PatchResultSuccess() return PatchResultSuccess()
}
} }
) )