mirror of
https://github.com/ReVanced/revanced-patcher.git
synced 2026-01-28 21:51:02 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b6dcd88495 | ||
|
|
a925650044 | ||
|
|
77bbf6be1f | ||
|
|
bd053b7e99 |
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,3 +1,17 @@
|
|||||||
|
# [6.2.0](https://github.com/revanced/revanced-patcher/compare/v6.1.1...v6.2.0) (2022-12-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* merge classes on addition ([#127](https://github.com/revanced/revanced-patcher/issues/127)) ([a925650](https://github.com/revanced/revanced-patcher/commit/a9256500440f9b4117f1b8813ba0097dafee4ebb))
|
||||||
|
|
||||||
|
## [6.1.1](https://github.com/revanced/revanced-patcher/compare/v6.1.0...v6.1.1) (2022-11-25)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* use `MethodUtil.methodSignaturesMatch` instead of `Method.softCompareTo` ([bd053b7](https://github.com/revanced/revanced-patcher/commit/bd053b7e9974c0282d56e6762459db7070452e4a))
|
||||||
|
|
||||||
# [6.1.0](https://github.com/revanced/revanced-patcher/compare/v6.0.2...v6.1.0) (2022-11-22)
|
# [6.1.0](https://github.com/revanced/revanced-patcher/compare/v6.0.2...v6.1.0) (2022-11-22)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
version = 6.1.0
|
version = 6.2.0
|
||||||
|
|||||||
@@ -8,6 +8,10 @@ import app.revanced.patcher.extensions.nullOutputStream
|
|||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
||||||
import app.revanced.patcher.patch.*
|
import app.revanced.patcher.patch.*
|
||||||
import app.revanced.patcher.util.VersionReader
|
import app.revanced.patcher.util.VersionReader
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass.Companion.toMutable
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||||
import brut.androlib.Androlib
|
import brut.androlib.Androlib
|
||||||
import brut.androlib.meta.UsesFramework
|
import brut.androlib.meta.UsesFramework
|
||||||
import brut.androlib.options.BuildOptions
|
import brut.androlib.options.BuildOptions
|
||||||
@@ -22,7 +26,9 @@ import lanchon.multidexlib2.BasicDexFileNamer
|
|||||||
import lanchon.multidexlib2.DexIO
|
import lanchon.multidexlib2.DexIO
|
||||||
import lanchon.multidexlib2.MultiDexIO
|
import lanchon.multidexlib2.MultiDexIO
|
||||||
import org.jf.dexlib2.Opcodes
|
import org.jf.dexlib2.Opcodes
|
||||||
|
import org.jf.dexlib2.iface.ClassDef
|
||||||
import org.jf.dexlib2.iface.DexFile
|
import org.jf.dexlib2.iface.DexFile
|
||||||
|
import org.jf.dexlib2.util.MethodUtil
|
||||||
import org.jf.dexlib2.writer.io.MemoryDataStore
|
import org.jf.dexlib2.writer.io.MemoryDataStore
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
@@ -65,40 +71,85 @@ class Patcher(private val options: PatcherOptions) {
|
|||||||
/**
|
/**
|
||||||
* Add additional dex file container to the patcher.
|
* Add additional dex file container to the patcher.
|
||||||
* @param files The dex file containers to add to the patcher.
|
* @param files The dex file containers to add to the patcher.
|
||||||
* @param allowedOverwrites A list of class types that are allowed to be overwritten.
|
* @param process The callback for [files] which are being added.
|
||||||
* @param throwOnDuplicates If this is set to true, the patcher will throw an exception if a duplicate class has been found.
|
|
||||||
*/
|
*/
|
||||||
fun addFiles(
|
fun addFiles(
|
||||||
files: List<File>,
|
files: List<File>,
|
||||||
allowedOverwrites: Iterable<String> = emptyList(),
|
process: (File) -> Unit
|
||||||
throwOnDuplicates: Boolean = false,
|
|
||||||
callback: (File) -> Unit
|
|
||||||
) {
|
) {
|
||||||
for (file in files) {
|
with(context.bytecodeContext.classes) {
|
||||||
var modified = false
|
for (file in files) {
|
||||||
for (classDef in MultiDexIO.readDexFile(true, file, NAMER, null, null).classes) {
|
process(file)
|
||||||
val type = classDef.type
|
for (classDef in MultiDexIO.readDexFile(true, file, NAMER, null, null).classes) {
|
||||||
|
val type = classDef.type
|
||||||
|
|
||||||
val existingClass = context.bytecodeContext.classes.classes.findIndexed { it.type == type }
|
val result = classes.findIndexed { it.type == type }
|
||||||
if (existingClass == null) {
|
if (result == null) {
|
||||||
if (throwOnDuplicates) throw Exception("Class $type has already been added to the patcher")
|
logger.trace("Merging type $type")
|
||||||
|
classes.add(classDef)
|
||||||
|
} else {
|
||||||
|
val (existingClass, existingClassIndex) = result
|
||||||
|
|
||||||
logger.trace("Merging $type")
|
logger.trace("Type $type exists. Adding missing methods and fields.")
|
||||||
context.bytecodeContext.classes.classes.add(classDef)
|
|
||||||
modified = true
|
|
||||||
|
|
||||||
continue
|
/**
|
||||||
|
* Add missing fields and methods from [from].
|
||||||
|
*
|
||||||
|
* @param from The class to add methods and fields from.
|
||||||
|
*/
|
||||||
|
fun ClassDef.addMissingFrom(from: ClassDef) {
|
||||||
|
var changed = false
|
||||||
|
fun <T> ClassDef.transformClass(transform: (MutableClass) -> T): T {
|
||||||
|
fun toMutableClass() =
|
||||||
|
if (this@transformClass is MutableClass) this else this.toMutable()
|
||||||
|
return transform(toMutableClass())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ClassDef.addMissingMethods(): ClassDef {
|
||||||
|
fun getMissingMethods() = from.methods.filterNot {
|
||||||
|
this@addMissingMethods.methods.any { original ->
|
||||||
|
MethodUtil.methodSignaturesMatch(original, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getMissingMethods()
|
||||||
|
.apply {
|
||||||
|
if (isEmpty()) return@addMissingMethods this@addMissingMethods else changed =
|
||||||
|
true
|
||||||
|
}
|
||||||
|
.map { it.toMutable() }
|
||||||
|
.let { missingMethods ->
|
||||||
|
this@addMissingMethods.transformClass { classDef ->
|
||||||
|
classDef.apply { methods.addAll(missingMethods) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ClassDef.addMissingFields(): ClassDef {
|
||||||
|
fun getMissingFields() = from.fields.filterNot {
|
||||||
|
this@addMissingFields.fields.any { original -> original.name == it.name }
|
||||||
|
}
|
||||||
|
|
||||||
|
return getMissingFields()
|
||||||
|
.apply {
|
||||||
|
if (isEmpty()) return@addMissingFields this@addMissingFields else changed = true
|
||||||
|
}
|
||||||
|
.map { it.toMutable() }
|
||||||
|
.let { missingFields ->
|
||||||
|
this@addMissingFields.transformClass { classDef ->
|
||||||
|
classDef.apply { fields.addAll(missingFields) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
classes[existingClassIndex] = addMissingMethods().addMissingFields()
|
||||||
|
.apply { if (!changed) return }
|
||||||
|
}
|
||||||
|
|
||||||
|
existingClass.addMissingFrom(classDef)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!allowedOverwrites.contains(type)) continue
|
|
||||||
|
|
||||||
logger.trace("Overwriting $type")
|
|
||||||
|
|
||||||
val index = existingClass.second
|
|
||||||
context.bytecodeContext.classes.classes[index] = classDef
|
|
||||||
modified = true
|
|
||||||
}
|
}
|
||||||
if (modified) callback(file)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,6 +205,7 @@ class Patcher(private val options: PatcherOptions) {
|
|||||||
cacheDirectory.close()
|
cacheDirectory.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> logger.info("Not compiling resources because resource patching is not required")
|
else -> logger.info("Not compiling resources because resource patching is not required")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,6 +292,7 @@ class Patcher(private val options: PatcherOptions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceDecodingMode.MANIFEST_ONLY -> {
|
ResourceDecodingMode.MANIFEST_ONLY -> {
|
||||||
logger.info("Decoding AndroidManifest.xml only, because resources are not needed")
|
logger.info("Decoding AndroidManifest.xml only, because resources are not needed")
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import org.jf.dexlib2.builder.MutableMethodImplementation
|
|||||||
import org.jf.dexlib2.builder.instruction.*
|
import org.jf.dexlib2.builder.instruction.*
|
||||||
import org.jf.dexlib2.iface.Method
|
import org.jf.dexlib2.iface.Method
|
||||||
import org.jf.dexlib2.iface.instruction.Instruction
|
import org.jf.dexlib2.iface.instruction.Instruction
|
||||||
import org.jf.dexlib2.iface.reference.MethodReference
|
|
||||||
import org.jf.dexlib2.immutable.ImmutableMethod
|
import org.jf.dexlib2.immutable.ImmutableMethod
|
||||||
import org.jf.dexlib2.immutable.ImmutableMethodImplementation
|
import org.jf.dexlib2.immutable.ImmutableMethodImplementation
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
@@ -45,17 +44,6 @@ fun MutableMethodImplementation.removeInstructions(index: Int, count: Int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Compare a method to another, considering name and parameters.
|
|
||||||
* @param otherMethod The method to compare against.
|
|
||||||
* @return True if the methods match given the conditions.
|
|
||||||
*/
|
|
||||||
fun Method.softCompareTo(otherMethod: MethodReference): Boolean {
|
|
||||||
return this.name == otherMethod.name && parametersEqual(
|
|
||||||
this.parameterTypes, otherMethod.parameterTypes
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clones the method.
|
* Clones the method.
|
||||||
* @param registerCount This parameter allows you to change the register count of the method.
|
* @param registerCount This parameter allows you to change the register count of the method.
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import app.revanced.patcher.data.BytecodeContext
|
|||||||
import app.revanced.patcher.extensions.MethodFingerprintExtensions.fuzzyPatternScanMethod
|
import app.revanced.patcher.extensions.MethodFingerprintExtensions.fuzzyPatternScanMethod
|
||||||
import app.revanced.patcher.extensions.MethodFingerprintExtensions.fuzzyScanThreshold
|
import app.revanced.patcher.extensions.MethodFingerprintExtensions.fuzzyScanThreshold
|
||||||
import app.revanced.patcher.extensions.parametersEqual
|
import app.revanced.patcher.extensions.parametersEqual
|
||||||
import app.revanced.patcher.extensions.softCompareTo
|
|
||||||
import app.revanced.patcher.fingerprint.Fingerprint
|
import app.revanced.patcher.fingerprint.Fingerprint
|
||||||
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
||||||
import app.revanced.patcher.util.proxy.ClassProxy
|
import app.revanced.patcher.util.proxy.ClassProxy
|
||||||
@@ -14,6 +13,7 @@ import org.jf.dexlib2.iface.Method
|
|||||||
import org.jf.dexlib2.iface.instruction.Instruction
|
import org.jf.dexlib2.iface.instruction.Instruction
|
||||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
import org.jf.dexlib2.iface.reference.StringReference
|
import org.jf.dexlib2.iface.reference.StringReference
|
||||||
|
import org.jf.dexlib2.util.MethodUtil
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the [MethodFingerprint] for a method.
|
* Represents the [MethodFingerprint] for a method.
|
||||||
@@ -297,7 +297,7 @@ data class MethodFingerprintResult(
|
|||||||
*/
|
*/
|
||||||
val mutableMethod by lazy {
|
val mutableMethod by lazy {
|
||||||
mutableClass.methods.first {
|
mutableClass.methods.first {
|
||||||
it.softCompareTo(this.method)
|
MethodUtil.methodSignaturesMatch(it, this.method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package app.revanced.patcher.util.method
|
package app.revanced.patcher.util.method
|
||||||
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.softCompareTo
|
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
import org.jf.dexlib2.iface.Method
|
import org.jf.dexlib2.iface.Method
|
||||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
import org.jf.dexlib2.iface.reference.MethodReference
|
import org.jf.dexlib2.iface.reference.MethodReference
|
||||||
|
import org.jf.dexlib2.util.MethodUtil
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a method from another method via instruction offsets.
|
* Find a method from another method via instruction offsets.
|
||||||
@@ -44,8 +44,8 @@ class MethodWalker internal constructor(
|
|||||||
val proxy = bytecodeContext.findClass(newMethod.definingClass)!!
|
val proxy = bytecodeContext.findClass(newMethod.definingClass)!!
|
||||||
|
|
||||||
val methods = if (walkMutable) proxy.mutableClass.methods else proxy.immutableClass.methods
|
val methods = if (walkMutable) proxy.mutableClass.methods else proxy.immutableClass.methods
|
||||||
currentMethod = methods.first { it ->
|
currentMethod = methods.first {
|
||||||
return@first it.softCompareTo(newMethod)
|
return@first MethodUtil.methodSignaturesMatch(it, newMethod)
|
||||||
}
|
}
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user