a couple more fixes
This commit is contained in:
parent
a8572bd4c7
commit
4a1d850bd4
34 changed files with 184 additions and 155 deletions
|
|
@ -7,13 +7,16 @@ 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
|
||||
|
||||
@Deprecated(
|
||||
"Use forEachInstructionAsSequence directly within a bytecodePatch", ReplaceWith(
|
||||
"bytecodePatch { apply { forEachInstructionAsSequence(filterMap, transform) } }",
|
||||
"app.revanced.util.forEachInstructionAsSequence",
|
||||
"app.revanced.patcher.patch.bytecodePatch",
|
||||
)
|
||||
)
|
||||
fun <T> transformInstructionsPatch(
|
||||
filterMap: (ClassDef, Method, Instruction, Int) -> T?,
|
||||
transform: (MutableMethod, T) -> Unit,
|
||||
) = bytecodePatch {
|
||||
apply {
|
||||
forEachInstructionAsSequence { classDef, method, i, instruction ->
|
||||
transform(method, filterMap(classDef, method, instruction, i) ?: return@forEachInstructionAsSequence)
|
||||
}
|
||||
}
|
||||
apply { forEachInstructionAsSequence(filterMap, transform) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import app.revanced.patcher.patch.bytecodePatch
|
|||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Suppress("unused")
|
||||
val hideSuggestedContent = bytecodePatch(
|
||||
val hideSuggestedContentPatch = bytecodePatch(
|
||||
name = "Hide suggested content",
|
||||
description = "Hides suggested stories, reels, threads and survey from feed (Suggested posts will still be shown).",
|
||||
use = false,
|
||||
|
|
@ -1,9 +1,6 @@
|
|||
package app.revanced.patches.music.misc.androidauto
|
||||
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.music.misc.settings.settingsPatch
|
||||
import app.revanced.util.returnEarly
|
||||
|
||||
@Deprecated("This patch is useless by itself and has been merged into another patch.", ReplaceWith("unlockAndroidAutoMediaBrowserPatch"))
|
||||
@Suppress("unused")
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import app.revanced.patcher.extensions.replaceInstruction
|
|||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Suppress("unused")
|
||||
val signatureDetectionPatch = bytecodePatch(
|
||||
description = "Disables detection of incorrect signature.",
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package app.revanced.patches.photomath.misc.unlock.bookpoint
|
|||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.util.returnEarly
|
||||
|
||||
@Suppress("unused")
|
||||
val enableBookpointPatch = bytecodePatch(
|
||||
description = "Enables textbook access",
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package app.revanced.patches.reddit.ad.comments
|
|||
import app.revanced.patcher.extensions.replaceInstructions
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
|
||||
@Suppress("unused")
|
||||
val hideCommentAdsPatch = bytecodePatch(
|
||||
description = "Removes ads in the comments."
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -60,34 +60,41 @@ internal fun sanitizeSharingLinksPatch(
|
|||
},
|
||||
)
|
||||
|
||||
fun Match.hook(
|
||||
getInsertIndex: List<Int>.() -> Int,
|
||||
getUrlRegister: MutableMethod.(insertIndex: Int) -> Int,
|
||||
) {
|
||||
val insertIndex = indices[0].getInsertIndex()
|
||||
val urlRegister = method.getUrlRegister(insertIndex)
|
||||
|
||||
fun Match.hookUrlString(matchIndex: Int) {
|
||||
val index = get(matchIndex)
|
||||
val urlRegister = method.getInstruction<OneRegisterInstruction>(index).registerA
|
||||
|
||||
method.addInstructions(
|
||||
insertIndex,
|
||||
index + 1,
|
||||
"""
|
||||
invoke-static {v$urlRegister}, $EXTENSION_CLASS_DESCRIPTOR->sanitize(Ljava/lang/String;)Ljava/lang/String;
|
||||
invoke-static { v$urlRegister }, $EXTENSION_CLASS_DESCRIPTOR->sanitize(Ljava/lang/String;)Ljava/lang/String;
|
||||
move-result-object v$urlRegister
|
||||
""",
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
// YouTube share sheet.\
|
||||
youTubeShareSheetMethodMatch.hook(getInsertIndex = { first() + 1 }) { insertIndex ->
|
||||
getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
|
||||
fun Match.hookIntentPutExtra(matchIndex: Int) {
|
||||
val index = get(matchIndex)
|
||||
val urlRegister = method.getInstruction<FiveRegisterInstruction>(index).registerE
|
||||
|
||||
method.addInstructionsAtControlFlowLabel(
|
||||
index,
|
||||
"""
|
||||
invoke-static { v$urlRegister }, $EXTENSION_CLASS_DESCRIPTOR->sanitize(Ljava/lang/String;)Ljava/lang/String;
|
||||
move-result-object v$urlRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
// YouTube share sheet copy link.
|
||||
youTubeCopyTextMethodMatch.hookUrlString(0)
|
||||
|
||||
// YouTube share sheet other apps.
|
||||
youTubeShareSheetMethodMatch.hookIntentPutExtra(3)
|
||||
|
||||
// Native system share sheet.
|
||||
youTubeSystemShareSheetMethodMatch.hook(getInsertIndex = { last() }) { insertIndex ->
|
||||
getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
|
||||
}
|
||||
|
||||
youTubeCopyTextMethodMatch.hook(getInsertIndex = { first() + 2 }) { insertIndex ->
|
||||
getInstruction<TwoRegisterInstruction>(insertIndex - 2).registerA
|
||||
}
|
||||
youTubeSystemShareSheetMethodMatch.hookIntentPutExtra(3)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ private val addGiveKudosButtonToLayoutPatch = resourcePatch {
|
|||
}
|
||||
|
||||
@Suppress("unused")
|
||||
val addGiveGroupKudosButtonToGroupActivity = bytecodePatch(
|
||||
val addGiveGroupKudosButtonToGroupActivityPatch = bytecodePatch(
|
||||
name = "Add 'Give Kudos' button to 'Group Activity'",
|
||||
description = "Adds a button that triggers the same action as shaking your phone would.",
|
||||
) {
|
||||
|
|
@ -4,7 +4,7 @@ import app.revanced.patcher.extensions.addInstruction
|
|||
import app.revanced.patcher.extensions.instructions
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.tiktok.misc.settings.Settings
|
||||
import app.revanced.patches.tiktok.misc.settings.settingsPatch
|
||||
import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadMethod
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
|
@ -19,7 +19,7 @@ val feedFilterPatch = bytecodePatch(
|
|||
) {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
Settings,
|
||||
settingsPatch,
|
||||
)
|
||||
|
||||
compatibleWith(
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package app.revanced.patches.tiktok.interaction.downloads
|
|||
import app.revanced.patcher.extensions.*
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.tiktok.misc.settings.Settings
|
||||
import app.revanced.patches.tiktok.misc.settings.settingsPatch
|
||||
import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadMethod
|
||||
import app.revanced.util.findInstructionIndicesReversedOrThrow
|
||||
import app.revanced.util.getReference
|
||||
|
|
@ -15,12 +15,13 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
|||
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/tiktok/download/DownloadsPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
val Downloads = bytecodePatch(
|
||||
val downloadsPatch = bytecodePatch(
|
||||
name = "Downloads",
|
||||
description = "Removes download restrictions and changes the default path to download to.",
|
||||
) {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
Settings,
|
||||
settingsPatch,
|
||||
)
|
||||
|
||||
compatibleWith(
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
|||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/extension/tiktok/settings/TikTokActivityHook;"
|
||||
|
||||
val Settings = bytecodePatch(
|
||||
val settingsPatch = bytecodePatch(
|
||||
name = "Settings",
|
||||
description = "Adds ReVanced settings to TikTok.",
|
||||
) {
|
||||
dependsOn(sharedExtensionPatch, addBrandLicensePatch)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import app.revanced.patcher.extensions.getInstruction
|
|||
import app.revanced.patcher.firstMutableMethod
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.tiktok.misc.settings.Settings
|
||||
import app.revanced.patches.tiktok.misc.settings.settingsPatch
|
||||
import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadMethod
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
|
@ -21,7 +21,7 @@ val sIMSpoofPatch = bytecodePatch(
|
|||
) {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
Settings,
|
||||
settingsPatch,
|
||||
)
|
||||
|
||||
compatibleWith(
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import app.revanced.patches.all.misc.resources.addResourcesPatch
|
|||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.twitch.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.twitch.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.twitch.misc.settings.Settings
|
||||
import app.revanced.patches.twitch.misc.settings.settingsPatch
|
||||
|
||||
@Suppress("unused")
|
||||
val blockAudioAdsPatch = bytecodePatch(
|
||||
|
|
@ -18,7 +18,7 @@ val blockAudioAdsPatch = bytecodePatch(
|
|||
) {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
Settings,
|
||||
settingsPatch,
|
||||
addResourcesPatch,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import app.revanced.patches.shared.misc.settings.preference.ListPreference
|
|||
import app.revanced.patches.twitch.ad.video.blockVideoAdsPatch
|
||||
import app.revanced.patches.twitch.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.twitch.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.twitch.misc.settings.Settings
|
||||
import app.revanced.patches.twitch.misc.settings.settingsPatch
|
||||
|
||||
@Suppress("unused")
|
||||
val blockEmbeddedAdsPatch = bytecodePatch(
|
||||
|
|
@ -17,7 +17,7 @@ val blockEmbeddedAdsPatch = bytecodePatch(
|
|||
dependsOn(
|
||||
blockVideoAdsPatch,
|
||||
sharedExtensionPatch,
|
||||
Settings,
|
||||
settingsPatch,
|
||||
)
|
||||
|
||||
compatibleWith("tv.twitch.android.app"("16.9.1", "25.3.0"))
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import app.revanced.patches.twitch.ad.shared.util.ReturnMethod
|
|||
import app.revanced.patches.twitch.ad.shared.util.adPatch
|
||||
import app.revanced.patches.twitch.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.twitch.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.twitch.misc.settings.Settings
|
||||
import app.revanced.patches.twitch.misc.settings.settingsPatch
|
||||
|
||||
@Suppress("ObjectPropertyName")
|
||||
val blockVideoAdsPatch = bytecodePatch(
|
||||
|
|
@ -24,7 +24,7 @@ val blockVideoAdsPatch = bytecodePatch(
|
|||
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
Settings,
|
||||
settingsPatch,
|
||||
addResourcesPatch,
|
||||
adPatch(conditionCall, skipLabelName) { createConditionInstructions, blockMethods ->
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import app.revanced.patches.all.misc.resources.addResourcesPatch
|
|||
import app.revanced.patches.shared.misc.settings.preference.ListPreference
|
||||
import app.revanced.patches.twitch.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.twitch.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.twitch.misc.settings.Settings
|
||||
import app.revanced.patches.twitch.misc.settings.settingsPatch
|
||||
|
||||
@Suppress("unused")
|
||||
val showDeletedMessagesPatch = bytecodePatch(
|
||||
|
|
@ -19,7 +19,7 @@ val showDeletedMessagesPatch = bytecodePatch(
|
|||
) {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
Settings,
|
||||
settingsPatch,
|
||||
addResourcesPatch,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import app.revanced.patches.all.misc.resources.addResources
|
|||
import app.revanced.patches.all.misc.resources.addResourcesPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.twitch.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.twitch.misc.settings.Settings
|
||||
import app.revanced.patches.twitch.misc.settings.settingsPatch
|
||||
|
||||
@Suppress("unused")
|
||||
val autoClaimChannelPointsPatch = bytecodePatch(
|
||||
|
|
@ -17,7 +17,7 @@ val autoClaimChannelPointsPatch = bytecodePatch(
|
|||
description = "Automatically claim Channel Points.",
|
||||
) {
|
||||
dependsOn(
|
||||
Settings,
|
||||
settingsPatch,
|
||||
addResourcesPatch,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import app.revanced.patches.all.misc.resources.addResourcesPatch
|
|||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.twitch.misc.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.twitch.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.twitch.misc.settings.Settings
|
||||
import app.revanced.patches.twitch.misc.settings.settingsPatch
|
||||
|
||||
@Suppress("ObjectPropertyName")
|
||||
val debugModePatch = bytecodePatch(
|
||||
|
|
@ -17,7 +17,7 @@ val debugModePatch = bytecodePatch(
|
|||
) {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
Settings,
|
||||
settingsPatch,
|
||||
addResourcesPatch,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ fun addSettingPreference(screen: BasePreference) {
|
|||
preferences += screen
|
||||
}
|
||||
|
||||
val Settings = bytecodePatch(
|
||||
val settingsPatch = bytecodePatch(
|
||||
name = "Settings",
|
||||
description = "Adds settings menu to Twitch.",
|
||||
) {
|
||||
dependsOn(
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ 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.firstMutableMethod
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
import app.revanced.patches.all.misc.resources.addResources
|
||||
|
|
@ -94,21 +95,25 @@ val hideAdsPatch = bytecodePatch(
|
|||
replaceInstruction(
|
||||
addListIndex,
|
||||
"invoke-static { v$listRegister, v$objectRegister }, $EXTENSION_CLASS_DESCRIPTOR" +
|
||||
"->hideEndScreenStoreBanner(Ljava/util/List;Ljava/lang/Object;)V",
|
||||
"->hideEndScreenStoreBanner(Ljava/util/List;Ljava/lang/Object;)V",
|
||||
)
|
||||
}
|
||||
|
||||
// Hide ad views.
|
||||
|
||||
forEachInstructionAsSequence { _, method, index, instruction ->
|
||||
if (instruction.opcode != Opcode.CONST) return@forEachInstructionAsSequence
|
||||
if (instruction.wideLiteral != adAttributionId) return@forEachInstructionAsSequence
|
||||
forEachInstructionAsSequence({ _, method, instruction, index ->
|
||||
if (instruction.opcode != Opcode.CONST) return@forEachInstructionAsSequence null
|
||||
if (instruction.wideLiteral != adAttributionId) return@forEachInstructionAsSequence null
|
||||
|
||||
val insertIndex = index + 1
|
||||
|
||||
// Call to get the view with the id adAttribution,
|
||||
if (method.instructions[insertIndex].opcode != Opcode.INVOKE_VIRTUAL) return@forEachInstructionAsSequence
|
||||
// Call to get the view with the id adAttribution.
|
||||
if (method.instructions.elementAt(insertIndex).opcode != Opcode.INVOKE_VIRTUAL) return@forEachInstructionAsSequence null
|
||||
val viewRegister = method.getInstruction<FiveRegisterInstruction>(insertIndex).registerC
|
||||
|
||||
return@forEachInstructionAsSequence insertIndex to viewRegister
|
||||
|
||||
}) { method, (insertIndex, viewRegister) ->
|
||||
method.injectHideViewCall(insertIndex, viewRegister, EXTENSION_CLASS_DESCRIPTOR, "hideAdAttributionView")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,8 @@ private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/
|
|||
internal const val BUTTON_DESCRIPTOR = "Lapp/revanced/extension/youtube/videoplayer/ExternalDownloadButton;"
|
||||
|
||||
@Suppress("unused")
|
||||
val Downloads = bytecodePatch(
|
||||
val downloadsPatch = bytecodePatch(
|
||||
name = "Downloads",
|
||||
description = "Adds support to download videos with an external downloader app " +
|
||||
"using the in-app download button or a video player action button.",
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -112,9 +112,9 @@ internal val BytecodePatchContext.seekbarTappingMethodMatch by composingFirstMet
|
|||
Int.MAX_VALUE.toLong()(),
|
||||
allOf(Opcode.NEW_INSTANCE(), type("Landroid/graphics/Point;")),
|
||||
after(method { toString() == "Landroid/graphics/Point;-><init>(II)V" }),
|
||||
after(method { toString() == "Landroid/view/MotionEvent;->getX()F" }),
|
||||
after(method { toString() == "Lj$/util/Optional;->of(Ljava/lang/Object;)Lj$/util/Optional;" }),
|
||||
after(Opcode.MOVE_RESULT_OBJECT()),
|
||||
after(allOf(Opcode.IPUT_OBJECT(), field { type == "Lj\$/util/Optional;" })),
|
||||
after(allOf(Opcode.IPUT_OBJECT(), field { type == "Lj$/util/Optional;" })),
|
||||
afterAtMost(10, Opcode.INVOKE_VIRTUAL()),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
|
|||
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
||||
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||
import app.revanced.patches.youtube.shared.seekbarMethod
|
||||
import app.revanced.patches.youtube.shared.seekbarOnDrawMethodMatch
|
||||
import app.revanced.patches.youtube.shared.getSeekbarOnDrawMethodMatch
|
||||
import app.revanced.util.insertLiteralOverride
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/HideSeekbarPatch;"
|
||||
|
|
@ -38,7 +38,7 @@ val hideSeekbarPatch = bytecodePatch(
|
|||
SwitchPreference("revanced_fullscreen_large_seekbar"),
|
||||
)
|
||||
|
||||
seekbarMethod.immutableClassDef.seekbarOnDrawMethodMatch.method.addInstructionsWithLabels(
|
||||
seekbarMethod.immutableClassDef.getSeekbarOnDrawMethodMatch().method.addInstructionsWithLabels(
|
||||
0,
|
||||
"""
|
||||
const/4 v0, 0x0
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ package app.revanced.patches.youtube.interaction.seekbar
|
|||
import app.revanced.patcher.patch.bytecodePatch
|
||||
|
||||
@Suppress("unused")
|
||||
val Seekbar = bytecodePatch(
|
||||
val seekbarPatch = bytecodePatch(
|
||||
name = "Seekbar",
|
||||
description = "Adds options to disable precise seeking when swiping up on the seekbar, " +
|
||||
"slide to seek instead of playing at 2x speed when pressing and holding, " +
|
||||
"tapping the player seekbar to seek, " +
|
||||
|
|
|
|||
|
|
@ -3,6 +3,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.firstMutableMethod
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
|
|
@ -77,12 +78,15 @@ private val changeHeaderBytecodePatch = bytecodePatch {
|
|||
).forEach { resourceName ->
|
||||
val id = ResourceType.ATTR[resourceName]
|
||||
|
||||
forEachInstructionAsSequence { _, method, i, instruction ->
|
||||
if (instruction.wideLiteral != id) return@forEachInstructionAsSequence
|
||||
forEachInstructionAsSequence({ _, method, instruction, index ->
|
||||
if (instruction.wideLiteral != id) return@forEachInstructionAsSequence null
|
||||
|
||||
val register = method.getInstruction<OneRegisterInstruction>(i).registerA
|
||||
val register = method.getInstruction<OneRegisterInstruction>(index).registerA
|
||||
|
||||
return@forEachInstructionAsSequence index to register
|
||||
}) { method, (index, register) ->
|
||||
method.addInstructions(
|
||||
i + 1,
|
||||
index + 1,
|
||||
"""
|
||||
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getHeaderAttributeId(I)I
|
||||
move-result v$register
|
||||
|
|
@ -218,14 +222,14 @@ val changeHeaderPatch = resourcePatch(
|
|||
if (!customFile.exists()) {
|
||||
throw PatchException(
|
||||
"The custom header path cannot be found: " +
|
||||
customFile.absolutePath,
|
||||
customFile.absolutePath,
|
||||
)
|
||||
}
|
||||
|
||||
if (!customFile.isDirectory) {
|
||||
throw PatchException(
|
||||
"The custom header path must be a folder: " +
|
||||
customFile.absolutePath,
|
||||
customFile.absolutePath,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -248,7 +252,7 @@ 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 },
|
||||
"must be specified but only found: " + customFiles.map { it.name },
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -263,8 +267,8 @@ 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,
|
||||
customHeaderResourceFileNames.contentToString() +
|
||||
"\nBut none were found in the provided option file path: " + customFile.absolutePath,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ 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.methodReference
|
||||
import app.revanced.patcher.extensions.wideLiteral
|
||||
import app.revanced.patcher.firstMutableMethod
|
||||
import app.revanced.patcher.immutableClassDef
|
||||
import app.revanced.patcher.patch.booleanOption
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
|
|
@ -66,9 +68,9 @@ private val hideShortsComponentsResourcePatch = resourcePatch {
|
|||
// FIXME: The buffer is very different for 20.22+ and these current cannot be hidden.
|
||||
Logger.getLogger(this::class.java.name).warning(
|
||||
"\n!!!" +
|
||||
"\n!!! Shorts action buttons currently cannot be set hidden when patching 20.22+" +
|
||||
"\n!!! Patch 20.21.37 or lower if you want to hide Shorts action buttons" +
|
||||
"\n!!!",
|
||||
"\n!!! Shorts action buttons currently cannot be set hidden when patching 20.22+" +
|
||||
"\n!!! Patch 20.21.37 or lower if you want to hide Shorts action buttons" +
|
||||
"\n!!!",
|
||||
)
|
||||
} else {
|
||||
preferences.addAll(
|
||||
|
|
@ -188,16 +190,18 @@ val hideShortsComponentsPatch = bytecodePatch(
|
|||
|
||||
val id = ResourceType.DIMEN["reel_player_right_pivot_v2_size"]
|
||||
|
||||
forEachInstructionAsSequence { _, method, i, instruction ->
|
||||
if (instruction.wideLiteral != id) return@forEachInstructionAsSequence
|
||||
forEachInstructionAsSequence({ _, method, instruction, index ->
|
||||
if (instruction.wideLiteral != id) return@forEachInstructionAsSequence null
|
||||
|
||||
val targetIndex = method.indexOfFirstInstructionOrThrow(i) {
|
||||
getReference<MethodReference>()?.name == "getDimensionPixelSize"
|
||||
val targetIndex = method.indexOfFirstInstructionOrThrow(index) {
|
||||
methodReference?.name == "getDimensionPixelSize"
|
||||
} + 1
|
||||
|
||||
val sizeRegister = method.getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||
|
||||
method.addInstructions(
|
||||
return@forEachInstructionAsSequence targetIndex to sizeRegister
|
||||
}) { method, (targetIndex, sizeRegister) ->
|
||||
firstMutableMethod(method).addInstructions(
|
||||
targetIndex + 1,
|
||||
"""
|
||||
invoke-static { v$sizeRegister }, $FILTER_CLASS_DESCRIPTOR->getSoundButtonSize(I)I
|
||||
|
|
@ -218,24 +222,24 @@ 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",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Hook to hide the shared navigation bar when the Shorts player is opened.
|
||||
(
|
||||
if (is_20_45_or_greater) {
|
||||
renderBottomNavigationBarParentMethod
|
||||
} else if (is_19_41_or_greater) {
|
||||
renderBottomNavigationBarLegacy1941ParentMethod
|
||||
} else {
|
||||
legacyRenderBottomNavigationBarLegacyParentMethod
|
||||
}
|
||||
).immutableClassDef.getRenderBottomNavigationBarMethodMatch().addInstruction(
|
||||
0,
|
||||
"invoke-static { p1 }, $FILTER_CLASS_DESCRIPTOR->hideNavigationBar(Ljava/lang/String;)V",
|
||||
)
|
||||
if (is_20_45_or_greater) {
|
||||
renderBottomNavigationBarParentMethod
|
||||
} else if (is_19_41_or_greater) {
|
||||
renderBottomNavigationBarLegacy1941ParentMethod
|
||||
} else {
|
||||
legacyRenderBottomNavigationBarLegacyParentMethod
|
||||
}
|
||||
).immutableClassDef.getRenderBottomNavigationBarMethodMatch().addInstruction(
|
||||
0,
|
||||
"invoke-static { p1 }, $FILTER_CLASS_DESCRIPTOR->hideNavigationBar(Ljava/lang/String;)V",
|
||||
)
|
||||
|
||||
// Hide the bottom bar container of the Shorts player.
|
||||
shortsBottomBarContainerMethodMatch.let {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,8 @@ private val miniplayerResourcePatch = resourcePatch {
|
|||
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/MiniplayerPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
val Miniplayer = bytecodePatch(
|
||||
val miniplayerPatch = bytecodePatch(
|
||||
name = "Miniplayer",
|
||||
description = "Adds options to change the in-app minimized player.",
|
||||
) {
|
||||
dependsOn(
|
||||
|
|
|
|||
|
|
@ -164,27 +164,22 @@ val returnYouTubeDislikePatch = bytecodePatch(
|
|||
charSequenceRegister = getInstruction<TwoRegisterInstruction>(charSequenceIndex).registerA
|
||||
}
|
||||
|
||||
val free1 = findFreeRegister(insertIndex, charSequenceRegister)
|
||||
val free2 = findFreeRegister(insertIndex, charSequenceRegister, free1)
|
||||
val conversionContext = findFreeRegister(insertIndex, charSequenceRegister)
|
||||
|
||||
addInstructionsAtControlFlowLabel(
|
||||
insertIndex,
|
||||
"""
|
||||
# Copy conversion context.
|
||||
move-object/from16 v$free1, p0
|
||||
move-object/from16 v$conversionContext, p0
|
||||
|
||||
# 20.41 field is the abstract superclass.
|
||||
# Verify it's the expected subclass just in case.
|
||||
instance-of v$free2, v$free1, ${textComponentConversionContextField.type}
|
||||
if-eqz v$free2, :ignore
|
||||
iget-object v$conversionContext, v$conversionContext, $textComponentConversionContextField
|
||||
|
||||
check-cast v$free1, $conversionContextClass
|
||||
invoke-static { v$free1, v$charSequenceRegister }, $EXTENSION_CLASS_DESCRIPTOR->onLithoTextLoaded(Ljava/lang/Object;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
|
||||
invoke-static { v$conversionContext, v$charSequenceRegister }, $EXTENSION_CLASS_DESCRIPTOR->onLithoTextLoaded(Ljava/lang/Object;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
|
||||
move-result-object v$charSequenceRegister
|
||||
|
||||
:ignore
|
||||
nop
|
||||
""",
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import app.revanced.patches.youtube.misc.settings.PreferenceScreen
|
|||
import app.revanced.patches.youtube.misc.settings.settingsPatch
|
||||
import app.revanced.patches.youtube.shared.getLayoutConstructorMethodMatch
|
||||
import app.revanced.patches.youtube.shared.seekbarMethod
|
||||
import app.revanced.patches.youtube.shared.seekbarOnDrawMethodMatch
|
||||
import app.revanced.patches.youtube.shared.getSeekbarOnDrawMethodMatch
|
||||
import app.revanced.patches.youtube.video.information.onCreateHook
|
||||
import app.revanced.patches.youtube.video.information.videoInformationPatch
|
||||
import app.revanced.patches.youtube.video.information.videoTimeHook
|
||||
|
|
@ -111,7 +111,8 @@ private const val EXTENSION_SPONSORBLOCK_VIEW_CONTROLLER_CLASS_DESCRIPTOR =
|
|||
"Lapp/revanced/extension/youtube/sponsorblock/ui/SponsorBlockViewController;"
|
||||
|
||||
@Suppress("unused")
|
||||
val SponsorBlock = bytecodePatch(
|
||||
val sponsorBlockPatch = bytecodePatch(
|
||||
name = "SponsorBlock",
|
||||
description = "Adds options to enable and configure SponsorBlock, which can skip undesired video segments such as sponsored content.",
|
||||
) {
|
||||
dependsOn(
|
||||
|
|
@ -164,7 +165,7 @@ val SponsorBlock = bytecodePatch(
|
|||
|
||||
// Cannot match using original immutable class because
|
||||
// class may have been modified by other patches
|
||||
seekbarMethod.immutableClassDef.seekbarOnDrawMethodMatch.let {
|
||||
seekbarMethod.immutableClassDef.getSeekbarOnDrawMethodMatch().let {
|
||||
it.method.apply {
|
||||
// Set seekbar thickness.
|
||||
val thicknessIndex = it[-1]
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
|
|||
"Lapp/revanced/extension/youtube/patches/announcements/AnnouncementsPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
val Announcements = bytecodePatch(
|
||||
val announcementsPatch = bytecodePatch(
|
||||
name = "Announcements",
|
||||
description = "Adds an option to show announcements from ReVanced on app startup.",
|
||||
) {
|
||||
dependsOn(
|
||||
|
|
|
|||
|
|
@ -136,7 +136,9 @@ internal val BytecodePatchContext.imageEnumConstructorMethodMatch by composingFi
|
|||
internal val BytecodePatchContext.setEnumMapMethodMatch by composingFirstMethod {
|
||||
instructions(
|
||||
ResourceType.DRAWABLE("yt_fill_bell_black_24"),
|
||||
afterAtMost(10, method { toString() == "Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;" }),
|
||||
afterAtMost(
|
||||
10,
|
||||
method { toString() == "Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;" }),
|
||||
afterAtMost(
|
||||
10,
|
||||
method { toString() == "Ljava/util/EnumMap;->put(Ljava/lang/Enum;Ljava/lang/Object;)Ljava/lang/Object;" },
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ internal val BytecodePatchContext.seekbarMethod by gettingFirstMethodDeclarative
|
|||
/**
|
||||
* Matches to _mutable_ class found in [seekbarMethod].
|
||||
*/
|
||||
internal val ClassDef.seekbarOnDrawMethodMatch by ClassDefComposing.composingFirstMethod {
|
||||
internal fun ClassDef.getSeekbarOnDrawMethodMatch() = firstMethodComposite {
|
||||
name("onDraw")
|
||||
instructions(
|
||||
method { toString() == "Ljava/lang/Math;->round(F)I" },
|
||||
|
|
|
|||
|
|
@ -46,7 +46,8 @@ val disableVideoCodecsPatch = bytecodePatch(
|
|||
|
||||
method.replaceInstruction(
|
||||
index,
|
||||
"invoke-static/range { v$register .. v$register }, $EXTENSION_CLASS_DESCRIPTOR->" + "disableHdrVideo(Landroid/view/Display\$HdrCapabilities;)[I",
|
||||
"invoke-static/range { v$register .. v$register }, $EXTENSION_CLASS_DESCRIPTOR->" +
|
||||
$$"disableHdrVideo(Landroid/view/Display$HdrCapabilities;)[I",
|
||||
)
|
||||
},
|
||||
),
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import com.android.tools.smali.dexlib2.Opcode
|
|||
import com.android.tools.smali.dexlib2.Opcode.*
|
||||
import com.android.tools.smali.dexlib2.analysis.reflection.util.ReflectionUtils
|
||||
import com.android.tools.smali.dexlib2.formatter.DexFormatter
|
||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.*
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
|
|
@ -27,8 +28,8 @@ import com.android.tools.smali.dexlib2.iface.reference.StringReference
|
|||
import com.android.tools.smali.dexlib2.iface.value.*
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableField
|
||||
import com.android.tools.smali.dexlib2.immutable.value.*
|
||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayDeque
|
||||
|
||||
/**
|
||||
* Starting from and including the instruction at index [startIndex],
|
||||
|
|
@ -89,7 +90,7 @@ fun Method.findFreeRegister(startIndex: Int, vararg registersToExclude: Int): In
|
|||
// 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",
|
||||
"a free register could be found from startIndex: $startIndex",
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -109,7 +110,7 @@ fun Method.findFreeRegister(startIndex: Int, vararg registersToExclude: Int): In
|
|||
// In practice this never occurs.
|
||||
throw IllegalArgumentException(
|
||||
"Could not find a free register from startIndex: " +
|
||||
"$startIndex excluding: $registersToExclude",
|
||||
"$startIndex excluding: $registersToExclude",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -193,7 +194,7 @@ private fun Method.findInstructionIndexFromToString(fieldName: String): Int {
|
|||
val stringUsageIndex = indexOfFirstInstruction(stringIndex) {
|
||||
val reference = getReference<MethodReference>()
|
||||
reference?.definingClass == "Ljava/lang/StringBuilder;" &&
|
||||
(this as? FiveRegisterInstruction)?.registerD == stringRegister
|
||||
(this as? FiveRegisterInstruction)?.registerD == stringRegister
|
||||
}
|
||||
if (stringUsageIndex < 0) {
|
||||
throw IllegalArgumentException("Could not find StringBuilder usage in: $this")
|
||||
|
|
@ -345,7 +346,8 @@ fun MutableMethod.addInstructionsAtControlFlowLabel(
|
|||
* @throws PatchException if the resource cannot be found.
|
||||
* @see [indexOfFirstResourceIdOrThrow], [indexOfFirstLiteralInstructionReversed]
|
||||
*/
|
||||
fun Method.indexOfFirstResourceId(resourceName: String): Int = indexOfFirstLiteralInstruction(ResourceType.ID[resourceName])
|
||||
fun Method.indexOfFirstResourceId(resourceName: String): Int =
|
||||
indexOfFirstLiteralInstruction(ResourceType.ID[resourceName])
|
||||
|
||||
/**
|
||||
* Get the index of the first instruction with the id of the given resource name or throw a [PatchException].
|
||||
|
|
@ -458,7 +460,8 @@ fun Method.indexOfFirstLiteralInstructionReversedOrThrow(literal: Long): Int {
|
|||
* @return the last literal instruction with the value, or -1 if not found.
|
||||
* @see indexOfFirstLiteralInstructionOrThrow
|
||||
*/
|
||||
fun Method.indexOfFirstLiteralInstructionReversed(literal: Float) = indexOfFirstLiteralInstructionReversed(literal.toRawBits().toLong())
|
||||
fun Method.indexOfFirstLiteralInstructionReversed(literal: Float) =
|
||||
indexOfFirstLiteralInstructionReversed(literal.toRawBits().toLong())
|
||||
|
||||
/**
|
||||
* Find the index of the last wide literal instruction with the given float value,
|
||||
|
|
@ -478,7 +481,8 @@ fun Method.indexOfFirstLiteralInstructionReversedOrThrow(literal: Float): Int {
|
|||
* @return the last literal instruction with the value, or -1 if not found.
|
||||
* @see indexOfFirstLiteralInstructionOrThrow
|
||||
*/
|
||||
fun Method.indexOfFirstLiteralInstructionReversed(literal: Double) = indexOfFirstLiteralInstructionReversed(literal.toRawBits())
|
||||
fun Method.indexOfFirstLiteralInstructionReversed(literal: Double) =
|
||||
indexOfFirstLiteralInstructionReversed(literal.toRawBits())
|
||||
|
||||
/**
|
||||
* Find the index of the last wide literal instruction with the given double value,
|
||||
|
|
@ -550,9 +554,10 @@ fun Method.indexOfFirstInstruction(targetOpcode: Opcode): Int = indexOfFirstInst
|
|||
* @return The index of the first opcode specified, or -1 if not found.
|
||||
* @see indexOfFirstInstructionOrThrow
|
||||
*/
|
||||
fun Method.indexOfFirstInstruction(startIndex: Int = 0, targetOpcode: Opcode): Int = indexOfFirstInstruction(startIndex) {
|
||||
opcode == targetOpcode
|
||||
}
|
||||
fun Method.indexOfFirstInstruction(startIndex: Int = 0, targetOpcode: Opcode): Int =
|
||||
indexOfFirstInstruction(startIndex) {
|
||||
opcode == targetOpcode
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index of the first [Instruction] that matches the predicate, starting from [startIndex].
|
||||
|
|
@ -587,9 +592,10 @@ fun Method.indexOfFirstInstructionOrThrow(targetOpcode: Opcode): Int = indexOfFi
|
|||
* @throws PatchException
|
||||
* @see indexOfFirstInstruction
|
||||
*/
|
||||
fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, targetOpcode: Opcode): Int = indexOfFirstInstructionOrThrow(startIndex) {
|
||||
opcode == targetOpcode
|
||||
}
|
||||
fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, targetOpcode: Opcode): Int =
|
||||
indexOfFirstInstructionOrThrow(startIndex) {
|
||||
opcode == targetOpcode
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index of the first [Instruction] that matches the predicate, starting from [startIndex].
|
||||
|
|
@ -615,9 +621,10 @@ fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, filter: Instructi
|
|||
* @return -1 if the instruction is not found.
|
||||
* @see indexOfFirstInstructionReversedOrThrow
|
||||
*/
|
||||
fun Method.indexOfFirstInstructionReversed(startIndex: Int? = null, targetOpcode: Opcode): Int = indexOfFirstInstructionReversed(startIndex) {
|
||||
opcode == targetOpcode
|
||||
}
|
||||
fun Method.indexOfFirstInstructionReversed(startIndex: Int? = null, targetOpcode: Opcode): Int =
|
||||
indexOfFirstInstructionReversed(startIndex) {
|
||||
opcode == targetOpcode
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index of matching instruction,
|
||||
|
|
@ -654,9 +661,10 @@ fun Method.indexOfFirstInstructionReversed(targetOpcode: Opcode): Int = indexOfF
|
|||
* @return The index of the instruction.
|
||||
* @see indexOfFirstInstructionReversed
|
||||
*/
|
||||
fun Method.indexOfFirstInstructionReversedOrThrow(startIndex: Int? = null, targetOpcode: Opcode): Int = indexOfFirstInstructionReversedOrThrow(startIndex) {
|
||||
opcode == targetOpcode
|
||||
}
|
||||
fun Method.indexOfFirstInstructionReversedOrThrow(startIndex: Int? = null, targetOpcode: Opcode): Int =
|
||||
indexOfFirstInstructionReversedOrThrow(startIndex) {
|
||||
opcode == targetOpcode
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index of matching instruction,
|
||||
|
|
@ -713,7 +721,8 @@ fun Method.findInstructionIndicesReversedOrThrow(filter: Instruction.() -> Boole
|
|||
* _Returns an empty list if no indices are found_
|
||||
* @see findInstructionIndicesReversedOrThrow
|
||||
*/
|
||||
fun Method.findInstructionIndicesReversed(opcode: Opcode): List<Int> = findInstructionIndicesReversed { this.opcode == opcode }
|
||||
fun Method.findInstructionIndicesReversed(opcode: Opcode): List<Int> =
|
||||
findInstructionIndicesReversed { this.opcode == opcode }
|
||||
|
||||
/**
|
||||
* @return An immutable list of indices of the opcode in reverse order.
|
||||
|
|
@ -779,33 +788,30 @@ internal fun MutableMethod.insertLiteralOverride(literalIndex: Int, override: Bo
|
|||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param match A function that matches instructions. If a match is found, it returns a value of type [T], otherwise null.
|
||||
* @param transform A function that transforms the matched instruction using the mutable method and the matched value
|
||||
* of type [T].
|
||||
*/
|
||||
fun BytecodePatchContext.forEachInstructionAsSequence(
|
||||
block: (classDef: MutableClassDef, method: MutableMethod, matchingIndex: Int, instruction: Instruction) -> Unit,
|
||||
fun <T> BytecodePatchContext.forEachInstructionAsSequence(
|
||||
match: (classDef: ClassDef, method: Method, instruction: Instruction, index: Int) -> T?,
|
||||
transform: (MutableMethod, T) -> Unit
|
||||
) {
|
||||
classDefs.asSequence().flatMap { classDef ->
|
||||
val mutableClassDef by lazy { classDefs.getOrReplaceMutable(classDef) }
|
||||
classDefs.flatMap { classDef ->
|
||||
classDef.methods.mapNotNull { method ->
|
||||
val matches = method.instructionsOrNull?.mapIndexedNotNull { index, instruction ->
|
||||
match(classDef, method, instruction, index)
|
||||
} ?: return@mapNotNull null
|
||||
|
||||
classDef.methods.asSequence().flatMap { method ->
|
||||
val instructions =
|
||||
method.instructionsOrNull as? List<Instruction> ?: return@flatMap emptySequence<() -> Unit>()
|
||||
|
||||
val mutableMethod by lazy { mutableClassDef.firstMutableMethod(method) }
|
||||
|
||||
instructions.asReversed().asSequence().mapIndexed { index, instruction ->
|
||||
{
|
||||
block(
|
||||
mutableClassDef,
|
||||
mutableMethod,
|
||||
instructions.size - 1 - index,
|
||||
instruction,
|
||||
)
|
||||
} // Reverse indices again.
|
||||
}
|
||||
if (matches.any()) method to matches else null
|
||||
}
|
||||
}.forEach { it() }
|
||||
}.forEach { (method, matches) ->
|
||||
|
||||
val method = firstMutableMethod(method)
|
||||
val matches = matches.toCollection(ArrayDeque())
|
||||
|
||||
while (!matches.isEmpty()) transform(method, matches.removeLast())
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableMethod.checkReturnType(expectedTypes: Iterable<Class<*>>) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue