feat: Convert patches to Kotlin DSL
BREAKING CHANGE: This removes all previous deprecated members and classes. Also the patches API is now Kotlin DSL.
This commit is contained in:
parent
1614d7f9f4
commit
3760cb2270
|
@ -1,5 +1,4 @@
|
|||
public abstract interface class app/revanced/patcher/IntegrationsConsumer {
|
||||
public abstract fun acceptIntegrations (Ljava/util/List;)V
|
||||
public abstract fun acceptIntegrations (Ljava/util/Set;)V
|
||||
}
|
||||
|
||||
|
@ -32,7 +31,6 @@ public abstract class app/revanced/patcher/PatchBundleLoader : java/util/Set, ko
|
|||
}
|
||||
|
||||
public final class app/revanced/patcher/PatchBundleLoader$Dex : app/revanced/patcher/PatchBundleLoader {
|
||||
public fun <init> ([Ljava/io/File;)V
|
||||
public fun <init> ([Ljava/io/File;Ljava/io/File;)V
|
||||
public synthetic fun <init> ([Ljava/io/File;Ljava/io/File;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
}
|
||||
|
@ -46,10 +44,7 @@ public abstract interface class app/revanced/patcher/PatchExecutorFunction : jav
|
|||
|
||||
public final class app/revanced/patcher/Patcher : app/revanced/patcher/IntegrationsConsumer, app/revanced/patcher/PatchExecutorFunction, app/revanced/patcher/PatchesConsumer, java/io/Closeable, java/util/function/Supplier {
|
||||
public fun <init> (Lapp/revanced/patcher/PatcherConfig;)V
|
||||
public fun <init> (Lapp/revanced/patcher/PatcherOptions;)V
|
||||
public fun acceptIntegrations (Ljava/util/List;)V
|
||||
public fun acceptIntegrations (Ljava/util/Set;)V
|
||||
public fun acceptPatches (Ljava/util/List;)V
|
||||
public fun acceptPatches (Ljava/util/Set;)V
|
||||
public synthetic fun apply (Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun apply (Z)Lkotlinx/coroutines/flow/Flow;
|
||||
|
@ -76,37 +71,12 @@ public abstract class app/revanced/patcher/PatcherException : java/lang/Exceptio
|
|||
public final class app/revanced/patcher/PatcherException$CircularDependencyException : app/revanced/patcher/PatcherException {
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/PatcherOptions {
|
||||
public fun <init> (Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Z)V
|
||||
public synthetic fun <init> (Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun copy (Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;Z)Lapp/revanced/patcher/PatcherOptions;
|
||||
public static synthetic fun copy$default (Lapp/revanced/patcher/PatcherOptions;Ljava/io/File;Ljava/io/File;Ljava/lang/String;Ljava/lang/String;ZILjava/lang/Object;)Lapp/revanced/patcher/PatcherOptions;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public fun hashCode ()I
|
||||
public final fun recreateResourceCacheDirectory ()Ljava/io/File;
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/PatcherResult {
|
||||
public fun <init> (Ljava/util/List;Ljava/io/File;Ljava/util/List;)V
|
||||
public synthetic fun <init> (Ljava/util/List;Ljava/io/File;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun component1 ()Ljava/util/List;
|
||||
public final fun component2 ()Ljava/io/File;
|
||||
public final fun component3 ()Ljava/util/List;
|
||||
public final fun copy (Ljava/util/List;Ljava/io/File;Ljava/util/List;)Lapp/revanced/patcher/PatcherResult;
|
||||
public static synthetic fun copy$default (Lapp/revanced/patcher/PatcherResult;Ljava/util/List;Ljava/io/File;Ljava/util/List;ILjava/lang/Object;)Lapp/revanced/patcher/PatcherResult;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public final fun getDexFiles ()Ljava/util/List;
|
||||
public final fun getDexFiles ()Ljava/util/Set;
|
||||
public final fun getDoNotCompress ()Ljava/util/List;
|
||||
public final fun getResourceFile ()Ljava/io/File;
|
||||
public final fun getResources ()Lapp/revanced/patcher/PatcherResult$PatchedResources;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/PatcherResult$PatchedDexFile {
|
||||
public fun <init> (Ljava/lang/String;Ljava/io/InputStream;)V
|
||||
public final fun getName ()Ljava/lang/String;
|
||||
public final fun getStream ()Ljava/io/InputStream;
|
||||
}
|
||||
|
@ -119,14 +89,9 @@ public final class app/revanced/patcher/PatcherResult$PatchedResources {
|
|||
}
|
||||
|
||||
public abstract interface class app/revanced/patcher/PatchesConsumer {
|
||||
public abstract fun acceptPatches (Ljava/util/List;)V
|
||||
public abstract fun acceptPatches (Ljava/util/Set;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/PatchesConsumer$DefaultImpls {
|
||||
public static fun acceptPatches (Lapp/revanced/patcher/PatchesConsumer;Ljava/util/List;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/data/BytecodeContext : app/revanced/patcher/data/Context {
|
||||
public final fun findClass (Ljava/lang/String;)Lapp/revanced/patcher/util/proxy/ClassProxy;
|
||||
public final fun findClass (Lkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/util/proxy/ClassProxy;
|
||||
|
@ -140,15 +105,12 @@ public final class app/revanced/patcher/data/BytecodeContext : app/revanced/patc
|
|||
public abstract interface class app/revanced/patcher/data/Context : java/util/function/Supplier {
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/data/ResourceContext : app/revanced/patcher/data/Context, java/lang/Iterable, kotlin/jvm/internal/markers/KMappedMarker {
|
||||
public final class app/revanced/patcher/data/ResourceContext : app/revanced/patcher/data/Context {
|
||||
public fun get ()Lapp/revanced/patcher/PatcherResult$PatchedResources;
|
||||
public synthetic fun get ()Ljava/lang/Object;
|
||||
public final fun get (Ljava/lang/String;)Ljava/io/File;
|
||||
public final fun get (Ljava/lang/String;Z)Ljava/io/File;
|
||||
public static synthetic fun get$default (Lapp/revanced/patcher/data/ResourceContext;Ljava/lang/String;ZILjava/lang/Object;)Ljava/io/File;
|
||||
public final fun getDocument ()Lapp/revanced/patcher/data/ResourceContext$DocumentOperatable;
|
||||
public final fun getXmlEditor ()Lapp/revanced/patcher/data/ResourceContext$XmlFileHolder;
|
||||
public fun iterator ()Ljava/util/Iterator;
|
||||
public final fun stageDelete (Lkotlin/jvm/functions/Function1;)Z
|
||||
}
|
||||
|
||||
|
@ -158,12 +120,6 @@ public final class app/revanced/patcher/data/ResourceContext$DocumentOperatable
|
|||
public final fun get (Ljava/lang/String;)Lapp/revanced/patcher/util/Document;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/data/ResourceContext$XmlFileHolder {
|
||||
public fun <init> (Lapp/revanced/patcher/data/ResourceContext;)V
|
||||
public final fun get (Ljava/io/InputStream;)Lapp/revanced/patcher/util/DomFileEditor;
|
||||
public final fun get (Ljava/lang/String;)Lapp/revanced/patcher/util/DomFileEditor;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/extensions/ExtensionsKt {
|
||||
public static final fun newLabel (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)Lcom/android/tools/smali/dexlib2/builder/Label;
|
||||
public static final fun or (ILcom/android/tools/smali/dexlib2/AccessFlags;)I
|
||||
|
@ -201,16 +157,11 @@ public final class app/revanced/patcher/extensions/InstructionExtensions {
|
|||
public final fun replaceInstructions (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;ILjava/util/List;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/extensions/MethodFingerprintExtensions {
|
||||
public static final field INSTANCE Lapp/revanced/patcher/extensions/MethodFingerprintExtensions;
|
||||
public final fun getFuzzyPatternScanMethod (Lapp/revanced/patcher/fingerprint/MethodFingerprint;)Lapp/revanced/patcher/fingerprint/annotation/FuzzyPatternScanMethod;
|
||||
}
|
||||
|
||||
public abstract class app/revanced/patcher/fingerprint/MethodFingerprint {
|
||||
public final class app/revanced/patcher/fingerprint/MethodFingerprint {
|
||||
public static final field Companion Lapp/revanced/patcher/fingerprint/MethodFingerprint$Companion;
|
||||
public fun <init> ()V
|
||||
public fun <init> (Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Iterable;Ljava/lang/Iterable;Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;)V
|
||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Iterable;Ljava/lang/Iterable;Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public fun <init> (Ljava/lang/String;Ljava/lang/Integer;Ljava/util/List;Ljava/util/List;Ljava/util/List;Lkotlin/jvm/functions/Function2;)V
|
||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/Integer;Ljava/util/List;Ljava/util/List;Ljava/util/List;Lkotlin/jvm/functions/Function2;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun getFuzzyPatternScanMethod ()Lapp/revanced/patcher/fingerprint/annotation/FuzzyPatternScanMethod;
|
||||
public final fun getResult ()Lapp/revanced/patcher/fingerprint/MethodFingerprintResult;
|
||||
public final fun resolve (Lapp/revanced/patcher/data/BytecodeContext;Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Z
|
||||
|
@ -237,20 +188,9 @@ public final class app/revanced/patcher/fingerprint/MethodFingerprintResult$Meth
|
|||
}
|
||||
|
||||
public final class app/revanced/patcher/fingerprint/MethodFingerprintResult$MethodFingerprintScanResult$PatternScanResult {
|
||||
public fun <init> (IILjava/util/List;)V
|
||||
public synthetic fun <init> (IILjava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public fun <init> (II)V
|
||||
public final fun getEndIndex ()I
|
||||
public final fun getStartIndex ()I
|
||||
public final fun getWarnings ()Ljava/util/List;
|
||||
public final fun setWarnings (Ljava/util/List;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/fingerprint/MethodFingerprintResult$MethodFingerprintScanResult$PatternScanResult$Warning {
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/Opcode;Lcom/android/tools/smali/dexlib2/Opcode;II)V
|
||||
public final fun getCorrectOpcode ()Lcom/android/tools/smali/dexlib2/Opcode;
|
||||
public final fun getInstructionIndex ()I
|
||||
public final fun getPatternIndex ()I
|
||||
public final fun getWrongOpcode ()Lcom/android/tools/smali/dexlib2/Opcode;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/fingerprint/MethodFingerprintResult$MethodFingerprintScanResult$StringsScanResult {
|
||||
|
@ -268,18 +208,26 @@ public abstract interface annotation class app/revanced/patcher/fingerprint/anno
|
|||
public abstract fun threshold ()I
|
||||
}
|
||||
|
||||
public abstract class app/revanced/patcher/patch/BytecodePatch : app/revanced/patcher/patch/Patch {
|
||||
public fun <init> ()V
|
||||
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;ZZLjava/util/Set;)V
|
||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;ZZLjava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public fun <init> (Ljava/util/Set;)V
|
||||
public synthetic fun <init> (Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final class app/revanced/patcher/patch/BytecodePatch : app/revanced/patcher/patch/Patch {
|
||||
public final fun fingerprints ([Lapp/revanced/patcher/fingerprint/MethodFingerprint;)V
|
||||
}
|
||||
|
||||
public abstract class app/revanced/patcher/patch/Patch {
|
||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;ZZLkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public abstract fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;ZZLkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun booleanArrayPatchOption (Ljava/lang/String;[Ljava/lang/Boolean;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public static synthetic fun booleanArrayPatchOption$default (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;[Ljava/lang/Boolean;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public final fun booleanPatchOption (Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public static synthetic fun booleanPatchOption$default (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public final fun close (Lapp/revanced/patcher/data/Context;)V
|
||||
public final fun close (Lkotlin/jvm/functions/Function1;)V
|
||||
public final fun compatibleWith (Lkotlin/jvm/functions/Function1;)V
|
||||
public final fun dependsOn ([Lapp/revanced/patcher/patch/Patch;)V
|
||||
public final fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
public final fun execute (Lkotlin/jvm/functions/Function1;)V
|
||||
public final fun floatArrayPatchOption (Ljava/lang/String;[Ljava/lang/Float;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public static synthetic fun floatArrayPatchOption$default (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;[Ljava/lang/Float;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public final fun floatPatchOption (Ljava/lang/String;Ljava/lang/Float;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public static synthetic fun floatPatchOption$default (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;Ljava/lang/Float;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public final fun getCompatiblePackages ()Ljava/util/Set;
|
||||
public final fun getDependencies ()Ljava/util/Set;
|
||||
public final fun getDescription ()Ljava/lang/String;
|
||||
|
@ -287,15 +235,26 @@ public abstract class app/revanced/patcher/patch/Patch {
|
|||
public final fun getOptions ()Lapp/revanced/patcher/patch/options/PatchOptions;
|
||||
public final fun getRequiresIntegrations ()Z
|
||||
public final fun getUse ()Z
|
||||
public fun hashCode ()I
|
||||
public final fun intArrayPatchOption (Ljava/lang/String;[Ljava/lang/Integer;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public static synthetic fun intArrayPatchOption$default (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;[Ljava/lang/Integer;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public final fun intPatchOption (Ljava/lang/String;Ljava/lang/Integer;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public static synthetic fun intPatchOption$default (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;Ljava/lang/Integer;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public final fun longArrayPatchOption (Ljava/lang/String;[Ljava/lang/Long;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public static synthetic fun longArrayPatchOption$default (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;[Ljava/lang/Long;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public final fun longPatchOption (Ljava/lang/String;Ljava/lang/Long;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public static synthetic fun longPatchOption$default (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;Ljava/lang/Long;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public final fun registerNewPatchOption (Ljava/lang/String;Ljava/lang/Object;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;Lkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public static synthetic fun registerNewPatchOption$default (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;Ljava/lang/Object;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public final fun stringArrayPatchOption (Ljava/lang/String;[Ljava/lang/String;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public static synthetic fun stringArrayPatchOption$default (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;[Ljava/lang/String;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public final fun stringPatchOption (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public static synthetic fun stringPatchOption$default (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/patch/Patch$CompatiblePackage {
|
||||
public fun <init> (Ljava/lang/String;Ljava/util/Set;)V
|
||||
public synthetic fun <init> (Ljava/lang/String;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun getName ()Ljava/lang/String;
|
||||
public final fun getVersions ()Ljava/util/Set;
|
||||
public final class app/revanced/patcher/patch/Patch$CompatiblePackages {
|
||||
public fun <init> ()V
|
||||
public final fun invoke (Ljava/lang/String;[Ljava/lang/String;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/patch/PatchException : java/lang/Exception {
|
||||
|
@ -304,39 +263,27 @@ public final class app/revanced/patcher/patch/PatchException : java/lang/Excepti
|
|||
public fun <init> (Ljava/lang/Throwable;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/patch/PatchKt {
|
||||
public static final fun bytecodePatch (Ljava/lang/String;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
public static synthetic fun bytecodePatch$default (Ljava/lang/String;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
public static final fun rawResourcePatch (Ljava/lang/String;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/patch/RawResourcePatch;
|
||||
public static synthetic fun rawResourcePatch$default (Ljava/lang/String;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/patch/RawResourcePatch;
|
||||
public static final fun resourcePatch (Ljava/lang/String;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/patch/ResourcePatch;
|
||||
public static synthetic fun resourcePatch$default (Ljava/lang/String;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/patch/ResourcePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/patch/PatchResult {
|
||||
public final fun getException ()Lapp/revanced/patcher/patch/PatchException;
|
||||
public final fun getPatch ()Lapp/revanced/patcher/patch/Patch;
|
||||
}
|
||||
|
||||
public abstract class app/revanced/patcher/patch/RawResourcePatch : app/revanced/patcher/patch/Patch {
|
||||
public fun <init> ()V
|
||||
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;ZZ)V
|
||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;ZZILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final class app/revanced/patcher/patch/RawResourcePatch : app/revanced/patcher/patch/Patch {
|
||||
}
|
||||
|
||||
public abstract class app/revanced/patcher/patch/ResourcePatch : app/revanced/patcher/patch/Patch {
|
||||
public fun <init> ()V
|
||||
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;ZZ)V
|
||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;ZZILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
}
|
||||
|
||||
public abstract interface annotation class app/revanced/patcher/patch/annotation/CompatiblePackage : java/lang/annotation/Annotation {
|
||||
public abstract fun name ()Ljava/lang/String;
|
||||
public abstract fun versions ()[Ljava/lang/String;
|
||||
}
|
||||
|
||||
public abstract interface annotation class app/revanced/patcher/patch/annotation/Patch : java/lang/annotation/Annotation {
|
||||
public abstract fun compatiblePackages ()[Lapp/revanced/patcher/patch/annotation/CompatiblePackage;
|
||||
public abstract fun dependencies ()[Ljava/lang/Class;
|
||||
public abstract fun description ()Ljava/lang/String;
|
||||
public abstract fun name ()Ljava/lang/String;
|
||||
public abstract fun requiresIntegrations ()Z
|
||||
public abstract fun use ()Z
|
||||
public final class app/revanced/patcher/patch/ResourcePatch : app/revanced/patcher/patch/Patch {
|
||||
}
|
||||
|
||||
public class app/revanced/patcher/patch/options/PatchOption {
|
||||
public static final field PatchExtensions Lapp/revanced/patcher/patch/options/PatchOption$PatchExtensions;
|
||||
public fun <init> (Ljava/lang/String;Ljava/lang/Object;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;Lkotlin/jvm/functions/Function2;)V
|
||||
public final fun getDefault ()Ljava/lang/Object;
|
||||
public final fun getDescription ()Ljava/lang/String;
|
||||
|
@ -354,31 +301,6 @@ public class app/revanced/patcher/patch/options/PatchOption {
|
|||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/patch/options/PatchOption$PatchExtensions {
|
||||
public final fun booleanArrayPatchOption (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;[Ljava/lang/Boolean;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public static synthetic fun booleanArrayPatchOption$default (Lapp/revanced/patcher/patch/options/PatchOption$PatchExtensions;Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;[Ljava/lang/Boolean;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public final fun booleanPatchOption (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public static synthetic fun booleanPatchOption$default (Lapp/revanced/patcher/patch/options/PatchOption$PatchExtensions;Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public final fun floatArrayPatchOption (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;[Ljava/lang/Float;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public static synthetic fun floatArrayPatchOption$default (Lapp/revanced/patcher/patch/options/PatchOption$PatchExtensions;Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;[Ljava/lang/Float;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public final fun floatPatchOption (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;Ljava/lang/Float;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public static synthetic fun floatPatchOption$default (Lapp/revanced/patcher/patch/options/PatchOption$PatchExtensions;Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;Ljava/lang/Float;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public final fun intArrayPatchOption (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;[Ljava/lang/Integer;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public static synthetic fun intArrayPatchOption$default (Lapp/revanced/patcher/patch/options/PatchOption$PatchExtensions;Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;[Ljava/lang/Integer;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public final fun intPatchOption (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;Ljava/lang/Integer;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public static synthetic fun intPatchOption$default (Lapp/revanced/patcher/patch/options/PatchOption$PatchExtensions;Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;Ljava/lang/Integer;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public final fun longArrayPatchOption (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;[Ljava/lang/Long;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public static synthetic fun longArrayPatchOption$default (Lapp/revanced/patcher/patch/options/PatchOption$PatchExtensions;Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;[Ljava/lang/Long;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public final fun longPatchOption (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;Ljava/lang/Long;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public static synthetic fun longPatchOption$default (Lapp/revanced/patcher/patch/options/PatchOption$PatchExtensions;Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;Ljava/lang/Long;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public final fun registerNewPatchOption (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;Ljava/lang/Object;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;Lkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public static synthetic fun registerNewPatchOption$default (Lapp/revanced/patcher/patch/options/PatchOption$PatchExtensions;Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;Ljava/lang/Object;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public final fun stringArrayPatchOption (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;[Ljava/lang/String;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public static synthetic fun stringArrayPatchOption$default (Lapp/revanced/patcher/patch/options/PatchOption$PatchExtensions;Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;[Ljava/lang/String;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public final fun stringPatchOption (Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
public static synthetic fun stringPatchOption$default (Lapp/revanced/patcher/patch/options/PatchOption$PatchExtensions;Lapp/revanced/patcher/patch/Patch;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
|
||||
}
|
||||
|
||||
public abstract class app/revanced/patcher/patch/options/PatchOptionException : java/lang/Exception {
|
||||
public synthetic fun <init> (Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
}
|
||||
|
@ -500,12 +422,6 @@ public final class app/revanced/patcher/util/Document : java/io/Closeable, org/w
|
|||
public fun setXmlVersion (Ljava/lang/String;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/DomFileEditor : java/io/Closeable {
|
||||
public fun <init> (Ljava/io/File;)V
|
||||
public fun close ()V
|
||||
public final fun getFile ()Lorg/w3c/dom/Document;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/ProxyClassList : java/util/Set, kotlin/jvm/internal/markers/KMutableSet {
|
||||
public final fun add (Lapp/revanced/patcher/util/proxy/ClassProxy;)Z
|
||||
public fun add (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Z
|
||||
|
|
|
@ -5,7 +5,4 @@ import java.io.File
|
|||
@FunctionalInterface
|
||||
interface IntegrationsConsumer {
|
||||
fun acceptIntegrations(integrations: Set<File>)
|
||||
|
||||
@Deprecated("Use acceptIntegrations(Set<File>) instead.")
|
||||
fun acceptIntegrations(integrations: List<File>)
|
||||
}
|
||||
|
|
|
@ -10,18 +10,12 @@ import java.io.File
|
|||
import java.net.URLClassLoader
|
||||
import java.util.jar.JarFile
|
||||
import java.util.logging.Logger
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* A set of [Patch]es.
|
||||
*/
|
||||
typealias PatchSet = Set<Patch<*>>
|
||||
|
||||
/**
|
||||
* A [Patch] class.
|
||||
*/
|
||||
typealias PatchClass = KClass<out Patch<*>>
|
||||
|
||||
/**
|
||||
* A loader of [Patch]es from patch bundles.
|
||||
* This will load all [Patch]es from the given patch bundles that have a name.
|
||||
|
@ -42,57 +36,19 @@ sealed class PatchBundleLoader private constructor(
|
|||
private val logger = Logger.getLogger(PatchBundleLoader::class.java.name)
|
||||
|
||||
init {
|
||||
patchBundles.flatMap(getBinaryClassNames).asSequence().map {
|
||||
patchBundles.asSequence().flatMap(getBinaryClassNames).map {
|
||||
classLoader.loadClass(it)
|
||||
}.filter {
|
||||
Patch::class.java.isAssignableFrom(it)
|
||||
}.mapNotNull { patchClass ->
|
||||
patchClass.getInstance(logger, silent = true)
|
||||
}.flatMap {
|
||||
it.declaredFields.filter { field ->
|
||||
Patch::class.java.isAssignableFrom(field.type)
|
||||
}.map { field -> field.get(null) as Patch<*> }
|
||||
}.filter {
|
||||
it.name != null
|
||||
}.let { patches ->
|
||||
}.toList().let { patches ->
|
||||
patchSet.addAll(patches)
|
||||
}
|
||||
}
|
||||
|
||||
internal companion object Utils {
|
||||
/**
|
||||
* Instantiates a [Patch]. If the class is a singleton, the INSTANCE field will be used.
|
||||
*
|
||||
* @param logger The [Logger] to use for logging.
|
||||
* @param silent Whether to suppress logging.
|
||||
* @return The instantiated [Patch] or `null` if the [Patch] could not be instantiated.
|
||||
*/
|
||||
internal fun Class<*>.getInstance(
|
||||
logger: Logger,
|
||||
silent: Boolean = false,
|
||||
): Patch<*>? {
|
||||
return try {
|
||||
getField("INSTANCE").get(null)
|
||||
} catch (exception: NoSuchFieldException) {
|
||||
if (!silent) {
|
||||
logger.fine(
|
||||
"Patch class '$name' has no INSTANCE field, therefor not a singleton. " +
|
||||
"Attempting to instantiate it.",
|
||||
)
|
||||
}
|
||||
|
||||
try {
|
||||
getDeclaredConstructor().newInstance()
|
||||
} catch (exception: Exception) {
|
||||
if (!silent) {
|
||||
logger.severe(
|
||||
"Patch class '$name' is not singleton and has no suitable constructor, " +
|
||||
"therefor cannot be instantiated and is ignored.",
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
} as Patch<*>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A [PatchBundleLoader] for JAR files.
|
||||
*
|
||||
|
@ -128,8 +84,5 @@ sealed class PatchBundleLoader private constructor(
|
|||
classDef.type.substring(1, classDef.length - 1)
|
||||
}
|
||||
},
|
||||
) {
|
||||
@Deprecated("This constructor is deprecated. Use the constructor with the second parameter instead.")
|
||||
constructor(vararg patchBundles: File) : this(*patchBundles, optimizedDexDirectory = null)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package app.revanced.patcher
|
||||
|
||||
import app.revanced.patcher.PatchBundleLoader.Utils.getInstance
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.fingerprint.LookupMap
|
||||
import app.revanced.patcher.patch.*
|
||||
|
@ -25,20 +24,6 @@ class Patcher(
|
|||
*/
|
||||
val context = PatcherContext(config)
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@Deprecated("Use Patcher(PatcherConfig) instead.")
|
||||
constructor(
|
||||
patcherOptions: PatcherOptions,
|
||||
) : this(
|
||||
PatcherConfig(
|
||||
patcherOptions.inputFile,
|
||||
patcherOptions.resourceCachePath,
|
||||
patcherOptions.aaptBinaryPath,
|
||||
patcherOptions.frameworkFileDirectory,
|
||||
patcherOptions.multithreadingDexFileWriter,
|
||||
),
|
||||
)
|
||||
|
||||
init {
|
||||
context.resourceContext.decodeResources(ResourceContext.ResourceMode.NONE)
|
||||
}
|
||||
|
@ -50,26 +35,15 @@ class Patcher(
|
|||
*/
|
||||
@Suppress("NAME_SHADOWING")
|
||||
override fun acceptPatches(patches: PatchSet) {
|
||||
/**
|
||||
* Add dependencies of a [Patch] recursively to [PatcherContext.allPatches].
|
||||
* If a [Patch] is already in [PatcherContext.allPatches], it will not be added again.
|
||||
*/
|
||||
fun PatchClass.putDependenciesRecursively() {
|
||||
if (context.allPatches.contains(this)) return
|
||||
// Add all patches to the executablePatches set.
|
||||
context.executablePatches.addAll(patches)
|
||||
|
||||
val dependency = this.java.getInstance(logger)!!
|
||||
context.allPatches[this] = dependency
|
||||
|
||||
dependency.dependencies?.forEach { it.putDependenciesRecursively() }
|
||||
}
|
||||
|
||||
// Add all patches and their dependencies to the context.
|
||||
// Add all patches and their dependencies to the allPatches set.
|
||||
patches.forEach { patch ->
|
||||
context.executablePatches.putIfAbsent(patch::class, patch) ?: run {
|
||||
context.allPatches[patch::class] = patch
|
||||
fun Patch<*>.addRecursively() =
|
||||
also(context.allPatches::add).dependencies.forEach(Patch<*>::addRecursively)
|
||||
|
||||
patch.dependencies?.forEach { it.putDependenciesRecursively() }
|
||||
}
|
||||
patch.addRecursively()
|
||||
}
|
||||
|
||||
// TODO: Detect circular dependencies.
|
||||
|
@ -80,13 +54,10 @@ class Patcher(
|
|||
* @param predicate The predicate to match.
|
||||
*/
|
||||
fun Patch<*>.anyRecursively(predicate: (Patch<*>) -> Boolean): Boolean =
|
||||
predicate(this) || dependencies?.any { dependency ->
|
||||
context.allPatches[dependency]!!.anyRecursively(predicate)
|
||||
} ?: false
|
||||
|
||||
context.allPatches.values.let { patches ->
|
||||
// Determine the resource mode.
|
||||
predicate(this) || dependencies.any { dependency -> dependency.anyRecursively(predicate) }
|
||||
|
||||
context.allPatches.let { patches ->
|
||||
// Check, if what kind of resource mode is required.
|
||||
config.resourceMode = if (patches.any { patch -> patch.anyRecursively { it is ResourcePatch } }) {
|
||||
ResourceContext.ResourceMode.FULL
|
||||
} else if (patches.any { patch -> patch.anyRecursively { it is RawResourcePatch } }) {
|
||||
|
@ -95,7 +66,7 @@ class Patcher(
|
|||
ResourceContext.ResourceMode.NONE
|
||||
}
|
||||
|
||||
// Determine, if merging integrations is required.
|
||||
// Check, if integrations need to be merged.
|
||||
for (patch in patches)
|
||||
if (patch.anyRecursively { it.requiresIntegrations }) {
|
||||
context.bytecodeContext.integrations.merge = true
|
||||
|
@ -113,12 +84,6 @@ class Patcher(
|
|||
context.bytecodeContext.integrations.addAll(integrations)
|
||||
}
|
||||
|
||||
@Deprecated(
|
||||
"Use acceptIntegrations(Set<File>) instead.",
|
||||
ReplaceWith("acceptIntegrations(integrations.toSet())"),
|
||||
)
|
||||
override fun acceptIntegrations(integrations: List<File>) = acceptIntegrations(integrations.toSet())
|
||||
|
||||
/**
|
||||
* Execute [Patch]es that were added to ReVanced [Patcher].
|
||||
*
|
||||
|
@ -127,52 +92,38 @@ class Patcher(
|
|||
*/
|
||||
override fun apply(returnOnError: Boolean) =
|
||||
flow {
|
||||
/**
|
||||
* Execute a [Patch] and its dependencies recursively.
|
||||
*
|
||||
* @param patch The [Patch] to execute.
|
||||
* @param executedPatches A map to prevent [Patch]es from being executed twice due to dependencies.
|
||||
* @return The result of executing the [Patch].
|
||||
*/
|
||||
fun executePatch(
|
||||
patch: Patch<*>,
|
||||
fun Patch<*>.execute(
|
||||
executedPatches: LinkedHashMap<Patch<*>, PatchResult>,
|
||||
): PatchResult {
|
||||
val patchName = patch.toString()
|
||||
|
||||
executedPatches[patch]?.let { patchResult ->
|
||||
// If the patch was executed before or failed, return it's the result.
|
||||
executedPatches[this]?.let { patchResult ->
|
||||
patchResult.exception ?: return patchResult
|
||||
|
||||
// Return a new result with an exception indicating that the patch was not executed previously,
|
||||
// because it is a dependency of another patch that failed.
|
||||
return PatchResult(patch, PatchException("'$patchName' did not succeed previously"))
|
||||
return PatchResult(this, PatchException("'$this' failed previously"))
|
||||
}
|
||||
|
||||
// Recursively execute all dependency patches.
|
||||
patch.dependencies?.forEach { dependencyClass ->
|
||||
val dependency = context.allPatches[dependencyClass]!!
|
||||
val result = executePatch(dependency, executedPatches)
|
||||
|
||||
result.exception?.let {
|
||||
dependencies.forEach { dependency ->
|
||||
execute(executedPatches).exception?.let {
|
||||
return PatchResult(
|
||||
patch,
|
||||
this,
|
||||
PatchException(
|
||||
"'$patchName' depends on '${dependency.name ?: dependency}' " +
|
||||
"that raised an exception:\n${it.stackTraceToString()}",
|
||||
"'$this' depends on '$dependency' that raised an exception:\n${it.stackTraceToString()}",
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Execute the patch.
|
||||
return try {
|
||||
patch.execute(context)
|
||||
execute(context)
|
||||
|
||||
PatchResult(patch)
|
||||
PatchResult(this)
|
||||
} catch (exception: PatchException) {
|
||||
PatchResult(patch, exception)
|
||||
PatchResult(this, exception)
|
||||
} catch (exception: Exception) {
|
||||
PatchResult(patch, PatchException(exception))
|
||||
}.also { executedPatches[patch] = it }
|
||||
PatchResult(this, PatchException(exception))
|
||||
}.also { executedPatches[this] = it }
|
||||
}
|
||||
|
||||
if (context.bytecodeContext.integrations.merge) context.bytecodeContext.integrations.flush()
|
||||
|
@ -186,10 +137,10 @@ class Patcher(
|
|||
|
||||
logger.info("Executing patches")
|
||||
|
||||
val executedPatches = LinkedHashMap<Patch<*>, PatchResult>() // Key is name.
|
||||
val executedPatches = LinkedHashMap<Patch<*>, PatchResult>()
|
||||
|
||||
context.executablePatches.values.sortedBy { it.name }.forEach { patch ->
|
||||
val patchResult = executePatch(patch, executedPatches)
|
||||
context.executablePatches.sortedBy { it.name }.forEach { patch ->
|
||||
val patchResult = patch.execute(executedPatches)
|
||||
|
||||
// If the patch failed, emit the result, even if it is closeable.
|
||||
// Results of executed patches that are closeable will be emitted later.
|
||||
|
@ -205,40 +156,38 @@ class Patcher(
|
|||
}
|
||||
}
|
||||
|
||||
executedPatches.values
|
||||
.filter { it.exception == null }
|
||||
.filter { it.patch is Closeable }.asReversed().forEach { executedPatch ->
|
||||
val patch = executedPatch.patch
|
||||
executedPatches.values.filter { it.exception == null }.asReversed().forEach { executedPatch ->
|
||||
val patch = executedPatch.patch
|
||||
|
||||
val result =
|
||||
try {
|
||||
(patch as Closeable).close()
|
||||
val result =
|
||||
try {
|
||||
(patch as Closeable).close()
|
||||
|
||||
executedPatch
|
||||
} catch (exception: PatchException) {
|
||||
PatchResult(patch, exception)
|
||||
} catch (exception: Exception) {
|
||||
PatchResult(patch, PatchException(exception))
|
||||
}
|
||||
|
||||
result.exception?.let {
|
||||
emit(
|
||||
PatchResult(
|
||||
patch,
|
||||
PatchException(
|
||||
"'$patch' raised an exception while being closed: ${it.stackTraceToString()}",
|
||||
result.exception,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
if (returnOnError) return@flow
|
||||
} ?: run {
|
||||
patch.name ?: return@run
|
||||
|
||||
emit(result)
|
||||
executedPatch
|
||||
} catch (exception: PatchException) {
|
||||
PatchResult(patch, exception)
|
||||
} catch (exception: Exception) {
|
||||
PatchResult(patch, PatchException(exception))
|
||||
}
|
||||
|
||||
result.exception?.let {
|
||||
emit(
|
||||
PatchResult(
|
||||
patch,
|
||||
PatchException(
|
||||
"'$patch' raised an exception while being closed: ${it.stackTraceToString()}",
|
||||
result.exception,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
if (returnOnError) return@flow
|
||||
} ?: run {
|
||||
patch.name ?: return@run
|
||||
|
||||
emit(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() = LookupMap.clearLookupMaps()
|
||||
|
|
|
@ -19,14 +19,14 @@ class PatcherContext internal constructor(config: PatcherConfig) {
|
|||
val packageMetadata = PackageMetadata(ApkInfo(ExtFile(config.apkFile)))
|
||||
|
||||
/**
|
||||
* The map of [Patch]es associated by their [PatchClass].
|
||||
* The set of [Patch]es.
|
||||
*/
|
||||
internal val executablePatches = mutableMapOf<PatchClass, Patch<*>>()
|
||||
internal val executablePatches = mutableSetOf<Patch<*>>()
|
||||
|
||||
/**
|
||||
* The map of all [Patch]es and their dependencies associated by their [PatchClass].
|
||||
* The set of all [Patch]es and their dependencies.
|
||||
*/
|
||||
internal val allPatches = mutableMapOf<PatchClass, Patch<*>>()
|
||||
internal val allPatches = mutableSetOf<Patch<*>>()
|
||||
|
||||
/**
|
||||
* A context for the patcher containing the current state of the resources.
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
package app.revanced.patcher
|
||||
|
||||
import java.io.File
|
||||
|
||||
@Deprecated("Use PatcherConfig instead.")
|
||||
data class PatcherOptions(
|
||||
internal val inputFile: File,
|
||||
internal val resourceCachePath: File = File("revanced-resource-cache"),
|
||||
internal val aaptBinaryPath: String? = null,
|
||||
internal val frameworkFileDirectory: String? = null,
|
||||
internal val multithreadingDexFileWriter: Boolean = false,
|
||||
) {
|
||||
@Deprecated("This method will be removed in the future.")
|
||||
fun recreateResourceCacheDirectory(): File {
|
||||
PatcherConfig(
|
||||
inputFile,
|
||||
resourceCachePath,
|
||||
aaptBinaryPath,
|
||||
frameworkFileDirectory,
|
||||
multithreadingDexFileWriter,
|
||||
).initializeTemporaryFilesDirectories()
|
||||
|
||||
return resourceCachePath
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@ package app.revanced.patcher
|
|||
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import kotlin.jvm.internal.Intrinsics
|
||||
|
||||
/**
|
||||
* The result of a patcher.
|
||||
|
@ -15,87 +14,6 @@ class PatcherResult internal constructor(
|
|||
val dexFiles: Set<PatchedDexFile>,
|
||||
val resources: PatchedResources?,
|
||||
) {
|
||||
@Deprecated("This method is not used anymore")
|
||||
constructor(
|
||||
dexFiles: List<PatchedDexFile>,
|
||||
resourceFile: File?,
|
||||
doNotCompress: List<String>? = null,
|
||||
) : this(dexFiles.toSet(), PatchedResources(resourceFile, null, doNotCompress?.toSet() ?: emptySet(), emptySet()))
|
||||
|
||||
@Deprecated("This method is not used anymore")
|
||||
fun component1(): List<PatchedDexFile> {
|
||||
return dexFiles.toList()
|
||||
}
|
||||
|
||||
@Deprecated("This method is not used anymore")
|
||||
fun component2(): File? {
|
||||
return resources?.resourcesApk
|
||||
}
|
||||
|
||||
@Deprecated("This method is not used anymore")
|
||||
fun component3(): List<String>? {
|
||||
return resources?.doNotCompress?.toList()
|
||||
}
|
||||
|
||||
@Deprecated("This method is not used anymore")
|
||||
fun copy(
|
||||
dexFiles: List<PatchedDexFile>,
|
||||
resourceFile: File?,
|
||||
doNotCompress: List<String>? = null,
|
||||
): PatcherResult {
|
||||
return PatcherResult(
|
||||
dexFiles.toSet(),
|
||||
PatchedResources(
|
||||
resourceFile,
|
||||
null,
|
||||
doNotCompress?.toSet() ?: emptySet(),
|
||||
emptySet(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Deprecated("This method is not used anymore")
|
||||
override fun toString(): String {
|
||||
return (("PatcherResult(dexFiles=" + this.dexFiles + ", resourceFile=" + this.resources?.resourcesApk) + ", doNotCompress=" + this.resources?.doNotCompress) + ")"
|
||||
}
|
||||
|
||||
@Deprecated("This method is not used anymore")
|
||||
override fun hashCode(): Int {
|
||||
val result = dexFiles.hashCode()
|
||||
return (
|
||||
(
|
||||
(result * 31) +
|
||||
(if (this.resources?.resourcesApk == null) 0 else this.resources.resourcesApk.hashCode())
|
||||
) * 31
|
||||
) +
|
||||
(if (this.resources?.doNotCompress == null) 0 else this.resources.doNotCompress.hashCode())
|
||||
}
|
||||
|
||||
@Deprecated("This method is not used anymore")
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) {
|
||||
return true
|
||||
}
|
||||
if (other is PatcherResult) {
|
||||
return Intrinsics.areEqual(this.dexFiles, other.dexFiles) && Intrinsics.areEqual(
|
||||
this.resources?.resourcesApk,
|
||||
other.resources?.resourcesApk,
|
||||
) && Intrinsics.areEqual(this.resources?.doNotCompress, other.resources?.doNotCompress)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@Deprecated("This method is not used anymore")
|
||||
fun getDexFiles() = component1()
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@Deprecated("This method is not used anymore")
|
||||
fun getResourceFile() = component2()
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@Deprecated("This method is not used anymore")
|
||||
fun getDoNotCompress() = component3()
|
||||
|
||||
/**
|
||||
* A dex file.
|
||||
|
@ -103,10 +21,7 @@ class PatcherResult internal constructor(
|
|||
* @param name The original name of the dex file.
|
||||
* @param stream The dex file as [InputStream].
|
||||
*/
|
||||
class PatchedDexFile
|
||||
// TODO: Add internal modifier.
|
||||
@Deprecated("This constructor will be removed in the future.")
|
||||
constructor(val name: String, val stream: InputStream)
|
||||
class PatchedDexFile internal constructor(val name: String, val stream: InputStream)
|
||||
|
||||
/**
|
||||
* The resources of a patched apk.
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
package app.revanced.patcher
|
||||
|
||||
import app.revanced.patcher.patch.Patch
|
||||
|
||||
@FunctionalInterface
|
||||
interface PatchesConsumer {
|
||||
@Deprecated("Use acceptPatches(PatchSet) instead.", ReplaceWith("acceptPatches(patches.toSet())"))
|
||||
fun acceptPatches(patches: List<Patch<*>>) = acceptPatches(patches.toSet())
|
||||
fun acceptPatches(patches: PatchSet)
|
||||
}
|
||||
|
|
|
@ -123,7 +123,6 @@ class BytecodeContext internal constructor(private val config: PatcherConfig) :
|
|||
DexIO.DEFAULT_MAX_DEX_POOL_SIZE,
|
||||
) { _, entryName, _ -> logger.info("Compiled $entryName") }
|
||||
}.listFiles(FileFilter { it.isFile })!!.map {
|
||||
@Suppress("DEPRECATION")
|
||||
PatcherResult.PatchedDexFile(it.name, it.inputStream())
|
||||
}.toSet()
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import app.revanced.patcher.PackageMetadata
|
|||
import app.revanced.patcher.PatcherConfig
|
||||
import app.revanced.patcher.PatcherResult
|
||||
import app.revanced.patcher.util.Document
|
||||
import app.revanced.patcher.util.DomFileEditor
|
||||
import brut.androlib.AaptInvoker
|
||||
import brut.androlib.ApkDecoder
|
||||
import brut.androlib.apk.UsesFramework
|
||||
|
@ -15,7 +14,6 @@ import brut.androlib.res.decoder.AndroidManifestResourceParser
|
|||
import brut.androlib.res.decoder.XmlPullStreamDecoder
|
||||
import brut.androlib.res.xml.ResXmlPatcher
|
||||
import brut.directory.ExtFile
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.nio.file.Files
|
||||
|
@ -30,7 +28,7 @@ import java.util.logging.Logger
|
|||
class ResourceContext internal constructor(
|
||||
private val packageMetadata: PackageMetadata,
|
||||
private val config: PatcherConfig,
|
||||
) : Context<PatcherResult.PatchedResources?>, Iterable<File> {
|
||||
) : Context<PatcherResult.PatchedResources?> {
|
||||
private val logger = Logger.getLogger(ResourceContext::class.java.name)
|
||||
|
||||
/**
|
||||
|
@ -38,10 +36,6 @@ class ResourceContext internal constructor(
|
|||
*/
|
||||
val document = DocumentOperatable()
|
||||
|
||||
@Deprecated("Use document instead.")
|
||||
@Suppress("DEPRECATION")
|
||||
val xmlEditor = XmlFileHolder()
|
||||
|
||||
/**
|
||||
* Predicate to delete resources from [PatcherConfig.apkFiles].
|
||||
*/
|
||||
|
@ -213,12 +207,6 @@ class ResourceContext internal constructor(
|
|||
*/
|
||||
fun stageDelete(shouldDelete: (String) -> Boolean) = deleteResources.add(shouldDelete)
|
||||
|
||||
@Deprecated("Use get(String, Boolean) instead.", ReplaceWith("get(path, false)"))
|
||||
operator fun get(path: String) = get(path, false)
|
||||
|
||||
@Deprecated("Use get(String, Boolean) instead.")
|
||||
override fun iterator(): Iterator<File> = config.apkFiles.listFiles()!!.iterator()
|
||||
|
||||
/**
|
||||
* How to handle resources decoding and compiling.
|
||||
*/
|
||||
|
@ -243,18 +231,6 @@ class ResourceContext internal constructor(
|
|||
inner class DocumentOperatable {
|
||||
operator fun get(inputStream: InputStream) = Document(inputStream)
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
operator fun get(path: String) = Document(this@ResourceContext[path])
|
||||
}
|
||||
|
||||
@Deprecated("Use DocumentOperatable instead.")
|
||||
inner class XmlFileHolder {
|
||||
@Suppress("DEPRECATION")
|
||||
operator fun get(inputStream: InputStream) = DomFileEditor(inputStream)
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
operator fun get(path: String): DomFileEditor {
|
||||
return DomFileEditor(this@ResourceContext[path])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
@file:Suppress("UNCHECKED_CAST")
|
||||
|
||||
package app.revanced.patcher.extensions
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
internal object AnnotationExtensions {
|
||||
/**
|
||||
* Search for an annotation recursively.
|
||||
*
|
||||
* @param targetAnnotationClass The annotation class to search for.
|
||||
* @param searchedClasses A set of annotations that have already been searched.
|
||||
* @return The annotation if found, otherwise null.
|
||||
*/
|
||||
fun <T : Annotation> Class<*>.findAnnotationRecursively(
|
||||
targetAnnotationClass: Class<T>,
|
||||
searchedClasses: HashSet<Annotation> = hashSetOf(),
|
||||
): T? {
|
||||
annotations.forEach { annotation ->
|
||||
// Terminate if the annotation is already searched.
|
||||
if (annotation in searchedClasses) return@forEach
|
||||
searchedClasses.add(annotation)
|
||||
|
||||
// Terminate if the annotation is found.
|
||||
if (targetAnnotationClass == annotation.annotationClass.java) return annotation as T
|
||||
|
||||
return annotation.annotationClass.java.findAnnotationRecursively(
|
||||
targetAnnotationClass,
|
||||
searchedClasses,
|
||||
) ?: return@forEach
|
||||
}
|
||||
|
||||
// Search the super class.
|
||||
superclass?.findAnnotationRecursively(
|
||||
targetAnnotationClass,
|
||||
searchedClasses,
|
||||
)?.let { return it }
|
||||
|
||||
// Search the interfaces.
|
||||
interfaces.forEach { superClass ->
|
||||
return superClass.findAnnotationRecursively(
|
||||
targetAnnotationClass,
|
||||
searchedClasses,
|
||||
) ?: return@forEach
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for an annotation recursively.
|
||||
*
|
||||
* First the annotations, then the annotated classes super class and then it's interfaces
|
||||
* are searched for the annotation recursively.
|
||||
*
|
||||
* @param targetAnnotation The annotation to search for.
|
||||
* @return The annotation if found, otherwise null.
|
||||
*/
|
||||
fun <T : Annotation> KClass<*>.findAnnotationRecursively(targetAnnotation: KClass<T>) =
|
||||
java.findAnnotationRecursively(targetAnnotation.java)
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package app.revanced.patcher.extensions
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patcher.fingerprint.annotation.FuzzyPatternScanMethod
|
||||
|
||||
object MethodFingerprintExtensions {
|
||||
/**
|
||||
* The [FuzzyPatternScanMethod] annotation of a [MethodFingerprint].
|
||||
*/
|
||||
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
|
||||
@Deprecated(
|
||||
message = "Use the property instead.",
|
||||
replaceWith = ReplaceWith("this.fuzzyPatternScanMethod"),
|
||||
)
|
||||
val MethodFingerprint.fuzzyPatternScanMethod
|
||||
get() = this.fuzzyPatternScanMethod
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package app.revanced.patcher.fingerprint
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively
|
||||
import app.revanced.patcher.fingerprint.LookupMap.Maps.appendParameters
|
||||
import app.revanced.patcher.fingerprint.LookupMap.Maps.initializeLookupMaps
|
||||
import app.revanced.patcher.fingerprint.LookupMap.Maps.methodSignatureLookupMap
|
||||
|
@ -14,9 +13,9 @@ import com.android.tools.smali.dexlib2.AccessFlags
|
|||
import com.android.tools.smali.dexlib2.Opcode
|
||||
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
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.StringReference
|
||||
import kotlin.reflect.full.findAnnotations
|
||||
|
||||
/**
|
||||
* A fingerprint to resolve methods.
|
||||
|
@ -29,12 +28,12 @@ import com.android.tools.smali.dexlib2.iface.reference.StringReference
|
|||
* @param customFingerprint A custom condition for this fingerprint.
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
abstract class MethodFingerprint(
|
||||
class MethodFingerprint(
|
||||
internal val returnType: String? = null,
|
||||
internal val accessFlags: Int? = null,
|
||||
internal val parameters: Iterable<String>? = null,
|
||||
internal val opcodes: Iterable<Opcode?>? = null,
|
||||
internal val strings: Iterable<String>? = null,
|
||||
internal val parameters: List<String>? = null,
|
||||
internal val opcodes: List<Opcode?>? = null,
|
||||
internal val strings: List<String>? = null,
|
||||
internal val customFingerprint: ((methodDef: Method, classDef: ClassDef) -> Boolean)? = null,
|
||||
) {
|
||||
/**
|
||||
|
@ -48,7 +47,7 @@ abstract class MethodFingerprint(
|
|||
*
|
||||
* If the annotation is not present, this property is null.
|
||||
*/
|
||||
val fuzzyPatternScanMethod = this::class.findAnnotationRecursively(FuzzyPatternScanMethod::class)
|
||||
val fuzzyPatternScanMethod = this::class.findAnnotations(FuzzyPatternScanMethod::class).singleOrNull()
|
||||
|
||||
/**
|
||||
* Resolve a [MethodFingerprint] using the lookup map built by [initializeLookupMaps].
|
||||
|
@ -184,7 +183,8 @@ abstract class MethodFingerprint(
|
|||
|
||||
if (methodFingerprint.parameters != null &&
|
||||
!parametersEqual(
|
||||
methodFingerprint.parameters, // TODO: parseParameters()
|
||||
// TODO: parseParameters()
|
||||
methodFingerprint.parameters,
|
||||
method.parameterTypes,
|
||||
)
|
||||
) {
|
||||
|
@ -231,27 +231,6 @@ abstract class MethodFingerprint(
|
|||
if (methodFingerprint.opcodes != null) {
|
||||
method.implementation?.instructions ?: return false
|
||||
|
||||
fun MethodFingerprintResult.MethodFingerprintScanResult.PatternScanResult.newWarnings(
|
||||
pattern: Iterable<Opcode?>,
|
||||
instructions: Iterable<Instruction>,
|
||||
) = buildList {
|
||||
for ((patternIndex, instructionIndex) in (this@newWarnings.startIndex until this@newWarnings.endIndex).withIndex()) {
|
||||
val originalOpcode = instructions.elementAt(instructionIndex).opcode
|
||||
val patternOpcode = pattern.elementAt(patternIndex)
|
||||
|
||||
if (patternOpcode == null || patternOpcode.ordinal == originalOpcode.ordinal) continue
|
||||
|
||||
this.add(
|
||||
MethodFingerprintResult.MethodFingerprintScanResult.PatternScanResult.Warning(
|
||||
originalOpcode,
|
||||
patternOpcode,
|
||||
instructionIndex,
|
||||
patternIndex,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun Method.patternScan(
|
||||
fingerprint: MethodFingerprint,
|
||||
): MethodFingerprintResult.MethodFingerprintScanResult.PatternScanResult? {
|
||||
|
@ -271,27 +250,21 @@ abstract class MethodFingerprint(
|
|||
val patternOpcode = pattern.elementAt(patternIndex)
|
||||
|
||||
if (patternOpcode != null && patternOpcode.ordinal != originalOpcode.ordinal) {
|
||||
// reaching maximum threshold (0) means,
|
||||
// the pattern does not match to the current instructions
|
||||
// Reaching maximum threshold (0) means,
|
||||
// the pattern does not match to the current instructions.
|
||||
if (threshold-- == 0) break
|
||||
}
|
||||
|
||||
if (patternIndex < patternLength - 1) {
|
||||
// if the entire pattern has not been scanned yet
|
||||
// continue the scan
|
||||
// If the entire pattern has not been scanned yet, continue the scan.
|
||||
patternIndex++
|
||||
continue
|
||||
}
|
||||
// the pattern is valid, generate warnings if fuzzyPatternScanMethod is FuzzyPatternScanMethod
|
||||
val result =
|
||||
MethodFingerprintResult.MethodFingerprintScanResult.PatternScanResult(
|
||||
index,
|
||||
index + patternIndex,
|
||||
)
|
||||
if (fingerprint.fuzzyPatternScanMethod !is FuzzyPatternScanMethod) return result
|
||||
result.warnings = result.newWarnings(pattern, instructions)
|
||||
|
||||
return result
|
||||
// The pattern is valid.
|
||||
return MethodFingerprintResult.MethodFingerprintScanResult.PatternScanResult(
|
||||
index,
|
||||
index + patternIndex,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package app.revanced.patcher.fingerprint
|
|||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.util.proxy.ClassProxy
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
|
@ -69,26 +68,10 @@ class MethodFingerprintResult(
|
|||
* The result of a pattern scan.
|
||||
* @param startIndex The start index of the instructions where to which this pattern matches.
|
||||
* @param endIndex The end index of the instructions where to which this pattern matches.
|
||||
* @param warnings A list of warnings considering this [PatternScanResult].
|
||||
*/
|
||||
class PatternScanResult(
|
||||
val startIndex: Int,
|
||||
val endIndex: Int,
|
||||
var warnings: List<Warning>? = null,
|
||||
) {
|
||||
/**
|
||||
* Represents warnings of the pattern scan.
|
||||
* @param correctOpcode The opcode the instruction list has.
|
||||
* @param wrongOpcode The opcode the pattern list of the signature currently has.
|
||||
* @param instructionIndex The index of the opcode relative to the instruction list.
|
||||
* @param patternIndex The index of the opcode relative to the pattern list from the signature.
|
||||
*/
|
||||
class Warning(
|
||||
val correctOpcode: Opcode,
|
||||
val wrongOpcode: Opcode,
|
||||
val instructionIndex: Int,
|
||||
val patternIndex: Int,
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
package app.revanced.patcher.patch
|
||||
|
||||
import app.revanced.patcher.PatchClass
|
||||
import app.revanced.patcher.Patcher
|
||||
import app.revanced.patcher.PatcherContext
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint.Companion.resolveUsingLookupMap
|
||||
import java.io.Closeable
|
||||
|
||||
/**
|
||||
* A [Patch] that accesses a [BytecodeContext].
|
||||
*
|
||||
* If an implementation of [Patch] also implements [Closeable]
|
||||
* it will be closed in reverse execution order of patches executed by [Patcher].
|
||||
*/
|
||||
@Suppress("unused")
|
||||
abstract class BytecodePatch : Patch<BytecodeContext> {
|
||||
/**
|
||||
* The fingerprints to resolve before executing the patch.
|
||||
*/
|
||||
internal val fingerprints: Set<MethodFingerprint>
|
||||
|
||||
/**
|
||||
* Create a new [BytecodePatch].
|
||||
*
|
||||
* @param fingerprints The fingerprints to resolve before executing the patch.
|
||||
*/
|
||||
constructor(fingerprints: Set<MethodFingerprint> = emptySet()) {
|
||||
this.fingerprints = fingerprints
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new [BytecodePatch].
|
||||
*
|
||||
* @param name The name of the patch.
|
||||
* @param description The description of the patch.
|
||||
* @param compatiblePackages The packages the patch is compatible with.
|
||||
* @param dependencies Other patches this patch depends on.
|
||||
* @param use Weather or not the patch should be used.
|
||||
* @param requiresIntegrations Weather or not the patch requires integrations.
|
||||
*/
|
||||
constructor(
|
||||
name: String? = null,
|
||||
description: String? = null,
|
||||
compatiblePackages: Set<CompatiblePackage>? = null,
|
||||
dependencies: Set<PatchClass>? = null,
|
||||
use: Boolean = true,
|
||||
requiresIntegrations: Boolean = false,
|
||||
fingerprints: Set<MethodFingerprint> = emptySet(),
|
||||
) : super(name, description, compatiblePackages, dependencies, use, requiresIntegrations) {
|
||||
this.fingerprints = fingerprints
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new [BytecodePatch].
|
||||
*/
|
||||
@Deprecated(
|
||||
"Use the constructor with fingerprints instead.",
|
||||
ReplaceWith("BytecodePatch(emptySet())"),
|
||||
)
|
||||
constructor() : this(emptySet())
|
||||
|
||||
override fun execute(context: PatcherContext) {
|
||||
fingerprints.resolveUsingLookupMap(context.bytecodeContext)
|
||||
execute(context.bytecodeContext)
|
||||
}
|
||||
}
|
|
@ -2,132 +2,621 @@
|
|||
|
||||
package app.revanced.patcher.patch
|
||||
|
||||
import app.revanced.patcher.PatchClass
|
||||
import app.revanced.patcher.Patcher
|
||||
import app.revanced.patcher.PatcherContext
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.data.Context
|
||||
import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patcher.patch.options.PatchOption
|
||||
import app.revanced.patcher.patch.options.PatchOptions
|
||||
import java.io.Closeable
|
||||
|
||||
typealias PackageName = String
|
||||
typealias VersionName = String
|
||||
typealias Package = Pair<PackageName, Set<VersionName>>
|
||||
|
||||
/**
|
||||
* A patch.
|
||||
*
|
||||
* If an implementation of [Patch] also implements [Closeable]
|
||||
* it will be closed in reverse execution order of patches executed by [Patcher].
|
||||
* @param C The [Context] type this patch will work on.
|
||||
* @property name The name of the patch.
|
||||
* @property description The description of the patch.
|
||||
* @property use Weather or not the patch should be used.
|
||||
* @property requiresIntegrations Weather or not the patch requires integrations.
|
||||
* @property compatibleWith The packages the patch is compatible with.
|
||||
* @property dependencies Other patches this patch depends on.
|
||||
* @property options The options of the patch.
|
||||
* @property executionBlock The execution block of the patch.
|
||||
* @property close The closing block of the patch. Called after all patches have been executed.
|
||||
*
|
||||
* @param T The [Context] type this patch will work on.
|
||||
* @constructor Creates a new patch.
|
||||
*/
|
||||
sealed class Patch<out T : Context<*>> {
|
||||
/**
|
||||
* The name of the patch.
|
||||
*/
|
||||
var name: String? = null
|
||||
private set
|
||||
|
||||
/**
|
||||
* The description of the patch.
|
||||
*/
|
||||
var description: String? = null
|
||||
private set
|
||||
|
||||
/**
|
||||
* The packages the patch is compatible with.
|
||||
*/
|
||||
var compatiblePackages: Set<CompatiblePackage>? = null
|
||||
private set
|
||||
|
||||
/**
|
||||
* Other patches this patch depends on.
|
||||
*/
|
||||
var dependencies: Set<PatchClass>? = null
|
||||
private set
|
||||
|
||||
/**
|
||||
* Weather or not the patch should be used.
|
||||
*/
|
||||
var use = true
|
||||
private set
|
||||
|
||||
// TODO: Remove this property, once integrations are coupled with patches.
|
||||
/**
|
||||
* Weather or not the patch requires integrations.
|
||||
*/
|
||||
var requiresIntegrations = false
|
||||
private set
|
||||
|
||||
constructor(
|
||||
name: String?,
|
||||
description: String?,
|
||||
compatiblePackages: Set<CompatiblePackage>?,
|
||||
dependencies: Set<PatchClass>?,
|
||||
use: Boolean,
|
||||
requiresIntegrations: Boolean,
|
||||
) {
|
||||
this.name = name
|
||||
this.description = description
|
||||
this.compatiblePackages = compatiblePackages
|
||||
this.dependencies = dependencies
|
||||
this.use = use
|
||||
this.requiresIntegrations = requiresIntegrations
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this::class.findAnnotationRecursively(app.revanced.patcher.patch.annotation.Patch::class)?.let { annotation ->
|
||||
this.name = annotation.name.ifEmpty { null }
|
||||
this.description = annotation.description.ifEmpty { null }
|
||||
this.compatiblePackages =
|
||||
annotation.compatiblePackages
|
||||
.map { CompatiblePackage(it.name, it.versions.toSet().ifEmpty { null }) }
|
||||
.toSet().ifEmpty { null }
|
||||
this.dependencies = annotation.dependencies.toSet().ifEmpty { null }
|
||||
this.use = annotation.use
|
||||
this.requiresIntegrations = annotation.requiresIntegrations
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The options of the patch associated by the options key.
|
||||
*/
|
||||
sealed class Patch<C : Context<*>>(
|
||||
val name: String?,
|
||||
val description: String?,
|
||||
val use: Boolean,
|
||||
val requiresIntegrations: Boolean,
|
||||
) {
|
||||
val compatiblePackages = mutableSetOf<Package>()
|
||||
val dependencies = mutableSetOf<Patch<*>>()
|
||||
val options = PatchOptions()
|
||||
|
||||
private var executionBlock: ((C) -> Unit)? = null
|
||||
private var close: ((C) -> Unit)? = null
|
||||
|
||||
/**
|
||||
* The execution function of the patch.
|
||||
* This function is called by [Patcher].
|
||||
* Adds compatible packages to the patch.
|
||||
*
|
||||
* @param context The [PatcherContext] the patch will work on.
|
||||
* @param block The block to build the compatible packages.
|
||||
*/
|
||||
fun compatibleWith(block: CompatiblePackages.() -> Unit) {
|
||||
compatiblePackages.addAll(CompatiblePackages().apply(block).packages)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds dependencies to the patch.
|
||||
*
|
||||
* @param patch The patches this patch depends on.
|
||||
*/
|
||||
fun dependsOn(vararg patch: Patch<*>) {
|
||||
dependencies.addAll(patch)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the execution block of the patch.
|
||||
*
|
||||
* @param block The execution block of the patch.
|
||||
*/
|
||||
fun execute(block: C.() -> Unit) {
|
||||
executionBlock = block
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the execution block of the patch.
|
||||
*/
|
||||
fun execute(context: C) {
|
||||
executionBlock?.invoke(context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the execution block of the patch.
|
||||
* Called by [Patcher].
|
||||
*
|
||||
* @param context The [PatcherContext] to execute the patch on.
|
||||
*/
|
||||
internal abstract fun execute(context: PatcherContext)
|
||||
|
||||
/**
|
||||
* The execution function of the patch.
|
||||
* Sets the closing block of the patch.
|
||||
*
|
||||
* @param context The [Context] the patch will work on.
|
||||
* @return The result of executing the patch.
|
||||
* @param block The closing block of the patch.
|
||||
*/
|
||||
abstract fun execute(context: @UnsafeVariance T)
|
||||
|
||||
override fun hashCode() = name.hashCode()
|
||||
|
||||
override fun toString() = name ?: this::class.simpleName ?: "Unnamed patch"
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as Patch<*>
|
||||
|
||||
return name == other.name
|
||||
fun close(block: C.() -> Unit) {
|
||||
close = block
|
||||
}
|
||||
|
||||
/**
|
||||
* A package a [Patch] is compatible with.
|
||||
*
|
||||
* @param name The name of the package.
|
||||
* @param versions The versions of the package.
|
||||
* Runs the closing block of the patch.
|
||||
*/
|
||||
class CompatiblePackage(
|
||||
val name: String,
|
||||
val versions: Set<String>? = null,
|
||||
fun close(context: C) {
|
||||
close?.invoke(context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the closing block of the patch.
|
||||
*/
|
||||
internal abstract fun close(context: PatcherContext)
|
||||
|
||||
/**
|
||||
* Create a new [PatchOption] with a string value and add it to the current [Patch].
|
||||
*
|
||||
* @param key The key.
|
||||
* @param default The default value.
|
||||
* @param values Eligible patch option values mapped to a human-readable name.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
* @param validator The function to validate the option value.
|
||||
*
|
||||
* @return The created [PatchOption].
|
||||
*
|
||||
* @see PatchOption
|
||||
*/
|
||||
fun stringPatchOption(
|
||||
key: String,
|
||||
default: String? = null,
|
||||
values: Map<String, String?>? = null,
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: PatchOption<String>.(String?) -> Boolean = { true },
|
||||
) = registerNewPatchOption(
|
||||
key,
|
||||
default,
|
||||
values,
|
||||
title,
|
||||
description,
|
||||
required,
|
||||
"String",
|
||||
validator,
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new [PatchOption] with an integer value and add it to the current [Patch].
|
||||
*
|
||||
* @param key The key.
|
||||
* @param default The default value.
|
||||
* @param values Eligible patch option values mapped to a human-readable name.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
* @param validator The function to validate the option value.
|
||||
*
|
||||
* @return The created [PatchOption].
|
||||
*
|
||||
* @see PatchOption
|
||||
*/
|
||||
fun intPatchOption(
|
||||
key: String,
|
||||
default: Int? = null,
|
||||
values: Map<String, Int?>? = null,
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: PatchOption<Int?>.(Int?) -> Boolean = { true },
|
||||
) = registerNewPatchOption(
|
||||
key,
|
||||
default,
|
||||
values,
|
||||
title,
|
||||
description,
|
||||
required,
|
||||
"Int",
|
||||
validator,
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new [PatchOption] with a boolean value and add it to the current [Patch].
|
||||
*
|
||||
* @param key The key.
|
||||
* @param default The default value.
|
||||
* @param values Eligible patch option values mapped to a human-readable name.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
* @param validator The function to validate the option value.
|
||||
*
|
||||
* @return The created [PatchOption].
|
||||
*
|
||||
* @see PatchOption
|
||||
*/
|
||||
fun booleanPatchOption(
|
||||
key: String,
|
||||
default: Boolean? = null,
|
||||
values: Map<String, Boolean?>? = null,
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: PatchOption<Boolean?>.(Boolean?) -> Boolean = { true },
|
||||
) = registerNewPatchOption(
|
||||
key,
|
||||
default,
|
||||
values,
|
||||
title,
|
||||
description,
|
||||
required,
|
||||
"Boolean",
|
||||
validator,
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new [PatchOption] with a float value and add it to the current [Patch].
|
||||
*
|
||||
* @param key The key.
|
||||
* @param default The default value.
|
||||
* @param values Eligible patch option values mapped to a human-readable name.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
* @param validator The function to validate the option value.
|
||||
*
|
||||
* @return The created [PatchOption].
|
||||
*
|
||||
* @see PatchOption
|
||||
*/
|
||||
fun floatPatchOption(
|
||||
key: String,
|
||||
default: Float? = null,
|
||||
values: Map<String, Float?>? = null,
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: PatchOption<Float?>.(Float?) -> Boolean = { true },
|
||||
) = registerNewPatchOption(
|
||||
key,
|
||||
default,
|
||||
values,
|
||||
title,
|
||||
description,
|
||||
required,
|
||||
"Float",
|
||||
validator,
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new [PatchOption] with a long value and add it to the current [Patch].
|
||||
*
|
||||
* @param key The key.
|
||||
* @param default The default value.
|
||||
* @param values Eligible patch option values mapped to a human-readable name.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
* @param validator The function to validate the option value.
|
||||
*
|
||||
* @return The created [PatchOption].
|
||||
*
|
||||
* @see PatchOption
|
||||
*/
|
||||
fun longPatchOption(
|
||||
key: String,
|
||||
default: Long? = null,
|
||||
values: Map<String, Long?>? = null,
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: PatchOption<Long?>.(Long?) -> Boolean = { true },
|
||||
) = registerNewPatchOption(
|
||||
key,
|
||||
default,
|
||||
values,
|
||||
title,
|
||||
description,
|
||||
required,
|
||||
"Long",
|
||||
validator,
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new [PatchOption] with a string array value and add it to the current [Patch].
|
||||
*
|
||||
* @param key The key.
|
||||
* @param default The default value.
|
||||
* @param values Eligible patch option values mapped to a human-readable name.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
* @param validator The function to validate the option value.
|
||||
*
|
||||
* @return The created [PatchOption].
|
||||
*
|
||||
* @see PatchOption
|
||||
*/
|
||||
fun stringArrayPatchOption(
|
||||
key: String,
|
||||
default: Array<String>? = null,
|
||||
values: Map<String, Array<String>?>? = null,
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: PatchOption<Array<String>?>.(Array<String>?) -> Boolean = { true },
|
||||
) = registerNewPatchOption(
|
||||
key,
|
||||
default,
|
||||
values,
|
||||
title,
|
||||
description,
|
||||
required,
|
||||
"StringArray",
|
||||
validator,
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new [PatchOption] with an integer array value and add it to the current [Patch].
|
||||
*
|
||||
* @param key The key.
|
||||
* @param default The default value.
|
||||
* @param values Eligible patch option values mapped to a human-readable name.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
* @param validator The function to validate the option value.
|
||||
*
|
||||
* @return The created [PatchOption].
|
||||
*
|
||||
* @see PatchOption
|
||||
*/
|
||||
fun intArrayPatchOption(
|
||||
key: String,
|
||||
default: Array<Int>? = null,
|
||||
values: Map<String, Array<Int>?>? = null,
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: PatchOption<Array<Int>?>.(Array<Int>?) -> Boolean = { true },
|
||||
) = registerNewPatchOption(
|
||||
key,
|
||||
default,
|
||||
values,
|
||||
title,
|
||||
description,
|
||||
required,
|
||||
"IntArray",
|
||||
validator,
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new [PatchOption] with a boolean array value and add it to the current [Patch].
|
||||
*
|
||||
* @param key The key.
|
||||
* @param default The default value.
|
||||
* @param values Eligible patch option values mapped to a human-readable name.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
* @param validator The function to validate the option value.
|
||||
*
|
||||
* @return The created [PatchOption].
|
||||
*
|
||||
* @see PatchOption
|
||||
*/
|
||||
fun booleanArrayPatchOption(
|
||||
key: String,
|
||||
default: Array<Boolean>? = null,
|
||||
values: Map<String, Array<Boolean>?>? = null,
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: PatchOption<Array<Boolean>?>.(Array<Boolean>?) -> Boolean = { true },
|
||||
) = registerNewPatchOption(
|
||||
key,
|
||||
default,
|
||||
values,
|
||||
title,
|
||||
description,
|
||||
required,
|
||||
"BooleanArray",
|
||||
validator,
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new [PatchOption] with a float array value and add it to the current [Patch].
|
||||
*
|
||||
* @param key The key.
|
||||
* @param default The default value.
|
||||
* @param values Eligible patch option values mapped to a human-readable name.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
* @param validator The function to validate the option value.
|
||||
*
|
||||
* @return The created [PatchOption].
|
||||
*
|
||||
* @see PatchOption
|
||||
*/
|
||||
fun floatArrayPatchOption(
|
||||
key: String,
|
||||
default: Array<Float>? = null,
|
||||
values: Map<String, Array<Float>?>? = null,
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: PatchOption<Array<Float>?>.(Array<Float>?) -> Boolean = { true },
|
||||
) = registerNewPatchOption(
|
||||
key,
|
||||
default,
|
||||
values,
|
||||
title,
|
||||
description,
|
||||
required,
|
||||
"FloatArray",
|
||||
validator,
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new [PatchOption] with a long array value and add it to the current [Patch].
|
||||
*
|
||||
* @param key The key.
|
||||
* @param default The default value.
|
||||
* @param values Eligible patch option values mapped to a human-readable name.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
* @param validator The function to validate the option value.
|
||||
*
|
||||
* @return The created [PatchOption].
|
||||
*
|
||||
* @see PatchOption
|
||||
*/
|
||||
fun longArrayPatchOption(
|
||||
key: String,
|
||||
default: Array<Long>? = null,
|
||||
values: Map<String, Array<Long>?>? = null,
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: PatchOption<Array<Long>?>.(Array<Long>?) -> Boolean = { true },
|
||||
) = registerNewPatchOption(
|
||||
key,
|
||||
default,
|
||||
values,
|
||||
title,
|
||||
description,
|
||||
required,
|
||||
"LongArray",
|
||||
validator,
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new [PatchOption] and add it to the current [Patch].
|
||||
*
|
||||
* @param key The key.
|
||||
* @param default The default value.
|
||||
* @param values Eligible patch option values mapped to a human-readable name.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
* @param valueType The type of the option value (to handle type erasure).
|
||||
* @param validator The function to validate the option value.
|
||||
*
|
||||
* @return The created [PatchOption].
|
||||
*
|
||||
* @see PatchOption
|
||||
*/
|
||||
fun <T> registerNewPatchOption(
|
||||
key: String,
|
||||
default: T? = null,
|
||||
values: Map<String, T?>? = null,
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
valueType: String,
|
||||
validator: PatchOption<T>.(T?) -> Boolean = { true },
|
||||
) = PatchOption(
|
||||
key,
|
||||
default,
|
||||
values,
|
||||
title,
|
||||
description,
|
||||
required,
|
||||
valueType,
|
||||
validator,
|
||||
).also(options::register)
|
||||
|
||||
override fun toString() = name ?: "Patch"
|
||||
|
||||
class CompatiblePackages {
|
||||
internal val packages = mutableSetOf<Package>()
|
||||
|
||||
operator fun String.invoke(vararg versions: String) {
|
||||
packages.add(this to versions.toSet())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A bytecode patch builder.
|
||||
*
|
||||
* @param name The name of the patch.
|
||||
* @param description The description of the patch.
|
||||
* @param use Weather or not the patch should be used.
|
||||
* @param requiresIntegrations Weather or not the patch requires integrations.
|
||||
*
|
||||
* @property fingerprints The fingerprints of the patch. Resolved before the patch is executed.
|
||||
*
|
||||
* @constructor Creates a new bytecode patch builder.
|
||||
*/
|
||||
class BytecodePatch internal constructor(
|
||||
name: String?,
|
||||
description: String?,
|
||||
use: Boolean,
|
||||
requiresIntegrations: Boolean,
|
||||
) : Patch<BytecodeContext>(name, description, use, requiresIntegrations) {
|
||||
internal val fingerprints = mutableSetOf<MethodFingerprint>()
|
||||
|
||||
/**
|
||||
* Adds fingerprints to the patch.
|
||||
*
|
||||
* @param fingerprint The fingerprints to add.
|
||||
*/
|
||||
fun fingerprints(vararg fingerprint: MethodFingerprint) {
|
||||
fingerprints.addAll(fingerprint)
|
||||
}
|
||||
|
||||
override fun execute(context: PatcherContext) = execute(context.bytecodeContext)
|
||||
override fun close(context: PatcherContext) = close(context.bytecodeContext)
|
||||
}
|
||||
|
||||
/**
|
||||
* A raw resource patch builder.
|
||||
*
|
||||
* @param name The name of the patch.
|
||||
* @param description The description of the patch.
|
||||
* @param use Weather or not the patch should be used.
|
||||
* @param requiresIntegrations Weather or not the patch requires integrations.
|
||||
*
|
||||
* @constructor Creates a new raw resource patch builder.
|
||||
*/
|
||||
class RawResourcePatch internal constructor(
|
||||
name: String?,
|
||||
description: String?,
|
||||
use: Boolean,
|
||||
requiresIntegrations: Boolean,
|
||||
) : Patch<ResourceContext>(name, description, use, requiresIntegrations) {
|
||||
override fun execute(context: PatcherContext) = execute(context.resourceContext)
|
||||
override fun close(context: PatcherContext) = close(context.resourceContext)
|
||||
}
|
||||
|
||||
/**
|
||||
* A resource patch builder.
|
||||
*
|
||||
* @param name The name of the patch.
|
||||
* @param description The description of the patch.
|
||||
* @param use Weather or not the patch should be used.
|
||||
* @param requiresIntegrations Weather or not the patch requires integrations.
|
||||
*
|
||||
* @constructor Creates a new resource patch builder.
|
||||
*/
|
||||
class ResourcePatch internal constructor(
|
||||
name: String?,
|
||||
description: String?,
|
||||
use: Boolean,
|
||||
requiresIntegrations: Boolean,
|
||||
) : Patch<ResourceContext>(name, description, use, requiresIntegrations) {
|
||||
override fun execute(context: PatcherContext) = execute(context.resourceContext)
|
||||
override fun close(context: PatcherContext) = close(context.resourceContext)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new [BytecodePatch].
|
||||
*
|
||||
* @param name The name of the patch.
|
||||
* @param description The description of the patch.
|
||||
* @param use Weather or not the patch should be used.
|
||||
* @param requiresIntegrations Weather or not the patch requires integrations.
|
||||
* @param block The block to build the patch.
|
||||
* @return The created [BytecodePatch].
|
||||
*/
|
||||
fun bytecodePatch(
|
||||
name: String? = null,
|
||||
description: String? = null,
|
||||
use: Boolean = true,
|
||||
requiresIntegrations: Boolean = false,
|
||||
block: BytecodePatch.() -> Unit = {},
|
||||
) = BytecodePatch(name, description, use, requiresIntegrations).apply(block)
|
||||
|
||||
/**
|
||||
* Creates a new [RawResourcePatch].
|
||||
*
|
||||
* @param name The name of the patch.
|
||||
* @param description The description of the patch.
|
||||
* @param use Weather or not the patch should be used.
|
||||
* @param requiresIntegrations Weather or not the patch requires integrations.
|
||||
* @param block The block to build the patch.
|
||||
* @return The created [RawResourcePatch].
|
||||
*/
|
||||
fun rawResourcePatch(
|
||||
name: String? = null,
|
||||
description: String? = null,
|
||||
use: Boolean = true,
|
||||
requiresIntegrations: Boolean = false,
|
||||
block: RawResourcePatch.() -> Unit = {},
|
||||
) = RawResourcePatch(name, description, use, requiresIntegrations).apply(block)
|
||||
|
||||
/**
|
||||
* Creates a new [ResourcePatch].
|
||||
*
|
||||
* @param name The name of the patch.
|
||||
* @param description The description of the patch.
|
||||
* @param use Weather or not the patch should be used.
|
||||
* @param requiresIntegrations Weather or not the patch requires integrations.
|
||||
* @param block The block to build the patch.
|
||||
* @return The created [ResourcePatch].
|
||||
*/
|
||||
fun resourcePatch(
|
||||
name: String? = null,
|
||||
description: String? = null,
|
||||
use: Boolean = true,
|
||||
requiresIntegrations: Boolean = false,
|
||||
block: ResourcePatch.() -> Unit = {},
|
||||
) = ResourcePatch(name, description, use, requiresIntegrations).apply(block)
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
package app.revanced.patcher.patch
|
||||
|
||||
import app.revanced.patcher.PatchClass
|
||||
import app.revanced.patcher.Patcher
|
||||
import app.revanced.patcher.PatcherContext
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import java.io.Closeable
|
||||
|
||||
/**
|
||||
* A [Patch] that accesses a [ResourceContext].
|
||||
*
|
||||
* If an implementation of [Patch] also implements [Closeable]
|
||||
* it will be closed in reverse execution order of patches executed by [Patcher].
|
||||
*
|
||||
* This type of patch that does not have access to decoded resources.
|
||||
* Instead, you can read and write arbitrary files in an APK file.
|
||||
*
|
||||
* If you want to access decoded resources, use [ResourcePatch] instead.
|
||||
*/
|
||||
abstract class RawResourcePatch : Patch<ResourceContext> {
|
||||
/**
|
||||
* Create a new [RawResourcePatch].
|
||||
*/
|
||||
constructor()
|
||||
|
||||
/**
|
||||
* Create a new [RawResourcePatch].
|
||||
*
|
||||
* @param name The name of the patch.
|
||||
* @param description The description of the patch.
|
||||
* @param compatiblePackages The packages the patch is compatible with.
|
||||
* @param dependencies Other patches this patch depends on.
|
||||
* @param use Weather or not the patch should be used.
|
||||
* @param requiresIntegrations Weather or not the patch requires integrations.
|
||||
*/
|
||||
constructor(
|
||||
name: String? = null,
|
||||
description: String? = null,
|
||||
compatiblePackages: Set<CompatiblePackage>? = null,
|
||||
dependencies: Set<PatchClass>? = null,
|
||||
use: Boolean = true,
|
||||
requiresIntegrations: Boolean = false,
|
||||
) : super(name, description, compatiblePackages, dependencies, use, requiresIntegrations)
|
||||
|
||||
override fun execute(context: PatcherContext) = execute(context.resourceContext)
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
package app.revanced.patcher.patch
|
||||
|
||||
import app.revanced.patcher.PatchClass
|
||||
import app.revanced.patcher.Patcher
|
||||
import app.revanced.patcher.PatcherContext
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import java.io.Closeable
|
||||
|
||||
/**
|
||||
* A [Patch] that accesses a [ResourceContext].
|
||||
*
|
||||
* If an implementation of [Patch] also implements [Closeable]
|
||||
* it will be closed in reverse execution order of patches executed by [Patcher].
|
||||
*
|
||||
* This type of patch has access to decoded resources.
|
||||
* Additionally, you can read and write arbitrary files in an APK file.
|
||||
*
|
||||
* If you do not need access to decoded resources, use [RawResourcePatch] instead.
|
||||
*/
|
||||
abstract class ResourcePatch : Patch<ResourceContext> {
|
||||
/**
|
||||
* Create a new [ResourcePatch].
|
||||
*/
|
||||
constructor()
|
||||
|
||||
/**
|
||||
* Create a new [ResourcePatch].
|
||||
*
|
||||
* @param name The name of the patch.
|
||||
* @param description The description of the patch.
|
||||
* @param compatiblePackages The packages the patch is compatible with.
|
||||
* @param dependencies Other patches this patch depends on.
|
||||
* @param use Weather or not the patch should be used.
|
||||
* @param requiresIntegrations Weather or not the patch requires integrations.
|
||||
*/
|
||||
constructor(
|
||||
name: String? = null,
|
||||
description: String? = null,
|
||||
compatiblePackages: Set<CompatiblePackage>? = null,
|
||||
dependencies: Set<PatchClass>? = null,
|
||||
use: Boolean = true,
|
||||
requiresIntegrations: Boolean = false,
|
||||
) : super(name, description, compatiblePackages, dependencies, use, requiresIntegrations)
|
||||
|
||||
override fun execute(context: PatcherContext) = execute(context.resourceContext)
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package app.revanced.patcher.patch.annotation
|
||||
|
||||
import java.lang.annotation.Inherited
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Annotation for [app.revanced.patcher.patch.Patch] classes.
|
||||
*
|
||||
* @param name The name of the patch. If empty, the patch will be unnamed.
|
||||
* @param description The description of the patch. If empty, no description will be used.
|
||||
* @param dependencies The patches this patch depends on.
|
||||
* @param compatiblePackages The packages this patch is compatible with.
|
||||
* @param use Whether this patch should be used.
|
||||
* @param requiresIntegrations Whether this patch requires integrations.
|
||||
*/
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Inherited
|
||||
annotation class Patch(
|
||||
val name: String = "",
|
||||
val description: String = "",
|
||||
val dependencies: Array<KClass<out app.revanced.patcher.patch.Patch<*>>> = [],
|
||||
val compatiblePackages: Array<CompatiblePackage> = [],
|
||||
val use: Boolean = true,
|
||||
// TODO: Remove this property, once integrations are coupled with patches.
|
||||
val requiresIntegrations: Boolean = false,
|
||||
)
|
||||
|
||||
/**
|
||||
* A package that a [app.revanced.patcher.patch.Patch] is compatible with.
|
||||
*
|
||||
* @param name The name of the package.
|
||||
* @param versions The versions of the package.
|
||||
*/
|
||||
annotation class CompatiblePackage(
|
||||
val name: String,
|
||||
val versions: Array<String> = [],
|
||||
)
|
|
@ -6,9 +6,9 @@ import kotlin.reflect.KProperty
|
|||
/**
|
||||
* A [Patch] option.
|
||||
*
|
||||
* @param key The identifier.
|
||||
* @param key The key.
|
||||
* @param default The default value.
|
||||
* @param values The set of guaranteed valid values identified by their string representation.
|
||||
* @param values Eligible patch option values mapped to a human-readable name.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
|
@ -94,383 +94,4 @@ open class PatchOption<T>(
|
|||
) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
companion object PatchExtensions {
|
||||
/**
|
||||
* Create a new [PatchOption] with a string value and add it to the current [Patch].
|
||||
*
|
||||
* @param key The identifier.
|
||||
* @param default The default value.
|
||||
* @param values The set of guaranteed valid values.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
* @param validator The function to validate the option value.
|
||||
*
|
||||
* @return The created [PatchOption].
|
||||
*
|
||||
* @see PatchOption
|
||||
*/
|
||||
fun <P : Patch<*>> P.stringPatchOption(
|
||||
key: String,
|
||||
default: String? = null,
|
||||
values: Map<String, String?>? = null,
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: PatchOption<String>.(String?) -> Boolean = { true },
|
||||
) = registerNewPatchOption(
|
||||
key,
|
||||
default,
|
||||
values,
|
||||
title,
|
||||
description,
|
||||
required,
|
||||
"String",
|
||||
validator,
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new [PatchOption] with an integer value and add it to the current [Patch].
|
||||
*
|
||||
* @param key The identifier.
|
||||
* @param default The default value.
|
||||
* @param values The set of guaranteed valid values.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
* @param validator The function to validate the option value.
|
||||
*
|
||||
* @return The created [PatchOption].
|
||||
*
|
||||
* @see PatchOption
|
||||
*/
|
||||
fun <P : Patch<*>> P.intPatchOption(
|
||||
key: String,
|
||||
default: Int? = null,
|
||||
values: Map<String, Int?>? = null,
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: PatchOption<Int?>.(Int?) -> Boolean = { true },
|
||||
) = registerNewPatchOption(
|
||||
key,
|
||||
default,
|
||||
values,
|
||||
title,
|
||||
description,
|
||||
required,
|
||||
"Int",
|
||||
validator,
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new [PatchOption] with a boolean value and add it to the current [Patch].
|
||||
*
|
||||
* @param key The identifier.
|
||||
* @param default The default value.
|
||||
* @param values The set of guaranteed valid values.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
* @param validator The function to validate the option value.
|
||||
*
|
||||
* @return The created [PatchOption].
|
||||
*
|
||||
* @see PatchOption
|
||||
*/
|
||||
fun <P : Patch<*>> P.booleanPatchOption(
|
||||
key: String,
|
||||
default: Boolean? = null,
|
||||
values: Map<String, Boolean?>? = null,
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: PatchOption<Boolean?>.(Boolean?) -> Boolean = { true },
|
||||
) = registerNewPatchOption(
|
||||
key,
|
||||
default,
|
||||
values,
|
||||
title,
|
||||
description,
|
||||
required,
|
||||
"Boolean",
|
||||
validator,
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new [PatchOption] with a float value and add it to the current [Patch].
|
||||
*
|
||||
* @param key The identifier.
|
||||
* @param default The default value.
|
||||
* @param values The set of guaranteed valid values.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
* @param validator The function to validate the option value.
|
||||
*
|
||||
* @return The created [PatchOption].
|
||||
*
|
||||
* @see PatchOption
|
||||
*/
|
||||
fun <P : Patch<*>> P.floatPatchOption(
|
||||
key: String,
|
||||
default: Float? = null,
|
||||
values: Map<String, Float?>? = null,
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: PatchOption<Float?>.(Float?) -> Boolean = { true },
|
||||
) = registerNewPatchOption(
|
||||
key,
|
||||
default,
|
||||
values,
|
||||
title,
|
||||
description,
|
||||
required,
|
||||
"Float",
|
||||
validator,
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new [PatchOption] with a long value and add it to the current [Patch].
|
||||
*
|
||||
* @param key The identifier.
|
||||
* @param default The default value.
|
||||
* @param values The set of guaranteed valid values.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
* @param validator The function to validate the option value.
|
||||
*
|
||||
* @return The created [PatchOption].
|
||||
*
|
||||
* @see PatchOption
|
||||
*/
|
||||
fun <P : Patch<*>> P.longPatchOption(
|
||||
key: String,
|
||||
default: Long? = null,
|
||||
values: Map<String, Long?>? = null,
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: PatchOption<Long?>.(Long?) -> Boolean = { true },
|
||||
) = registerNewPatchOption(
|
||||
key,
|
||||
default,
|
||||
values,
|
||||
title,
|
||||
description,
|
||||
required,
|
||||
"Long",
|
||||
validator,
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new [PatchOption] with a string array value and add it to the current [Patch].
|
||||
*
|
||||
* @param key The identifier.
|
||||
* @param default The default value.
|
||||
* @param values The set of guaranteed valid values.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
* @param validator The function to validate the option value.
|
||||
*
|
||||
* @return The created [PatchOption].
|
||||
*
|
||||
* @see PatchOption
|
||||
*/
|
||||
fun <P : Patch<*>> P.stringArrayPatchOption(
|
||||
key: String,
|
||||
default: Array<String>? = null,
|
||||
values: Map<String, Array<String>?>? = null,
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: PatchOption<Array<String>?>.(Array<String>?) -> Boolean = { true },
|
||||
) = registerNewPatchOption(
|
||||
key,
|
||||
default,
|
||||
values,
|
||||
title,
|
||||
description,
|
||||
required,
|
||||
"StringArray",
|
||||
validator,
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new [PatchOption] with an integer array value and add it to the current [Patch].
|
||||
*
|
||||
* @param key The identifier.
|
||||
* @param default The default value.
|
||||
* @param values The set of guaranteed valid values.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
* @param validator The function to validate the option value.
|
||||
*
|
||||
* @return The created [PatchOption].
|
||||
*
|
||||
* @see PatchOption
|
||||
*/
|
||||
fun <P : Patch<*>> P.intArrayPatchOption(
|
||||
key: String,
|
||||
default: Array<Int>? = null,
|
||||
values: Map<String, Array<Int>?>? = null,
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: PatchOption<Array<Int>?>.(Array<Int>?) -> Boolean = { true },
|
||||
) = registerNewPatchOption(
|
||||
key,
|
||||
default,
|
||||
values,
|
||||
title,
|
||||
description,
|
||||
required,
|
||||
"IntArray",
|
||||
validator,
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new [PatchOption] with a boolean array value and add it to the current [Patch].
|
||||
*
|
||||
* @param key The identifier.
|
||||
* @param default The default value.
|
||||
* @param values The set of guaranteed valid values.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
* @param validator The function to validate the option value.
|
||||
*
|
||||
* @return The created [PatchOption].
|
||||
*
|
||||
* @see PatchOption
|
||||
*/
|
||||
fun <P : Patch<*>> P.booleanArrayPatchOption(
|
||||
key: String,
|
||||
default: Array<Boolean>? = null,
|
||||
values: Map<String, Array<Boolean>?>? = null,
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: PatchOption<Array<Boolean>?>.(Array<Boolean>?) -> Boolean = { true },
|
||||
) = registerNewPatchOption(
|
||||
key,
|
||||
default,
|
||||
values,
|
||||
title,
|
||||
description,
|
||||
required,
|
||||
"BooleanArray",
|
||||
validator,
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new [PatchOption] with a float array value and add it to the current [Patch].
|
||||
*
|
||||
* @param key The identifier.
|
||||
* @param default The default value.
|
||||
* @param values The set of guaranteed valid values.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
* @param validator The function to validate the option value.
|
||||
*
|
||||
* @return The created [PatchOption].
|
||||
*
|
||||
* @see PatchOption
|
||||
*/
|
||||
fun <P : Patch<*>> P.floatArrayPatchOption(
|
||||
key: String,
|
||||
default: Array<Float>? = null,
|
||||
values: Map<String, Array<Float>?>? = null,
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: PatchOption<Array<Float>?>.(Array<Float>?) -> Boolean = { true },
|
||||
) = registerNewPatchOption(
|
||||
key,
|
||||
default,
|
||||
values,
|
||||
title,
|
||||
description,
|
||||
required,
|
||||
"FloatArray",
|
||||
validator,
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new [PatchOption] with a long array value and add it to the current [Patch].
|
||||
*
|
||||
* @param key The identifier.
|
||||
* @param default The default value.
|
||||
* @param values The set of guaranteed valid values.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
* @param validator The function to validate the option value.
|
||||
*
|
||||
* @return The created [PatchOption].
|
||||
*
|
||||
* @see PatchOption
|
||||
*/
|
||||
fun <P : Patch<*>> P.longArrayPatchOption(
|
||||
key: String,
|
||||
default: Array<Long>? = null,
|
||||
values: Map<String, Array<Long>?>? = null,
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
validator: PatchOption<Array<Long>?>.(Array<Long>?) -> Boolean = { true },
|
||||
) = registerNewPatchOption(
|
||||
key,
|
||||
default,
|
||||
values,
|
||||
title,
|
||||
description,
|
||||
required,
|
||||
"LongArray",
|
||||
validator,
|
||||
)
|
||||
|
||||
/**
|
||||
* Create a new [PatchOption] and add it to the current [Patch].
|
||||
*
|
||||
* @param key The identifier.
|
||||
* @param default The default value.
|
||||
* @param values The set of guaranteed valid values identified by their string representation.
|
||||
* @param title The title.
|
||||
* @param description A description.
|
||||
* @param required Whether the option is required.
|
||||
* @param valueType The type of the option value (to handle type erasure).
|
||||
* @param validator The function to validate the option value.
|
||||
*
|
||||
* @return The created [PatchOption].
|
||||
*
|
||||
* @see PatchOption
|
||||
*/
|
||||
fun <P : Patch<*>, T> P.registerNewPatchOption(
|
||||
key: String,
|
||||
default: T? = null,
|
||||
values: Map<String, T?>? = null,
|
||||
title: String? = null,
|
||||
description: String? = null,
|
||||
required: Boolean = false,
|
||||
valueType: String,
|
||||
validator: PatchOption<T>.(T?) -> Boolean = { true },
|
||||
) = PatchOption(
|
||||
key,
|
||||
default,
|
||||
values,
|
||||
title,
|
||||
description,
|
||||
required,
|
||||
valueType,
|
||||
validator,
|
||||
).also(options::register)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ class PatchOptions internal constructor(
|
|||
|
||||
/**
|
||||
* Set an option's value.
|
||||
* @param key The identifier.
|
||||
* @param key The key.
|
||||
* @param value The value.
|
||||
* @throws PatchOptionException.PatchOptionNotFoundException If the option does not exist.
|
||||
*/
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
package app.revanced.patcher.util
|
||||
|
||||
import org.w3c.dom.Document
|
||||
import java.io.Closeable
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
|
||||
@Deprecated("Use Document instead.")
|
||||
class DomFileEditor : Closeable {
|
||||
val file: Document
|
||||
internal constructor(
|
||||
inputStream: InputStream,
|
||||
) {
|
||||
file = Document(inputStream)
|
||||
}
|
||||
|
||||
constructor(file: File) {
|
||||
this.file = Document(file)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
file as app.revanced.patcher.util.Document
|
||||
file.close()
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
package app.revanced.patcher.extensions
|
||||
|
||||
import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
|
||||
private object AnnotationExtensionsTest {
|
||||
@Test
|
||||
fun `find annotation in annotated class`() {
|
||||
assertNotNull(TestClasses.Annotation2::class.findAnnotationRecursively(TestClasses.Annotation::class))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `find annotation`() {
|
||||
assertNotNull(TestClasses.AnnotatedClass::class.findAnnotationRecursively(TestClasses.Annotation::class))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `find annotation recursively in super class`() {
|
||||
assertNotNull(TestClasses.AnnotatedClass2::class.findAnnotationRecursively(TestClasses.Annotation::class))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `find annotation recursively in super class with annotation`() {
|
||||
assertNotNull(TestClasses.AnnotatedTestClass3::class.findAnnotationRecursively(TestClasses.Annotation::class))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `don't find unknown annotation in annotated class`() {
|
||||
assertNull(TestClasses.AnnotatedClass::class.findAnnotationRecursively(TestClasses.UnknownAnnotation::class))
|
||||
}
|
||||
|
||||
object TestClasses {
|
||||
annotation class Annotation
|
||||
|
||||
@Annotation
|
||||
annotation class Annotation2
|
||||
|
||||
annotation class UnknownAnnotation
|
||||
|
||||
@Annotation
|
||||
abstract class AnnotatedClass
|
||||
|
||||
@Annotation2
|
||||
class AnnotatedTestClass3
|
||||
|
||||
abstract class AnnotatedClass2 : AnnotatedClass()
|
||||
}
|
||||
}
|
|
@ -1,27 +1,11 @@
|
|||
package app.revanced.patcher.patch
|
||||
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import kotlin.test.Test
|
||||
import app.revanced.patcher.patch.annotation.Patch as PatchAnnotation
|
||||
|
||||
object PatchInitializationTest {
|
||||
@Test
|
||||
fun `initialize using constructor`() {
|
||||
val patch =
|
||||
object : RawResourcePatch(name = "Resource patch test") {
|
||||
override fun execute(context: ResourceContext) {}
|
||||
}
|
||||
|
||||
assert(patch.name == "Resource patch test")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `initialize using annotation`() {
|
||||
val patch =
|
||||
@PatchAnnotation("Resource patch test")
|
||||
object : RawResourcePatch() {
|
||||
override fun execute(context: ResourceContext) {}
|
||||
}
|
||||
val patch = rawResourcePatch(name = "Resource patch test") { assert(true) }
|
||||
|
||||
assert(patch.name == "Resource patch test")
|
||||
}
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
package app.revanced.patcher.patch.options
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.booleanPatchOption
|
||||
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringArrayPatchOption
|
||||
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import org.junit.jupiter.api.assertDoesNotThrow
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import kotlin.test.Test
|
||||
|
@ -12,116 +8,123 @@ import kotlin.test.assertNull
|
|||
import kotlin.test.assertTrue
|
||||
|
||||
internal class PatchOptionsTest {
|
||||
@Test
|
||||
fun `should not fail because default value is unvalidated`() {
|
||||
assertDoesNotThrow { OptionsTestPatch.requiredStringOption }
|
||||
private val optionsTestPatch = bytecodePatch {
|
||||
booleanPatchOption("bool", true)
|
||||
|
||||
stringPatchOption("required", "default", required = true)
|
||||
|
||||
stringArrayPatchOption("array", arrayOf("1", "2"))
|
||||
|
||||
stringPatchOption("choices", "value", values = mapOf("Valid option value" to "valid"))
|
||||
|
||||
stringPatchOption("validated", "default") { it == "valid" }
|
||||
|
||||
stringPatchOption("resettable", null, required = true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should not allow setting custom value with validation`() {
|
||||
fun `should not fail because default value is unvalidated`() = options {
|
||||
assertDoesNotThrow { get("required") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should not allow setting custom value with validation`() = options {
|
||||
// Getter validation on incorrect value.
|
||||
assertThrows<PatchOptionException.ValueValidationException> { OptionsTestPatch.validatedOption }
|
||||
assertThrows<PatchOptionException.ValueValidationException> {
|
||||
set("validated", get("validated"))
|
||||
}
|
||||
|
||||
// Setter validation on incorrect value.
|
||||
assertThrows<PatchOptionException.ValueValidationException> { OptionsTestPatch.validatedOption = "invalid" }
|
||||
assertThrows<PatchOptionException.ValueValidationException> {
|
||||
set("validated", "invalid")
|
||||
}
|
||||
|
||||
// Setter validation on correct value.
|
||||
assertDoesNotThrow { OptionsTestPatch.validatedOption = "valid" }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should throw due to incorrect type`() {
|
||||
assertThrows<PatchOptionException.InvalidValueTypeException> {
|
||||
OptionsTestPatch.options["bool"] = "not a boolean"
|
||||
assertDoesNotThrow {
|
||||
set("validated", "valid")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should be nullable`() {
|
||||
OptionsTestPatch.booleanOption = null
|
||||
fun `should throw due to incorrect type`() = options {
|
||||
assertThrows<PatchOptionException.InvalidValueTypeException> {
|
||||
set("bool", "not a boolean")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `option should not be found`() {
|
||||
fun `should be nullable`() = options {
|
||||
assertDoesNotThrow {
|
||||
set("bool", null)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `option should not be found`() = options {
|
||||
assertThrows<PatchOptionException.PatchOptionNotFoundException> {
|
||||
OptionsTestPatch.options["this option does not exist"] = 1
|
||||
set("this option does not exist", 1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should be able to add options manually`() {
|
||||
fun `should be able to add options manually`() = options {
|
||||
assertThrows<PatchOptionException.InvalidValueTypeException> {
|
||||
OptionsTestPatch.options["array"] = OptionsTestPatch.stringArrayOption
|
||||
set("array", get("array"))
|
||||
}
|
||||
assertDoesNotThrow {
|
||||
OptionsTestPatch.options.register(OptionsTestPatch.stringArrayOption)
|
||||
register(get("array"))
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@Test
|
||||
fun `should allow setting value from values`() =
|
||||
with(OptionsTestPatch.options["choices"] as PatchOption<String>) {
|
||||
value = values!!.values.last()
|
||||
assertTrue(value == "valid")
|
||||
fun `should allow setting value from values`() = options {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val option = get("choices") as PatchOption<String>
|
||||
|
||||
option.value = option.values!!.values.last()
|
||||
|
||||
assertTrue(option.value == "valid")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should allow setting custom value`() = options {
|
||||
assertDoesNotThrow {
|
||||
set("choices", "unknown")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should allow resetting value`() = options {
|
||||
assertDoesNotThrow {
|
||||
set("choices", null)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should allow setting custom value`() = assertDoesNotThrow { OptionsTestPatch.stringOptionWithChoices = "unknown" }
|
||||
assert(get("choices").value == null)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should allow resetting value`() = assertDoesNotThrow { OptionsTestPatch.stringOptionWithChoices = null }
|
||||
|
||||
@Test
|
||||
fun `reset should not fail`() {
|
||||
fun `reset should not fail`() = options {
|
||||
assertDoesNotThrow {
|
||||
OptionsTestPatch.resettableOption.value = "test"
|
||||
OptionsTestPatch.resettableOption.reset()
|
||||
set("resettable", "test")
|
||||
get("resettable").reset()
|
||||
}
|
||||
|
||||
assertThrows<PatchOptionException.ValueRequiredException> {
|
||||
OptionsTestPatch.resettableOption.value
|
||||
get("resettable").value
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `option types should be known`() = assertTrue(OptionsTestPatch.options["array"].valueType == "StringArray")
|
||||
fun `option types should be known`() = options {
|
||||
assertTrue(get("array").valueType == "StringArray")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getting default value should work`() = assertDoesNotThrow { assertNull(OptionsTestPatch.resettableOption.default) }
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private object OptionsTestPatch : BytecodePatch() {
|
||||
var booleanOption by booleanPatchOption(
|
||||
"bool",
|
||||
true,
|
||||
)
|
||||
var requiredStringOption by stringPatchOption(
|
||||
"required",
|
||||
"default",
|
||||
required = true,
|
||||
)
|
||||
var stringArrayOption =
|
||||
stringArrayPatchOption(
|
||||
"array",
|
||||
arrayOf("1", "2"),
|
||||
)
|
||||
var stringOptionWithChoices by stringPatchOption(
|
||||
"choices",
|
||||
"value",
|
||||
values = mapOf("Valid option value" to "valid"),
|
||||
)
|
||||
var validatedOption by stringPatchOption(
|
||||
"validated",
|
||||
"default",
|
||||
) { it == "valid" }
|
||||
var resettableOption =
|
||||
stringPatchOption(
|
||||
"resettable",
|
||||
null,
|
||||
required = true,
|
||||
)
|
||||
|
||||
override fun execute(context: BytecodeContext) {}
|
||||
fun `getting default value should work`() = options {
|
||||
assertDoesNotThrow {
|
||||
assertNull(get("resettable").default)
|
||||
}
|
||||
}
|
||||
|
||||
private fun options(block: PatchOptions.() -> Unit) = optionsTestPatch.options.let(block)
|
||||
}
|
||||
|
|
|
@ -1,148 +0,0 @@
|
|||
package app.revanced.patcher.patch.usage
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Format
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction11x
|
||||
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21c
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableField
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodImplementation
|
||||
import com.android.tools.smali.dexlib2.immutable.reference.ImmutableFieldReference
|
||||
import com.android.tools.smali.dexlib2.immutable.reference.ImmutableStringReference
|
||||
import com.android.tools.smali.dexlib2.immutable.value.ImmutableFieldEncodedValue
|
||||
import com.android.tools.smali.dexlib2.util.Preconditions
|
||||
import com.google.common.collect.ImmutableList
|
||||
|
||||
@Suppress("unused")
|
||||
@Patch(
|
||||
name = "Example bytecode patch",
|
||||
description = "Example demonstration of a bytecode patch.",
|
||||
dependencies = [ExampleResourcePatch::class],
|
||||
compatiblePackages = [CompatiblePackage("com.example.examplePackage", arrayOf("0.0.1", "0.0.2"))],
|
||||
)
|
||||
object ExampleBytecodePatch : BytecodePatch(setOf(ExampleFingerprint)) {
|
||||
// Entry point of a patch. Supplied fingerprints are resolved at this point.
|
||||
override fun execute(context: BytecodeContext) {
|
||||
ExampleFingerprint.result?.let { result ->
|
||||
// Let's modify it, so it prints "Hello, ReVanced! Editing bytecode."
|
||||
// Get the start index of our opcode pattern.
|
||||
// This will be the index of the instruction with the opcode CONST_STRING.
|
||||
val startIndex = result.scanResult.patternScanResult!!.startIndex
|
||||
|
||||
result.mutableMethod.apply {
|
||||
replaceStringAt(startIndex, "Hello, ReVanced! Editing bytecode.")
|
||||
|
||||
// Store the fields initial value into the first virtual register.
|
||||
replaceInstruction(0, "sget-object v0, LTestClass;->dummyField:Ljava/io/PrintStream;")
|
||||
|
||||
// Now let's create a new call to our method and print the return value!
|
||||
// You can also use the smali compiler to create instructions.
|
||||
// For this sake of example I reuse the TestClass field dummyField inside the virtual register 0.
|
||||
//
|
||||
// Control flow instructions are not supported as of now.
|
||||
addInstructionsWithLabels(
|
||||
startIndex + 2,
|
||||
"""
|
||||
invoke-static { }, LTestClass;->returnHello()Ljava/lang/String;
|
||||
move-result-object v1
|
||||
invoke-virtual { v0, v1 }, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
|
||||
""",
|
||||
)
|
||||
}
|
||||
|
||||
// Find the class in which the method matching our fingerprint is defined in.
|
||||
context.findClass(result.classDef.type)!!.mutableClass.apply {
|
||||
// Add a new method that returns a string.
|
||||
methods.add(
|
||||
ImmutableMethod(
|
||||
result.classDef.type,
|
||||
"returnHello",
|
||||
null,
|
||||
"Ljava/lang/String;",
|
||||
AccessFlags.PRIVATE or AccessFlags.STATIC,
|
||||
null,
|
||||
null,
|
||||
ImmutableMethodImplementation(
|
||||
1,
|
||||
ImmutableList.of(
|
||||
BuilderInstruction21c(
|
||||
Opcode.CONST_STRING,
|
||||
0,
|
||||
ImmutableStringReference("Hello, ReVanced! Adding bytecode."),
|
||||
),
|
||||
BuilderInstruction11x(Opcode.RETURN_OBJECT, 0),
|
||||
),
|
||||
null,
|
||||
null,
|
||||
),
|
||||
).toMutable(),
|
||||
)
|
||||
|
||||
// Add a field in the main class.
|
||||
// We will use this field in our method below to call println on.
|
||||
// The field holds the Ljava/io/PrintStream->out; field.
|
||||
fields.add(
|
||||
ImmutableField(
|
||||
type,
|
||||
"dummyField",
|
||||
"Ljava/io/PrintStream;",
|
||||
AccessFlags.PRIVATE or AccessFlags.STATIC,
|
||||
ImmutableFieldEncodedValue(
|
||||
ImmutableFieldReference(
|
||||
"Ljava/lang/System;",
|
||||
"out",
|
||||
"Ljava/io/PrintStream;",
|
||||
),
|
||||
),
|
||||
null,
|
||||
null,
|
||||
).toMutable(),
|
||||
)
|
||||
}
|
||||
} ?: throw PatchException("Fingerprint failed to resolve.")
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace an existing instruction with a new one containing a reference to a new string.
|
||||
* @param index The index of the instruction to replace.
|
||||
* @param string The replacement string.
|
||||
*/
|
||||
private fun MutableMethod.replaceStringAt(
|
||||
index: Int,
|
||||
string: String,
|
||||
) {
|
||||
val instruction = getInstruction(index)
|
||||
|
||||
// Utility method of dexlib2.
|
||||
Preconditions.checkFormat(instruction.opcode, Format.Format21c)
|
||||
|
||||
// Cast this to an instruction of the format 21c.
|
||||
// The instruction format can be found in the docs at
|
||||
// https://source.android.com/devices/tech/dalvik/dalvik-bytecode
|
||||
val strInstruction = instruction as Instruction21c
|
||||
|
||||
// In our case we want an instruction with the opcode CONST_STRING
|
||||
// The format is 21c, so we create a new BuilderInstruction21c
|
||||
// This instruction will hold the string reference constant in the virtual register of the original instruction
|
||||
// For that a reference to the string is needed. It can be created with an ImmutableStringReference.
|
||||
// At last, use the method replaceInstruction to replace it at the given index startIndex.
|
||||
replaceInstruction(
|
||||
index,
|
||||
"const-string ${strInstruction.registerA}, ${ImmutableStringReference(string)}",
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package app.revanced.patcher.patch.usage
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patcher.fingerprint.annotation.FuzzyPatternScanMethod
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
@FuzzyPatternScanMethod(2)
|
||||
object ExampleFingerprint : MethodFingerprint(
|
||||
"V",
|
||||
AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
listOf("[L"),
|
||||
listOf(
|
||||
Opcode.SGET_OBJECT,
|
||||
null, // Matching unknown opcodes.
|
||||
Opcode.INVOKE_STATIC, // This is intentionally wrong to test fuzzy matching.
|
||||
Opcode.RETURN_VOID,
|
||||
),
|
||||
null,
|
||||
)
|
|
@ -1,14 +0,0 @@
|
|||
package app.revanced.patcher.patch.usage
|
||||
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import org.w3c.dom.Element
|
||||
|
||||
class ExampleResourcePatch : ResourcePatch() {
|
||||
override fun execute(context: ResourceContext) {
|
||||
context.document["AndroidManifest.xml"].use { document ->
|
||||
val element = document.getElementsByTagName("application").item(0) as Element
|
||||
element.setAttribute("exampleAttribute", "exampleValue")
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue