mirror of
https://github.com/revanced/revanced-patches.git
synced 2025-12-07 01:51:27 +01:00
fix: Adjusting to new API
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
package app.revanced.patches.all.misc.transformation
|
||||
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.dex.mutable.MutableMethod
|
||||
import app.revanced.util.findMutableMethodOf
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.util.forEachInstructionAsSequence
|
||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||
@@ -11,39 +11,9 @@ fun <T> transformInstructionsPatch(
|
||||
filterMap: (ClassDef, Method, Instruction, Int) -> T?,
|
||||
transform: (MutableMethod, T) -> Unit,
|
||||
) = bytecodePatch {
|
||||
// Returns the patch indices as a Sequence, which will execute lazily.
|
||||
fun findPatchIndices(classDef: ClassDef, method: Method): Sequence<T>? =
|
||||
method.implementation?.instructions?.asSequence()?.withIndex()?.mapNotNull { (index, instruction) ->
|
||||
filterMap(classDef, method, instruction, index)
|
||||
}
|
||||
|
||||
execute {
|
||||
// Find all methods to patch
|
||||
buildMap {
|
||||
classDefs.forEach { classDef ->
|
||||
val methods = buildList {
|
||||
classDef.methods.forEach { method ->
|
||||
// Since the Sequence executes lazily,
|
||||
// using any() results in only calling
|
||||
// filterMap until the first index has been found.
|
||||
if (findPatchIndices(classDef, method)?.any() == true) add(method)
|
||||
}
|
||||
}
|
||||
|
||||
if (methods.isNotEmpty()) {
|
||||
put(classDef, methods)
|
||||
}
|
||||
}
|
||||
}.forEach { (classDef, methods) ->
|
||||
// And finally transform the methods...
|
||||
val mutableClass = classDef.mutable()
|
||||
|
||||
methods.map(mutableClass::findMutableMethodOf).forEach methods@{ mutableMethod ->
|
||||
val patchIndices = findPatchIndices(mutableClass, mutableMethod)?.toCollection(ArrayDeque())
|
||||
?: return@methods
|
||||
|
||||
while (!patchIndices.isEmpty()) transform(mutableMethod, patchIndices.removeLast())
|
||||
}
|
||||
forEachInstructionAsSequence { classDef, method, i, instruction ->
|
||||
transform(method, filterMap(classDef, method, instruction, i) ?: return@forEachInstructionAsSequence)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ val hideAdsPatch = bytecodePatch(
|
||||
execute {
|
||||
// Get obfuscated "enableAds" field from toString method.
|
||||
val enableAdsField = videoUrlReadyToStringFingerprint.let {
|
||||
val strIndex = videoUrlReadyToStringFingerprint.stringMatches!!.last().index
|
||||
val strIndex = videoUrlReadyToStringFingerprint.stringMatches.last().index
|
||||
val fieldIndex = it.method.indexOfFirstInstruction(strIndex, Opcode.IGET_BOOLEAN)
|
||||
it.method.getInstruction<ReferenceInstruction>(fieldIndex).getReference<FieldReference>()!!
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ val enableDebugMenuPatch = bytecodePatch(
|
||||
buildConfigProviderConstructorFingerprint.match(
|
||||
buildConfigProviderToStringFingerprint.classDef
|
||||
).let {
|
||||
val index = it.patternMatch!!.startIndex
|
||||
val index = it.patternMatch.startIndex
|
||||
|
||||
it.method.apply {
|
||||
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
||||
|
||||
@@ -17,7 +17,7 @@ val skipEnergyRechargeAdsPatch = bytecodePatch(
|
||||
.method.apply {
|
||||
val energyField = energyConfigToStringFingerprint.method
|
||||
.findFieldFromToString("energy=")
|
||||
val insertIndex = initializeEnergyConfigFingerprint.patternMatch!!.startIndex
|
||||
val insertIndex = initializeEnergyConfigFingerprint.patternMatch.startIndex
|
||||
|
||||
addInstructions(
|
||||
insertIndex,
|
||||
|
||||
@@ -11,7 +11,7 @@ context(BytecodePatchContext)
|
||||
internal fun Fingerprint.replaceJsonFieldWithBogus(
|
||||
key: String,
|
||||
) {
|
||||
val targetStringIndex = stringMatches!!.first { match -> match.string == key }.index
|
||||
val targetStringIndex = stringMatches.first { match -> match.string == key }.index
|
||||
val targetStringRegister = method.getInstruction<OneRegisterInstruction>(targetStringIndex).registerA
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,7 +12,7 @@ val hideStoriesPatch = bytecodePatch(
|
||||
|
||||
execute {
|
||||
val addStoryMethod = getOrCreateAvatarViewFingerprint.method // Creates Story
|
||||
val addStoryEndIndex = getOrCreateAvatarViewFingerprint.patternMatch!!.endIndex
|
||||
val addStoryEndIndex = getOrCreateAvatarViewFingerprint.patternMatch.endIndex
|
||||
|
||||
// Remove addView of Story.
|
||||
addStoryMethod.removeInstruction(addStoryEndIndex)
|
||||
|
||||
@@ -22,7 +22,7 @@ val enableDeveloperMenuPatch = bytecodePatch(
|
||||
|
||||
execute {
|
||||
with(clearNotificationReceiverFingerprint.method) {
|
||||
indexOfFirstInstructionReversedOrThrow(clearNotificationReceiverFingerprint.stringMatches!!.first().index) {
|
||||
indexOfFirstInstructionReversedOrThrow(clearNotificationReceiverFingerprint.stringMatches.first().index) {
|
||||
val reference = getReference<MethodReference>()
|
||||
opcode in listOf(Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC_RANGE) &&
|
||||
reference?.parameterTypes?.size == 1 &&
|
||||
|
||||
@@ -19,7 +19,7 @@ internal fun editShareLinksPatch(block: MutableMethod.(index: Int, register: Int
|
||||
for (fingerprint in fingerprintsToPatch) {
|
||||
fingerprint.method.apply {
|
||||
val putSharingUrlIndex = indexOfFirstInstruction(
|
||||
permalinkResponseJsonParserFingerprint.stringMatches!!.first().index,
|
||||
permalinkResponseJsonParserFingerprint.stringMatches.first().index,
|
||||
Opcode.IPUT_OBJECT
|
||||
)
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ val removeMetaAIPatch = bytecodePatch(
|
||||
|
||||
execute {
|
||||
getMobileConfigBoolFingerprint.method.apply {
|
||||
val returnIndex = getMobileConfigBoolFingerprint.patternMatch!!.startIndex
|
||||
val returnIndex = getMobileConfigBoolFingerprint.patternMatch.startIndex
|
||||
val returnRegister = getInstruction<OneRegisterInstruction>(returnIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
@@ -42,7 +42,7 @@ val removeMetaAIPatch = bytecodePatch(
|
||||
// Replace placeholder in the extension method.
|
||||
with(extensionMethodFingerprint) {
|
||||
method.replaceInstruction(
|
||||
stringMatches!!.first().index,
|
||||
stringMatches.first().index,
|
||||
"""
|
||||
const-string v1, "$relevantDigits"
|
||||
"""
|
||||
|
||||
@@ -73,7 +73,7 @@ val hideButtons = bytecodePatch(
|
||||
historyMenuItemOfflineTabFingerprint
|
||||
).forEach { fingerprint ->
|
||||
fingerprint.method.apply {
|
||||
val targetIndex = fingerprint.patternMatch!!.startIndex
|
||||
val targetIndex = fingerprint.patternMatch.startIndex
|
||||
val targetRegister = getInstruction<FiveRegisterInstruction>(targetIndex).registerD
|
||||
|
||||
addInstructions(
|
||||
|
||||
@@ -46,7 +46,7 @@ val hideCategoryBar = bytecodePatch(
|
||||
chipCloud = getResourceId(ResourceType.LAYOUT, "chip_cloud")
|
||||
|
||||
chipCloudFingerprint.method.apply {
|
||||
val targetIndex = chipCloudFingerprint.patternMatch!!.endIndex
|
||||
val targetIndex = chipCloudFingerprint.patternMatch.endIndex
|
||||
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
addInstruction(
|
||||
|
||||
@@ -100,7 +100,7 @@ val navigationBarPatch = bytecodePatch(
|
||||
)
|
||||
|
||||
// Set navigation enum and hide navigation buttons.
|
||||
val enumIndex = tabLayoutTextFingerprint.patternMatch!!.startIndex + 3
|
||||
val enumIndex = tabLayoutTextFingerprint.patternMatch.startIndex + 3
|
||||
val enumRegister = getInstruction<OneRegisterInstruction>(enumIndex).registerA
|
||||
val insertEnumIndex = indexOfFirstInstructionOrThrow(Opcode.AND_INT_LIT8) - 2
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ val hideAdsPatch = bytecodePatch(
|
||||
// Filter injected content from API calls out of lists.
|
||||
arrayOf(screenMapperFingerprint, nextPageRepositoryImplFingerprint).forEach {
|
||||
// Index of instruction moving result of BlockPage;->getBlocks(...).
|
||||
val moveGetBlocksResultObjectIndex = it.patternMatch!!.startIndex
|
||||
val moveGetBlocksResultObjectIndex = it.patternMatch.startIndex
|
||||
it.method.apply {
|
||||
val moveInstruction = getInstruction<OneRegisterInstruction>(moveGetBlocksResultObjectIndex)
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ val skipAdsPatch = bytecodePatch(
|
||||
// Force doTrigger() access to public so we can call it from our extension.
|
||||
doTriggerFingerprint.method.accessFlags = AccessFlags.PUBLIC.value;
|
||||
|
||||
val getPlayerIndex = enterServerInsertedAdBreakStateFingerprint.patternMatch!!.startIndex
|
||||
val getPlayerIndex = enterServerInsertedAdBreakStateFingerprint.patternMatch.startIndex
|
||||
enterServerInsertedAdBreakStateFingerprint.method.apply {
|
||||
// Get register that stores VideoPlayer:
|
||||
// invoke-virtual ->getPrimaryPlayer()
|
||||
|
||||
@@ -23,7 +23,7 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "http://baconreader.com/au
|
||||
|
||||
execute {
|
||||
fun Fingerprint.patch(replacementString: String) {
|
||||
val clientIdIndex = stringMatches!!.first().index
|
||||
val clientIdIndex = stringMatches.first().index
|
||||
|
||||
method.apply {
|
||||
val clientIdRegister = getInstruction<OneRegisterInstruction>(clientIdIndex).registerA
|
||||
|
||||
@@ -24,7 +24,7 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "http://rubenmayayo.com")
|
||||
val randomName = (0..100000).random()
|
||||
val userAgent = "$randomName:app.revanced.$randomName:v1.0.0 (by /u/revanced)"
|
||||
buildUserAgentFingerprint.let {
|
||||
val userAgentTemplateIndex = it.stringMatches!!.first().index
|
||||
val userAgentTemplateIndex = it.stringMatches.first().index
|
||||
val register = it.method.getInstruction<OneRegisterInstruction>(userAgentTemplateIndex).registerA
|
||||
|
||||
it.method.replaceInstruction(userAgentTemplateIndex, "const-string v$register, \"$userAgent\"")
|
||||
|
||||
@@ -34,7 +34,7 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "redditisfun://auth") { cl
|
||||
string: String,
|
||||
getReplacementIndex: List<Match.StringMatch>.() -> Int,
|
||||
) = method.apply {
|
||||
val replacementIndex = stringMatches!!.getReplacementIndex()
|
||||
val replacementIndex = stringMatches.getReplacementIndex()
|
||||
val clientIdRegister = getInstruction<OneRegisterInstruction>(replacementIndex).registerA
|
||||
|
||||
replaceInstruction(replacementIndex, "const-string v$clientIdRegister, \"$string\"")
|
||||
|
||||
@@ -11,7 +11,7 @@ val lithoColorHookPatch = bytecodePatch(
|
||||
) {
|
||||
|
||||
execute {
|
||||
var insertionIndex = lithoOnBoundsChangeFingerprint.patternMatch!!.endIndex - 1
|
||||
var insertionIndex = lithoOnBoundsChangeFingerprint.patternMatch.endIndex - 1
|
||||
|
||||
lithoColorOverrideHook = { targetMethodClass, targetMethodName ->
|
||||
lithoOnBoundsChangeFingerprint.method.addInstructions(
|
||||
|
||||
@@ -79,33 +79,41 @@ fun gmsCoreSupportPatch(
|
||||
val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption
|
||||
|
||||
execute {
|
||||
fun transformStringReferences(transform: (str: String) -> String?) = classDefs.forEach {
|
||||
val mutableClass by lazy { it.mutable() }
|
||||
fun transformStringReferences(transform: (str: String) -> String?) {
|
||||
val transformations = mutableListOf<() -> Unit>()
|
||||
|
||||
it.methods.forEach classLoop@{ method ->
|
||||
val implementation = method.implementation ?: return@classLoop
|
||||
classDefs.forEach { classDef ->
|
||||
val mutableClass by lazy { classDef.mutable() }
|
||||
|
||||
val mutableMethod by lazy {
|
||||
mutableClass.methods.first { MethodUtil.methodSignaturesMatch(it, method) }
|
||||
}
|
||||
classDef.methods.forEach classLoop@{ method ->
|
||||
val implementation = method.implementation ?: return@classLoop
|
||||
|
||||
implementation.instructions.forEachIndexed { index, instruction ->
|
||||
val string = ((instruction as? Instruction21c)?.reference as? StringReference)?.string
|
||||
?: return@forEachIndexed
|
||||
val mutableMethod by lazy {
|
||||
mutableClass.methods.first { MethodUtil.methodSignaturesMatch(it, method) }
|
||||
}
|
||||
|
||||
// Apply transformation.
|
||||
val transformedString = transform(string) ?: return@forEachIndexed
|
||||
implementation.instructions.forEachIndexed { index, instruction ->
|
||||
val string = ((instruction as? Instruction21c)?.reference as? StringReference)?.string
|
||||
?: return@forEachIndexed
|
||||
|
||||
mutableMethod.replaceInstruction(
|
||||
index,
|
||||
BuilderInstruction21c(
|
||||
Opcode.CONST_STRING,
|
||||
instruction.registerA,
|
||||
ImmutableStringReference(transformedString),
|
||||
),
|
||||
)
|
||||
// Apply transformation.
|
||||
val transformedString = transform(string) ?: return@forEachIndexed
|
||||
|
||||
transformations += {
|
||||
mutableMethod.replaceInstruction(
|
||||
index,
|
||||
BuilderInstruction21c(
|
||||
Opcode.CONST_STRING,
|
||||
instruction.registerA,
|
||||
ImmutableStringReference(transformedString),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
transformations.forEach { it() }
|
||||
}
|
||||
|
||||
// region Collection of transformations that are applied to all strings.
|
||||
|
||||
@@ -2,11 +2,13 @@ package app.revanced.patches.shared.misc.mapping
|
||||
|
||||
import app.revanced.patcher.InstructionLocation
|
||||
import app.revanced.patcher.LiteralFilter
|
||||
import app.revanced.patcher.extensions.wideLiteral
|
||||
import app.revanced.patcher.literal
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||
import org.w3c.dom.Element
|
||||
import java.util.Collections
|
||||
import java.util.*
|
||||
|
||||
enum class ResourceType(val value: String) {
|
||||
ANIM("anim"),
|
||||
@@ -35,6 +37,9 @@ enum class ResourceType(val value: String) {
|
||||
VALUES("values"),
|
||||
XML("xml");
|
||||
|
||||
operator fun invoke(name: String): Instruction.() -> Boolean =
|
||||
getResourceId(this, name).let { { wideLiteral(it) } }
|
||||
|
||||
companion object {
|
||||
private val VALUE_MAP: Map<String, ResourceType> = entries.associateBy { it.value }
|
||||
|
||||
@@ -77,10 +82,9 @@ fun hasResourceId(type: ResourceType, name: String) = resourceMappings[type.valu
|
||||
fun resourceLiteral(
|
||||
type: ResourceType,
|
||||
name: String,
|
||||
location : InstructionLocation = InstructionLocation.MatchAfterAnywhere()
|
||||
location: InstructionLocation = InstructionLocation.MatchAfterAnywhere()
|
||||
) = literal({ getResourceId(type, name) }, null, location)
|
||||
|
||||
|
||||
val resourceMappingPatch = resourcePatch {
|
||||
execute {
|
||||
// Use a stream of the file, since no modifications are done
|
||||
|
||||
@@ -283,7 +283,7 @@ internal fun spoofVideoStreamsPatch(
|
||||
// If SABR is disabled, it seems 'MediaFetchHotConfig' may no longer need an override (not confirmed).
|
||||
|
||||
val (mediaFetchEnumClass, sabrFieldReference) = with(mediaFetchEnumConstructorFingerprint.method) {
|
||||
val stringIndex = mediaFetchEnumConstructorFingerprint.stringMatches!!.first {
|
||||
val stringIndex = mediaFetchEnumConstructorFingerprint.stringMatches.first {
|
||||
it.string == DISABLED_BY_SABR_STREAMING_URI_STRING
|
||||
}.index
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ val hideAdsPatch = bytecodePatch(
|
||||
val method = findAdStringFingerprint.method
|
||||
|
||||
// Find the ads free string index
|
||||
val stringIndex = findAdStringFingerprint.stringMatches!!.first().index
|
||||
val stringIndex = findAdStringFingerprint.stringMatches.first().index
|
||||
|
||||
// Search backwards from the string to find the `new-instance` (TypeReference) instruction
|
||||
val typeRefIndex = method.indexOfFirstInstructionReversedOrThrow(stringIndex) { this.opcode == Opcode.NEW_INSTANCE }
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package app.revanced.patches.youtube.ad.general
|
||||
|
||||
import app.revanced.patcher.extensions.getInstruction
|
||||
import app.revanced.patcher.extensions.instructions
|
||||
import app.revanced.patcher.extensions.replaceInstruction
|
||||
import app.revanced.patcher.extensions.wideLiteral
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
@@ -17,12 +19,10 @@ import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter
|
||||
import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch
|
||||
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||
import app.revanced.util.findMutableMethodOf
|
||||
import app.revanced.util.forEachInstructionAsSequence
|
||||
import app.revanced.util.injectHideViewCall
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction31i
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
|
||||
|
||||
internal var adAttributionId = -1L
|
||||
private set
|
||||
@@ -84,7 +84,7 @@ val hideAdsPatch = bytecodePatch(
|
||||
)
|
||||
|
||||
execute {
|
||||
// Hide end screen store banner
|
||||
// Hide end screen store banner.
|
||||
|
||||
fullScreenEngagementAdContainerFingerprint.method.apply {
|
||||
val addListIndex = indexOfAddListInstruction(this)
|
||||
@@ -99,42 +99,19 @@ val hideAdsPatch = bytecodePatch(
|
||||
)
|
||||
}
|
||||
|
||||
// Hide ad views
|
||||
// Hide ad views.
|
||||
|
||||
classDefs.forEach { classDef ->
|
||||
classDef.methods.forEach { method ->
|
||||
with(method.implementation) {
|
||||
this?.instructions?.forEachIndexed { index, instruction ->
|
||||
if (instruction.opcode != Opcode.CONST) {
|
||||
return@forEachIndexed
|
||||
}
|
||||
// Instruction to store the id adAttribution into a register
|
||||
if ((instruction as Instruction31i).wideLiteral != adAttributionId) {
|
||||
return@forEachIndexed
|
||||
}
|
||||
forEachInstructionAsSequence { _, method, index, instruction ->
|
||||
if (instruction.opcode != Opcode.CONST) return@forEachInstructionAsSequence
|
||||
if (instruction.wideLiteral != adAttributionId) return@forEachInstructionAsSequence
|
||||
|
||||
val insertIndex = index + 1
|
||||
|
||||
// Call to get the view with the id adAttribution
|
||||
with(instructions.elementAt(insertIndex)) {
|
||||
if (opcode != Opcode.INVOKE_VIRTUAL) {
|
||||
return@forEachIndexed
|
||||
}
|
||||
val insertIndex = index + 1
|
||||
|
||||
// Hide the view
|
||||
val viewRegister = (this as Instruction35c).registerC
|
||||
classDef.mutable()
|
||||
.findMutableMethodOf(method)
|
||||
.injectHideViewCall(
|
||||
insertIndex,
|
||||
viewRegister,
|
||||
EXTENSION_CLASS_DESCRIPTOR,
|
||||
"hideAdAttributionView",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Call to get the view with the id adAttribution,
|
||||
if (method.instructions[insertIndex].opcode != Opcode.INVOKE_VIRTUAL) return@forEachInstructionAsSequence
|
||||
val viewRegister = method.getInstruction<FiveRegisterInstruction>(insertIndex).registerC
|
||||
method.injectHideViewCall(insertIndex, viewRegister, EXTENSION_CLASS_DESCRIPTOR, "hideAdAttributionView")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package app.revanced.patches.youtube.layout.branding.header
|
||||
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.getInstruction
|
||||
import app.revanced.patcher.extensions.wideLiteral
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
@@ -19,7 +20,7 @@ import app.revanced.util.ResourceGroup
|
||||
import app.revanced.util.Utils.trimIndentMultiline
|
||||
import app.revanced.util.copyResources
|
||||
import app.revanced.util.findElementByAttributeValueOrThrow
|
||||
import app.revanced.util.forEachLiteralValueInstruction
|
||||
import app.revanced.util.forEachInstructionAsSequence
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import java.io.File
|
||||
|
||||
@@ -75,12 +76,14 @@ private val changeHeaderBytecodePatch = bytecodePatch {
|
||||
"ytWordmarkHeader",
|
||||
"ytPremiumWordmarkHeader"
|
||||
).forEach { resourceName ->
|
||||
val resourceId = getResourceId(ResourceType.ATTR, resourceName)
|
||||
val id = getResourceId(ResourceType.ATTR, resourceName)
|
||||
|
||||
forEachLiteralValueInstruction(resourceId) { literalIndex ->
|
||||
val register = getInstruction<OneRegisterInstruction>(literalIndex).registerA
|
||||
addInstructions(
|
||||
literalIndex + 1,
|
||||
forEachInstructionAsSequence { _, method, i, instruction ->
|
||||
if (instruction.wideLiteral != id) return@forEachInstructionAsSequence
|
||||
|
||||
val register = method.getInstruction<OneRegisterInstruction>(i).registerA
|
||||
method.addInstructions(
|
||||
i + 1,
|
||||
"""
|
||||
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getHeaderAttributeId(I)I
|
||||
move-result v$register
|
||||
@@ -214,21 +217,24 @@ val changeHeaderPatch = resourcePatch(
|
||||
if (custom != null) {
|
||||
val customFile = File(custom!!.trim())
|
||||
if (!customFile.exists()) {
|
||||
throw PatchException("The custom header path cannot be found: " +
|
||||
customFile.absolutePath
|
||||
throw PatchException(
|
||||
"The custom header path cannot be found: " +
|
||||
customFile.absolutePath
|
||||
)
|
||||
}
|
||||
|
||||
if (!customFile.isDirectory) {
|
||||
throw PatchException("The custom header path must be a folder: "
|
||||
+ customFile.absolutePath)
|
||||
throw PatchException(
|
||||
"The custom header path must be a folder: "
|
||||
+ customFile.absolutePath
|
||||
)
|
||||
}
|
||||
|
||||
var copiedFiles = false
|
||||
|
||||
// For each source folder, copy the files to the target resource directories.
|
||||
customFile.listFiles {
|
||||
file -> file.isDirectory && file.name in targetResourceDirectoryNames
|
||||
customFile.listFiles { file ->
|
||||
file.isDirectory && file.name in targetResourceDirectoryNames
|
||||
}!!.forEach { dpiSourceFolder ->
|
||||
val targetDpiFolder = get("res").resolve(dpiSourceFolder.name)
|
||||
if (!targetDpiFolder.exists()) {
|
||||
@@ -241,8 +247,9 @@ val changeHeaderPatch = resourcePatch(
|
||||
}!!
|
||||
|
||||
if (customFiles.isNotEmpty() && customFiles.size != variants.size) {
|
||||
throw PatchException("Both light/dark mode images " +
|
||||
"must be specified but only found: " + customFiles.map { it.name })
|
||||
throw PatchException(
|
||||
"Both light/dark mode images " +
|
||||
"must be specified but only found: " + customFiles.map { it.name })
|
||||
}
|
||||
|
||||
customFiles.forEach { imgSourceFile ->
|
||||
@@ -254,9 +261,11 @@ val changeHeaderPatch = resourcePatch(
|
||||
}
|
||||
|
||||
if (!copiedFiles) {
|
||||
throw PatchException("Expected to find directories and files: "
|
||||
+ customHeaderResourceFileNames.contentToString()
|
||||
+ "\nBut none were found in the provided option file path: " + customFile.absolutePath)
|
||||
throw PatchException(
|
||||
"Expected to find directories and files: "
|
||||
+ customHeaderResourceFileNames.contentToString()
|
||||
+ "\nBut none were found in the provided option file path: " + customFile.absolutePath
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,26 +2,15 @@ package app.revanced.patches.youtube.layout.hide.general
|
||||
|
||||
import app.revanced.patcher.Fingerprint
|
||||
import app.revanced.patcher.Match
|
||||
import app.revanced.patcher.extensions.addInstruction
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.getInstruction
|
||||
import app.revanced.patcher.extensions.instructions
|
||||
import app.revanced.patcher.extensions.removeInstruction
|
||||
import app.revanced.patcher.extensions.replaceInstruction
|
||||
import app.revanced.patcher.extensions.*
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
import app.revanced.patcher.extensions.ExternalLabel
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||
import app.revanced.patches.shared.misc.mapping.ResourceType
|
||||
import app.revanced.patches.shared.misc.mapping.getResourceId
|
||||
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.InputType
|
||||
import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference
|
||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.shared.misc.settings.preference.TextPreference
|
||||
import app.revanced.patches.shared.misc.settings.preference.*
|
||||
import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter
|
||||
import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch
|
||||
import app.revanced.patches.youtube.misc.navigation.navigationBarHookPatch
|
||||
@@ -32,13 +21,13 @@ import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||
import app.revanced.util.findFreeRegister
|
||||
import app.revanced.util.findInstructionIndicesReversedOrThrow
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||
|
||||
internal var albumCardId = -1L
|
||||
private set
|
||||
@@ -390,7 +379,7 @@ val hideLayoutComponentsPatch = bytecodePatch(
|
||||
// region hide view count
|
||||
|
||||
hideViewCountFingerprint.method.apply {
|
||||
val startIndex = hideViewCountFingerprint.patternMatch!!.startIndex
|
||||
val startIndex = hideViewCountFingerprint.patternMatch.startIndex
|
||||
var returnStringRegister = getInstruction<OneRegisterInstruction>(startIndex).registerA
|
||||
|
||||
// Find the instruction where the text dimension is retrieved.
|
||||
|
||||
@@ -3,6 +3,7 @@ package app.revanced.patches.youtube.layout.hide.shorts
|
||||
import app.revanced.patcher.extensions.addInstruction
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.getInstruction
|
||||
import app.revanced.patcher.extensions.wideLiteral
|
||||
import app.revanced.patcher.patch.booleanOption
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
@@ -17,19 +18,10 @@ import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter
|
||||
import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch
|
||||
import app.revanced.patches.youtube.misc.navigation.navigationBarHookPatch
|
||||
import app.revanced.patches.youtube.misc.playservice.is_19_41_or_greater
|
||||
import app.revanced.patches.youtube.misc.playservice.is_20_07_or_greater
|
||||
import app.revanced.patches.youtube.misc.playservice.is_20_22_or_greater
|
||||
import app.revanced.patches.youtube.misc.playservice.is_20_45_or_greater
|
||||
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
|
||||
import app.revanced.patches.youtube.misc.playservice.*
|
||||
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||
import app.revanced.util.findElementByAttributeValueOrThrow
|
||||
import app.revanced.util.forEachLiteralValueInstruction
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.removeFromParent
|
||||
import app.revanced.util.returnLate
|
||||
import app.revanced.util.*
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import java.util.logging.Logger
|
||||
@@ -194,16 +186,18 @@ val hideShortsComponentsPatch = bytecodePatch(
|
||||
execute {
|
||||
addLithoFilter(FILTER_CLASS_DESCRIPTOR)
|
||||
|
||||
forEachLiteralValueInstruction(
|
||||
getResourceId(ResourceType.DIMEN, "reel_player_right_pivot_v2_size")
|
||||
) { literalInstructionIndex ->
|
||||
val targetIndex = indexOfFirstInstructionOrThrow(literalInstructionIndex) {
|
||||
val id = getResourceId(ResourceType.DIMEN, "reel_player_right_pivot_v2_size")
|
||||
|
||||
forEachInstructionAsSequence { _, method, i, instruction ->
|
||||
if (instruction.wideLiteral != id) return@forEachInstructionAsSequence
|
||||
|
||||
val targetIndex = method.indexOfFirstInstructionOrThrow(i) {
|
||||
getReference<MethodReference>()?.name == "getDimensionPixelSize"
|
||||
} + 1
|
||||
|
||||
val sizeRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||
val sizeRegister = method.getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
method.addInstructions(
|
||||
targetIndex + 1,
|
||||
"""
|
||||
invoke-static { v$sizeRegister }, $FILTER_CLASS_DESCRIPTOR->getSoundButtonSize(I)I
|
||||
@@ -212,6 +206,7 @@ val hideShortsComponentsPatch = bytecodePatch(
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
// endregion
|
||||
|
||||
// region Hide the navigation bar.
|
||||
@@ -226,7 +221,7 @@ val hideShortsComponentsPatch = bytecodePatch(
|
||||
addInstruction(
|
||||
insertIndex,
|
||||
"invoke-static {v$viewRegister}," +
|
||||
" $FILTER_CLASS_DESCRIPTOR->setNavigationBar(Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;)V",
|
||||
" $FILTER_CLASS_DESCRIPTOR->setNavigationBar(Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;)V",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,8 @@ val backgroundPlaybackPatch = bytecodePatch(
|
||||
}
|
||||
|
||||
val settingsBooleanIndex = booleanCalls.elementAt(1).index
|
||||
val settingsBooleanMethod by navigate(this).to(settingsBooleanIndex)
|
||||
|
||||
val settingsBooleanMethod = navigate(this).to(settingsBooleanIndex).stop()
|
||||
|
||||
settingsBooleanMethod.returnEarly(true)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ internal val fixBackToExitGesturePatch = bytecodePatch(
|
||||
|
||||
scrollPositionFingerprint.let {
|
||||
navigate(it.originalMethod)
|
||||
.to(it.patternMatch!!.startIndex + 1)
|
||||
.to(it.patternMatch.startIndex + 1)
|
||||
.stop().apply {
|
||||
val index = indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.INVOKE_VIRTUAL && getReference<MethodReference>()?.definingClass ==
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package app.revanced.patches.youtube.misc.fix.playbackspeed
|
||||
|
||||
import app.revanced.patcher.extensions.ExternalLabel
|
||||
import app.revanced.patcher.extensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.getInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.extensions.ExternalLabel
|
||||
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch
|
||||
import app.revanced.patches.youtube.misc.playservice.is_19_34_or_greater
|
||||
@@ -29,7 +29,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
* 6. Resume the video
|
||||
* 7. Playback speed will incorrectly change to 1.0x.
|
||||
*/
|
||||
val fixPlaybackSpeedWhilePlayingPatch = bytecodePatch{
|
||||
val fixPlaybackSpeedWhilePlayingPatch = bytecodePatch {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
playerTypeHookPatch,
|
||||
@@ -1,11 +1,7 @@
|
||||
package app.revanced.patches.youtube.misc.navigation
|
||||
|
||||
import app.revanced.patcher.*
|
||||
import app.revanced.patcher.InstructionLocation.MatchAfterWithin
|
||||
import app.revanced.patcher.checkCast
|
||||
import app.revanced.patcher.fingerprint
|
||||
import app.revanced.patcher.methodCall
|
||||
import app.revanced.patcher.opcode
|
||||
import app.revanced.patcher.string
|
||||
import app.revanced.patches.shared.misc.mapping.ResourceType
|
||||
import app.revanced.patches.shared.misc.mapping.resourceLiteral
|
||||
import app.revanced.patches.youtube.layout.buttons.navigation.navigationButtonsPatch
|
||||
@@ -79,6 +75,7 @@ internal val navigationEnumFingerprint = fingerprint {
|
||||
"TAB_ACTIVITY",
|
||||
"VIDEO_LIBRARY_WHITE",
|
||||
"INCOGNITO_CIRCLE",
|
||||
"UNKNOWN" // Required to distinguish from patch extension class.
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package app.revanced.patches.youtube.misc.navigation
|
||||
|
||||
import app.revanced.patcher.dex.mutable.MutableMethod
|
||||
import app.revanced.patcher.dex.mutable.MutableMethod.Companion.toMutable
|
||||
import app.revanced.patcher.extensions.addInstruction
|
||||
import app.revanced.patcher.extensions.addInstructions
|
||||
import app.revanced.patcher.extensions.getInstruction
|
||||
@@ -7,16 +9,10 @@ import app.revanced.patcher.extensions.instructions
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
import app.revanced.patcher.dex.mutable.MutableMethod
|
||||
import app.revanced.patcher.dex.mutable.MutableMethod.Companion.toMutable
|
||||
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
|
||||
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch
|
||||
import app.revanced.patches.youtube.misc.playservice.is_19_35_or_greater
|
||||
import app.revanced.patches.youtube.misc.playservice.is_20_21_or_greater
|
||||
import app.revanced.patches.youtube.misc.playservice.is_20_28_or_greater
|
||||
import app.revanced.patches.youtube.misc.playservice.is_20_39_or_greater
|
||||
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
|
||||
import app.revanced.patches.youtube.misc.playservice.*
|
||||
import app.revanced.patches.youtube.shared.mainActivityOnBackPressedFingerprint
|
||||
import app.revanced.util.ResourceGroup
|
||||
import app.revanced.util.copyResources
|
||||
@@ -74,7 +70,7 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig
|
||||
addInstruction(
|
||||
insertIndex,
|
||||
"invoke-static { v$register }, " +
|
||||
"$EXTENSION_CLASS_DESCRIPTOR->${hook.methodName}(${hook.parameters})V",
|
||||
"$EXTENSION_CLASS_DESCRIPTOR->${hook.methodName}(${hook.parameters})V",
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -84,7 +80,7 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig
|
||||
val navigationEnumClassName = navigationEnumFingerprint.classDef.type
|
||||
addHook(NavigationHook.SET_LAST_APP_NAVIGATION_ENUM) {
|
||||
opcode == Opcode.INVOKE_STATIC &&
|
||||
getReference<MethodReference>()?.definingClass == navigationEnumClassName
|
||||
getReference<MethodReference>()?.definingClass == navigationEnumClassName
|
||||
}
|
||||
|
||||
// Hook the creation of navigation tab views.
|
||||
@@ -206,7 +202,7 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig
|
||||
navigationBarHookCallbackFingerprint.method.addInstruction(
|
||||
0,
|
||||
"invoke-static { p0, p1 }, $extensionClassDescriptor->navigationTabCreated" +
|
||||
"(${EXTENSION_NAVIGATION_BUTTON_DESCRIPTOR}Landroid/view/View;)V",
|
||||
"(${EXTENSION_NAVIGATION_BUTTON_DESCRIPTOR}Landroid/view/View;)V",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -221,21 +217,19 @@ val navigationBarHookPatch = bytecodePatch(description = "Hooks the active navig
|
||||
val cairoNotificationEnumReference = imageEnumConstructorFingerprint
|
||||
.instructionMatches.last().getInstruction<ReferenceInstruction>().reference
|
||||
|
||||
setEnumMapFingerprint.let {
|
||||
it.method.apply {
|
||||
val setEnumIntegerIndex = it.instructionMatches.last().index
|
||||
val enumMapRegister = getInstruction<FiveRegisterInstruction>(setEnumIntegerIndex).registerC
|
||||
val insertIndex = setEnumIntegerIndex + 1
|
||||
val freeRegister = findFreeRegister(insertIndex, enumMapRegister)
|
||||
setEnumMapFingerprint.method.apply {
|
||||
val setEnumIntegerIndex = setEnumMapFingerprint.instructionMatches.last().index
|
||||
val enumMapRegister = getInstruction<FiveRegisterInstruction>(setEnumIntegerIndex).registerC
|
||||
val insertIndex = setEnumIntegerIndex + 1
|
||||
val freeRegister = findFreeRegister(insertIndex, enumMapRegister)
|
||||
|
||||
addInstructions(
|
||||
insertIndex,
|
||||
"""
|
||||
sget-object v$freeRegister, $cairoNotificationEnumReference
|
||||
invoke-static { v$enumMapRegister, v$freeRegister }, $EXTENSION_CLASS_DESCRIPTOR->setCairoNotificationFilledIcon(Ljava/util/EnumMap;Ljava/lang/Enum;)V
|
||||
"""
|
||||
)
|
||||
}
|
||||
addInstructions(
|
||||
insertIndex,
|
||||
"""
|
||||
sget-object v$freeRegister, $cairoNotificationEnumReference
|
||||
invoke-static { v$enumMapRegister, v$freeRegister }, $EXTENSION_CLASS_DESCRIPTOR->setCairoNotificationFilledIcon(Ljava/util/EnumMap;Ljava/lang/Enum;)V
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,8 +86,10 @@ fun Method.findFreeRegister(startIndex: Int, vararg registersToExclude: Int): In
|
||||
return bestFreeRegisterFound
|
||||
}
|
||||
// This method is simple and does not follow branching.
|
||||
throw IllegalArgumentException("Encountered a branch statement before " +
|
||||
"a free register could be found from startIndex: $startIndex")
|
||||
throw IllegalArgumentException(
|
||||
"Encountered a branch statement before " +
|
||||
"a free register could be found from startIndex: $startIndex"
|
||||
)
|
||||
}
|
||||
|
||||
if (instruction.isReturnInstruction) {
|
||||
@@ -104,8 +106,10 @@ fun Method.findFreeRegister(startIndex: Int, vararg registersToExclude: Int): In
|
||||
|
||||
// Somehow every method register was read from before any register was wrote to.
|
||||
// In practice this never occurs.
|
||||
throw IllegalArgumentException("Could not find a free register from startIndex: " +
|
||||
"$startIndex excluding: $registersToExclude")
|
||||
throw IllegalArgumentException(
|
||||
"Could not find a free register from startIndex: " +
|
||||
"$startIndex excluding: $registersToExclude"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +174,7 @@ internal val Instruction.isReturnInstruction: Boolean
|
||||
*
|
||||
* @param fieldName The name of the field to find. Partial matches are allowed.
|
||||
*/
|
||||
private fun Method.findInstructionIndexFromToString(fieldName: String) : Int {
|
||||
private fun Method.findInstructionIndexFromToString(fieldName: String): Int {
|
||||
val stringIndex = indexOfFirstInstruction {
|
||||
val reference = getReference<StringReference>()
|
||||
reference?.string?.contains(fieldName) == true
|
||||
@@ -210,7 +214,8 @@ private fun Method.findInstructionIndexFromToString(fieldName: String) : Int {
|
||||
val fieldSetOpcode = getInstruction(fieldSetIndex).opcode
|
||||
if (fieldSetOpcode == MOVE_RESULT ||
|
||||
fieldSetOpcode == MOVE_RESULT_WIDE ||
|
||||
fieldSetOpcode == MOVE_RESULT_OBJECT) {
|
||||
fieldSetOpcode == MOVE_RESULT_OBJECT
|
||||
) {
|
||||
fieldSetIndex--
|
||||
}
|
||||
|
||||
@@ -223,7 +228,7 @@ private fun Method.findInstructionIndexFromToString(fieldName: String) : Int {
|
||||
* @param fieldName The name of the field to find. Partial matches are allowed.
|
||||
*/
|
||||
context(BytecodePatchContext)
|
||||
internal fun Method.findMethodFromToString(fieldName: String) : MutableMethod {
|
||||
internal fun Method.findMethodFromToString(fieldName: String): MutableMethod {
|
||||
val methodUsageIndex = findInstructionIndexFromToString(fieldName)
|
||||
return navigate(this).to(methodUsageIndex).stop()
|
||||
}
|
||||
@@ -233,7 +238,7 @@ internal fun Method.findMethodFromToString(fieldName: String) : MutableMethod {
|
||||
*
|
||||
* @param fieldName The name of the field to find. Partial matches are allowed.
|
||||
*/
|
||||
internal fun Method.findFieldFromToString(fieldName: String) : FieldReference {
|
||||
internal fun Method.findFieldFromToString(fieldName: String): FieldReference {
|
||||
val methodUsageIndex = findInstructionIndexFromToString(fieldName)
|
||||
return getInstruction<ReferenceInstruction>(methodUsageIndex).getReference<FieldReference>()!!
|
||||
}
|
||||
@@ -792,36 +797,34 @@ internal fun MutableMethod.insertLiteralOverride(literalIndex: Int, override: Bo
|
||||
}
|
||||
|
||||
/**
|
||||
* Called for _all_ methods with the given literal value.
|
||||
* Method indices are iterated from last to first.
|
||||
* Iterates all instructions as sequence in all methods of all classes in the [BytecodePatchContext].
|
||||
* The instructions are provided in reverse order (last to first).
|
||||
* The [block] is invoked after collecting all instructions to avoid concurrent modification issues.
|
||||
*/
|
||||
fun BytecodePatchContext.forEachLiteralValueInstruction(
|
||||
literal: Long,
|
||||
block: MutableMethod.(matchingIndex: Int) -> Unit,
|
||||
fun BytecodePatchContext.forEachInstructionAsSequence(
|
||||
block: (classDef: MutableClassDef, method: MutableMethod, matchingIndex: Int, instruction: Instruction) -> Unit,
|
||||
) {
|
||||
val matchingIndexes = ArrayList<Int>()
|
||||
classDefs.asSequence().flatMap { classDef ->
|
||||
val mutableClassDef by lazy { classDef.mutable() }
|
||||
|
||||
classDefs.forEach { classDef ->
|
||||
classDef.methods.forEach { method ->
|
||||
method.implementation?.instructions?.let { instructions ->
|
||||
matchingIndexes.clear()
|
||||
classDef.methods.asSequence().flatMap { method ->
|
||||
val instructions =
|
||||
method.instructionsOrNull as? List<Instruction> ?: return@flatMap emptySequence<() -> Unit>()
|
||||
|
||||
instructions.forEachIndexed { index, instruction ->
|
||||
if ((instruction as? WideLiteralInstruction)?.wideLiteral == literal) {
|
||||
matchingIndexes.add(index)
|
||||
}
|
||||
}
|
||||
val mutableMethod by lazy { mutableClassDef.findMutableMethodOf(method) }
|
||||
|
||||
if (matchingIndexes.isNotEmpty()) {
|
||||
val mutableMethod = classDef.mutable().findMutableMethodOf(method)
|
||||
matchingIndexes.asReversed().forEach { index ->
|
||||
block.invoke(mutableMethod, index)
|
||||
}
|
||||
}
|
||||
instructions.asReversed().asSequence().mapIndexed { index, instruction ->
|
||||
{
|
||||
block(
|
||||
mutableClassDef,
|
||||
mutableMethod,
|
||||
instructions.size - 1 - index,
|
||||
instruction
|
||||
)
|
||||
} // Reverse indices again.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}.forEach { it() }
|
||||
}
|
||||
|
||||
private const val RETURN_TYPE_MISMATCH = "Mismatch between override type and Method return type"
|
||||
@@ -1090,7 +1093,7 @@ fun MutableMethod.returnLate(value: Void?) {
|
||||
}
|
||||
|
||||
private fun MutableMethod.overrideReturnValue(value: String, returnLate: Boolean) {
|
||||
val instructions = if (returnType == "Ljava/lang/String;" || returnType == "Ljava/lang/CharSequence;" ) {
|
||||
val instructions = if (returnType == "Ljava/lang/String;" || returnType == "Ljava/lang/CharSequence;") {
|
||||
"""
|
||||
const-string v0, "$value"
|
||||
return-object v0
|
||||
|
||||
Reference in New Issue
Block a user