Compare commits

...

5 Commits

Author SHA1 Message Date
oSumAtrIX 8a64ccf250
feat: Add fingerprints to DSL and finish patches DSL 2024-04-25 04:59:12 +02:00
oSumAtrIX d0cbbac3f2
Merge branch 'dev' into feat/dsl-api 2024-04-25 00:21:11 +02:00
oSumAtrIX 1d78d690bb
chore: Fix spelling mistake 2024-04-07 18:22:00 +02:00
Vologhat 042f554d75
refactor: Simplify mapping classes to their names (#290)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-04-07 17:54:37 +02:00
oSumAtrIX f63302feab
build: Publish sources 2024-03-14 12:21:48 +01:00
30 changed files with 1647 additions and 1125 deletions

View File

@ -10,35 +10,6 @@ public final class app/revanced/patcher/PackageMetadata {
public final fun getPackageVersion ()Ljava/lang/String;
}
public abstract class app/revanced/patcher/PatchBundleLoader : java/util/Set, kotlin/jvm/internal/markers/KMappedMarker {
public synthetic fun <init> (Ljava/lang/ClassLoader;[Ljava/io/File;Lkotlin/jvm/functions/Function1;Ljava/util/Set;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun add (Lapp/revanced/patcher/patch/Patch;)Z
public synthetic fun add (Ljava/lang/Object;)Z
public fun addAll (Ljava/util/Collection;)Z
public fun clear ()V
public fun contains (Lapp/revanced/patcher/patch/Patch;)Z
public final fun contains (Ljava/lang/Object;)Z
public fun containsAll (Ljava/util/Collection;)Z
public fun getSize ()I
public fun isEmpty ()Z
public fun iterator ()Ljava/util/Iterator;
public fun remove (Ljava/lang/Object;)Z
public fun removeAll (Ljava/util/Collection;)Z
public fun retainAll (Ljava/util/Collection;)Z
public final fun size ()I
public fun toArray ()[Ljava/lang/Object;
public fun toArray ([Ljava/lang/Object;)[Ljava/lang/Object;
}
public final class app/revanced/patcher/PatchBundleLoader$Dex : app/revanced/patcher/PatchBundleLoader {
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
}
public final class app/revanced/patcher/PatchBundleLoader$Jar : app/revanced/patcher/PatchBundleLoader {
public fun <init> ([Ljava/io/File;)V
}
public abstract interface class app/revanced/patcher/PatchExecutorFunction : java/util/function/Function {
}
@ -92,34 +63,6 @@ public abstract interface class app/revanced/patcher/PatchesConsumer {
public abstract fun acceptPatches (Ljava/util/Set;)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;
public synthetic fun get ()Ljava/lang/Object;
public fun get ()Ljava/util/Set;
public final fun getClasses ()Lapp/revanced/patcher/util/ProxyClassList;
public final fun proxy (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Lapp/revanced/patcher/util/proxy/ClassProxy;
public final fun toMethodWalker (Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/util/method/MethodWalker;
}
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 {
public fun get ()Lapp/revanced/patcher/PatcherResult$PatchedResources;
public synthetic fun get ()Ljava/lang/Object;
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 stageDelete (Lkotlin/jvm/functions/Function1;)Z
}
public final class app/revanced/patcher/data/ResourceContext$DocumentOperatable {
public fun <init> (Lapp/revanced/patcher/data/ResourceContext;)V
public final fun get (Ljava/io/InputStream;)Lapp/revanced/patcher/util/Document;
public final fun get (Ljava/lang/String;)Lapp/revanced/patcher/util/Document;
}
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
@ -157,23 +100,39 @@ public final class app/revanced/patcher/extensions/InstructionExtensions {
public final fun replaceInstructions (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;ILjava/util/List;)V
}
public abstract interface annotation class app/revanced/patcher/fingerprint/FuzzyPatternScanMethod : java/lang/annotation/Annotation {
public abstract fun threshold ()I
}
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/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 getFuzzyPatternScanMethod ()Lapp/revanced/patcher/fingerprint/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
public final fun resolve (Lapp/revanced/patcher/data/BytecodeContext;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Z
public final fun resolve (Lapp/revanced/patcher/patch/BytecodePatchContext;Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Z
public final fun resolve (Lapp/revanced/patcher/patch/BytecodePatchContext;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Z
}
public final class app/revanced/patcher/fingerprint/MethodFingerprint$Companion {
public final fun resolve (Ljava/lang/Iterable;Lapp/revanced/patcher/data/BytecodeContext;Ljava/lang/Iterable;)V
public final class app/revanced/patcher/fingerprint/MethodFingerprintBuilder {
public final fun accessFlags (I)V
public final fun accessFlags (Lcom/android/tools/smali/dexlib2/AccessFlags;)V
public final fun custom (Lkotlin/jvm/functions/Function2;)V
public final fun opcodes (Ljava/lang/String;)V
public final fun opcodes ([Lcom/android/tools/smali/dexlib2/Opcode;)V
public final fun parameters ([Ljava/lang/String;)V
public final fun returns (Ljava/lang/String;)V
public final fun strings ([Ljava/lang/String;)V
}
public final class app/revanced/patcher/fingerprint/MethodFingerprintKt {
public static final fun methodFingerprint (Lapp/revanced/patcher/patch/BytecodePatchBuilder;Lkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/fingerprint/MethodFingerprint;
public static final fun methodFingerprint (Lkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/fingerprint/MethodFingerprint;
public static final fun resolve (Ljava/lang/Iterable;Lapp/revanced/patcher/patch/BytecodePatchContext;Ljava/lang/Iterable;)V
}
public final class app/revanced/patcher/fingerprint/MethodFingerprintResult {
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lapp/revanced/patcher/fingerprint/MethodFingerprintResult$MethodFingerprintScanResult;Lapp/revanced/patcher/data/BytecodeContext;)V
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lapp/revanced/patcher/fingerprint/MethodFingerprintResult$MethodFingerprintScanResult;Lapp/revanced/patcher/patch/BytecodePatchContext;)V
public final fun getClassDef ()Lcom/android/tools/smali/dexlib2/iface/ClassDef;
public final fun getMethod ()Lcom/android/tools/smali/dexlib2/iface/Method;
public final fun getMutableClass ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;
@ -204,57 +163,61 @@ public final class app/revanced/patcher/fingerprint/MethodFingerprintResult$Meth
public final fun getString ()Ljava/lang/String;
}
public abstract interface annotation class app/revanced/patcher/fingerprint/annotation/FuzzyPatternScanMethod : java/lang/annotation/Annotation {
public abstract fun threshold ()I
public final class app/revanced/patcher/patch/BytecodePatch : app/revanced/patcher/patch/Patch {
}
public final class app/revanced/patcher/patch/BytecodePatch : app/revanced/patcher/patch/Patch {
public final fun fingerprints ([Lapp/revanced/patcher/fingerprint/MethodFingerprint;)V
public final class app/revanced/patcher/patch/BytecodePatchBuilder : app/revanced/patcher/patch/PatchBuilder {
public synthetic fun build$revanced_patcher ()Lapp/revanced/patcher/patch/Patch;
public final fun getValue (Lapp/revanced/patcher/fingerprint/MethodFingerprint;Ljava/lang/Void;Lkotlin/reflect/KProperty;)Lapp/revanced/patcher/fingerprint/MethodFingerprintResult;
public final fun invoke (Lapp/revanced/patcher/fingerprint/MethodFingerprint;)Lapp/revanced/patcher/fingerprint/MethodFingerprint;
}
public final class app/revanced/patcher/patch/BytecodePatchContext : app/revanced/patcher/patch/PatchContext {
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;
public synthetic fun get ()Ljava/lang/Object;
public fun get ()Ljava/util/Set;
public final fun getClasses ()Lapp/revanced/patcher/util/ProxyClassList;
public final fun proxy (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Lapp/revanced/patcher/util/proxy/ClassProxy;
public final fun toMethodWalker (Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/util/method/MethodWalker;
}
public abstract class app/revanced/patcher/patch/Patch {
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 synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;ZZLjava/util/Set;Ljava/util/Set;Ljava/util/Set;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun execute (Lapp/revanced/patcher/patch/PatchContext;)V
public final fun finalize (Lapp/revanced/patcher/patch/PatchContext;)V
public final fun getCompatiblePackages ()Ljava/util/Set;
public final fun getDependencies ()Ljava/util/Set;
public final fun getDescription ()Ljava/lang/String;
public final fun getName ()Ljava/lang/String;
public final fun getOptions ()Lapp/revanced/patcher/patch/options/PatchOptions;
public final fun getOptions ()Lapp/revanced/patcher/patch/PatchOptions;
public final fun getRequiresIntegrations ()Z
public final fun getUse ()Z
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$CompatiblePackages {
public fun <init> ()V
public abstract class app/revanced/patcher/patch/PatchBuilder {
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;ZZLkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun execute (Lkotlin/jvm/functions/Function1;)V
public final fun finalize (Lkotlin/jvm/functions/Function1;)V
protected final fun getCompatiblePackages ()Ljava/util/Set;
protected final fun getDependencies ()Ljava/util/Set;
protected final fun getDescription ()Ljava/lang/String;
protected final fun getExecutionBlock ()Lkotlin/jvm/functions/Function1;
protected final fun getFinalizeBlock ()Lkotlin/jvm/functions/Function1;
protected final fun getName ()Ljava/lang/String;
protected final fun getOptions ()Ljava/util/Set;
protected final fun getRequiresIntegrations ()Z
protected final fun getUse ()Z
public final fun invoke (Lapp/revanced/patcher/patch/Patch;)Lapp/revanced/patcher/patch/Patch;
public final fun invoke (Ljava/lang/String;[Ljava/lang/String;)V
public final fun option ([Lapp/revanced/patcher/patch/PatchOption;)V
protected final fun setCompatiblePackages (Ljava/util/Set;)V
protected final fun setExecutionBlock (Lkotlin/jvm/functions/Function1;)V
protected final fun setFinalizeBlock (Lkotlin/jvm/functions/Function1;)V
}
public abstract interface class app/revanced/patcher/patch/PatchContext : java/util/function/Supplier {
}
public final class app/revanced/patcher/patch/PatchException : java/lang/Exception {
@ -264,26 +227,50 @@ public final class app/revanced/patcher/patch/PatchException : java/lang/Excepti
}
public final class app/revanced/patcher/patch/PatchKt {
public static final fun bytecodePatch (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/patch/BytecodePatch;
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 (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)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 (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/patch/RawResourcePatch;
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 (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)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 (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/patch/ResourcePatch;
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 (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/lang/String;ZZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)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/PatchLoader : java/util/Set, kotlin/jvm/internal/markers/KMappedMarker {
public synthetic fun <init> (Ljava/lang/ClassLoader;Ljava/util/Set;Lkotlin/jvm/functions/Function1;Ljava/util/Set;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun add (Lapp/revanced/patcher/patch/Patch;)Z
public synthetic fun add (Ljava/lang/Object;)Z
public fun addAll (Ljava/util/Collection;)Z
public fun clear ()V
public fun contains (Lapp/revanced/patcher/patch/Patch;)Z
public final fun contains (Ljava/lang/Object;)Z
public fun containsAll (Ljava/util/Collection;)Z
public fun getSize ()I
public fun isEmpty ()Z
public fun iterator ()Ljava/util/Iterator;
public fun remove (Ljava/lang/Object;)Z
public fun removeAll (Ljava/util/Collection;)Z
public fun retainAll (Ljava/util/Collection;)Z
public final fun size ()I
public fun toArray ()[Ljava/lang/Object;
public fun toArray ([Ljava/lang/Object;)[Ljava/lang/Object;
}
public final class app/revanced/patcher/patch/RawResourcePatch : app/revanced/patcher/patch/Patch {
public final class app/revanced/patcher/patch/PatchLoader$Dex : app/revanced/patcher/patch/PatchLoader {
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
}
public final class app/revanced/patcher/patch/ResourcePatch : app/revanced/patcher/patch/Patch {
public final class app/revanced/patcher/patch/PatchLoader$Jar : app/revanced/patcher/patch/PatchLoader {
public fun <init> ([Ljava/io/File;)V
}
public class app/revanced/patcher/patch/options/PatchOption {
public class app/revanced/patcher/patch/PatchOption {
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;
@ -301,55 +288,129 @@ public class app/revanced/patcher/patch/options/PatchOption {
public fun toString ()Ljava/lang/String;
}
public abstract class app/revanced/patcher/patch/options/PatchOptionException : java/lang/Exception {
public abstract class app/revanced/patcher/patch/PatchOptionException : java/lang/Exception {
public synthetic fun <init> (Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
}
public final class app/revanced/patcher/patch/options/PatchOptionException$InvalidValueTypeException : app/revanced/patcher/patch/options/PatchOptionException {
public final class app/revanced/patcher/patch/PatchOptionException$InvalidValueTypeException : app/revanced/patcher/patch/PatchOptionException {
public fun <init> (Ljava/lang/String;Ljava/lang/String;)V
}
public final class app/revanced/patcher/patch/options/PatchOptionException$PatchOptionNotFoundException : app/revanced/patcher/patch/options/PatchOptionException {
public final class app/revanced/patcher/patch/PatchOptionException$PatchOptionNotFoundException : app/revanced/patcher/patch/PatchOptionException {
public fun <init> (Ljava/lang/String;)V
}
public final class app/revanced/patcher/patch/options/PatchOptionException$ValueRequiredException : app/revanced/patcher/patch/options/PatchOptionException {
public fun <init> (Lapp/revanced/patcher/patch/options/PatchOption;)V
public final class app/revanced/patcher/patch/PatchOptionException$ValueRequiredException : app/revanced/patcher/patch/PatchOptionException {
public fun <init> (Lapp/revanced/patcher/patch/PatchOption;)V
}
public final class app/revanced/patcher/patch/options/PatchOptionException$ValueValidationException : app/revanced/patcher/patch/options/PatchOptionException {
public fun <init> (Ljava/lang/Object;Lapp/revanced/patcher/patch/options/PatchOption;)V
public final class app/revanced/patcher/patch/PatchOptionException$ValueValidationException : app/revanced/patcher/patch/PatchOptionException {
public fun <init> (Ljava/lang/Object;Lapp/revanced/patcher/patch/PatchOption;)V
}
public final class app/revanced/patcher/patch/options/PatchOptions : java/util/Map, kotlin/jvm/internal/markers/KMutableMap {
public fun <init> ()V
public final class app/revanced/patcher/patch/PatchOptionKt {
public static final fun addNewPatchOption (Lapp/revanced/patcher/patch/PatchBuilder;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/PatchOption;
public static synthetic fun addNewPatchOption$default (Lapp/revanced/patcher/patch/PatchBuilder;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/PatchOption;
public static final fun booleanArrayPatchOption (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;[Ljava/lang/Boolean;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/PatchOption;
public static synthetic fun booleanArrayPatchOption$default (Lapp/revanced/patcher/patch/PatchBuilder;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/PatchOption;
public static final fun booleanPatchOption (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/lang/Boolean;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/PatchOption;
public static synthetic fun booleanPatchOption$default (Lapp/revanced/patcher/patch/PatchBuilder;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/PatchOption;
public static final fun floatArrayPatchOption (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;[Ljava/lang/Float;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/PatchOption;
public static synthetic fun floatArrayPatchOption$default (Lapp/revanced/patcher/patch/PatchBuilder;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/PatchOption;
public static final fun floatPatchOption (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/lang/Float;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/PatchOption;
public static synthetic fun floatPatchOption$default (Lapp/revanced/patcher/patch/PatchBuilder;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/PatchOption;
public static final fun intArrayPatchOption (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;[Ljava/lang/Integer;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/PatchOption;
public static synthetic fun intArrayPatchOption$default (Lapp/revanced/patcher/patch/PatchBuilder;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/PatchOption;
public static final fun intPatchOption (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/lang/Integer;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/PatchOption;
public static synthetic fun intPatchOption$default (Lapp/revanced/patcher/patch/PatchBuilder;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/PatchOption;
public static final fun longArrayPatchOption (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;[Ljava/lang/Long;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/PatchOption;
public static synthetic fun longArrayPatchOption$default (Lapp/revanced/patcher/patch/PatchBuilder;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/PatchOption;
public static final fun longPatchOption (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/lang/Long;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/PatchOption;
public static synthetic fun longPatchOption$default (Lapp/revanced/patcher/patch/PatchBuilder;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/PatchOption;
public static final fun stringArrayPatchOption (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;[Ljava/lang/String;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/PatchOption;
public static synthetic fun stringArrayPatchOption$default (Lapp/revanced/patcher/patch/PatchBuilder;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/PatchOption;
public static final fun stringPatchOption (Lapp/revanced/patcher/patch/PatchBuilder;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/patch/PatchOption;
public static synthetic fun stringPatchOption$default (Lapp/revanced/patcher/patch/PatchBuilder;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/PatchOption;
}
public final class app/revanced/patcher/patch/PatchOptions : java/util/Map, kotlin/jvm/internal/markers/KMappedMarker {
public fun <init> (Ljava/util/Map;)V
public fun <init> (Ljava/util/Set;)V
public fun clear ()V
public synthetic fun compute (Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;
public fun compute (Ljava/lang/String;Ljava/util/function/BiFunction;)Lapp/revanced/patcher/patch/PatchOption;
public synthetic fun computeIfAbsent (Ljava/lang/Object;Ljava/util/function/Function;)Ljava/lang/Object;
public fun computeIfAbsent (Ljava/lang/String;Ljava/util/function/Function;)Lapp/revanced/patcher/patch/PatchOption;
public synthetic fun computeIfPresent (Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;
public fun computeIfPresent (Ljava/lang/String;Ljava/util/function/BiFunction;)Lapp/revanced/patcher/patch/PatchOption;
public final fun containsKey (Ljava/lang/Object;)Z
public fun containsKey (Ljava/lang/String;)Z
public fun containsValue (Lapp/revanced/patcher/patch/options/PatchOption;)Z
public fun containsValue (Lapp/revanced/patcher/patch/PatchOption;)Z
public final fun containsValue (Ljava/lang/Object;)Z
public final fun entrySet ()Ljava/util/Set;
public final fun get (Ljava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
public final fun get (Ljava/lang/Object;)Lapp/revanced/patcher/patch/PatchOption;
public final synthetic fun get (Ljava/lang/Object;)Ljava/lang/Object;
public fun get (Ljava/lang/String;)Lapp/revanced/patcher/patch/options/PatchOption;
public fun get (Ljava/lang/String;)Lapp/revanced/patcher/patch/PatchOption;
public fun getEntries ()Ljava/util/Set;
public fun getKeys ()Ljava/util/Set;
public fun getSize ()I
public fun getValues ()Ljava/util/Collection;
public fun isEmpty ()Z
public final fun keySet ()Ljava/util/Set;
public synthetic fun merge (Ljava/lang/Object;Ljava/lang/Object;Ljava/util/function/BiFunction;)Ljava/lang/Object;
public fun merge (Ljava/lang/String;Lapp/revanced/patcher/patch/PatchOption;Ljava/util/function/BiFunction;)Lapp/revanced/patcher/patch/PatchOption;
public synthetic fun put (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public fun put (Ljava/lang/String;Lapp/revanced/patcher/patch/options/PatchOption;)Lapp/revanced/patcher/patch/options/PatchOption;
public fun put (Ljava/lang/String;Lapp/revanced/patcher/patch/PatchOption;)Lapp/revanced/patcher/patch/PatchOption;
public fun putAll (Ljava/util/Map;)V
public final fun register (Lapp/revanced/patcher/patch/options/PatchOption;)V
public final fun remove (Ljava/lang/Object;)Lapp/revanced/patcher/patch/options/PatchOption;
public final synthetic fun remove (Ljava/lang/Object;)Ljava/lang/Object;
public fun remove (Ljava/lang/String;)Lapp/revanced/patcher/patch/options/PatchOption;
public synthetic fun putIfAbsent (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public fun putIfAbsent (Ljava/lang/String;Lapp/revanced/patcher/patch/PatchOption;)Lapp/revanced/patcher/patch/PatchOption;
public fun remove (Ljava/lang/Object;)Lapp/revanced/patcher/patch/PatchOption;
public synthetic fun remove (Ljava/lang/Object;)Ljava/lang/Object;
public fun remove (Ljava/lang/Object;Ljava/lang/Object;)Z
public synthetic fun replace (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public synthetic fun replace (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Z
public fun replace (Ljava/lang/String;Lapp/revanced/patcher/patch/PatchOption;)Lapp/revanced/patcher/patch/PatchOption;
public fun replace (Ljava/lang/String;Lapp/revanced/patcher/patch/PatchOption;Lapp/revanced/patcher/patch/PatchOption;)Z
public fun replaceAll (Ljava/util/function/BiFunction;)V
public final fun set (Ljava/lang/String;Ljava/lang/Object;)V
public final fun size ()I
public final fun values ()Ljava/util/Collection;
}
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 final class app/revanced/patcher/patch/RawResourcePatch : app/revanced/patcher/patch/Patch {
}
public final class app/revanced/patcher/patch/RawResourcePatchBuilder : app/revanced/patcher/patch/PatchBuilder {
public synthetic fun build$revanced_patcher ()Lapp/revanced/patcher/patch/Patch;
}
public final class app/revanced/patcher/patch/ResourcePatch : app/revanced/patcher/patch/Patch {
}
public final class app/revanced/patcher/patch/ResourcePatchBuilder : app/revanced/patcher/patch/PatchBuilder {
public synthetic fun build$revanced_patcher ()Lapp/revanced/patcher/patch/Patch;
}
public final class app/revanced/patcher/patch/ResourcePatchContext : app/revanced/patcher/patch/PatchContext {
public fun get ()Lapp/revanced/patcher/PatcherResult$PatchedResources;
public synthetic fun get ()Ljava/lang/Object;
public final fun get (Ljava/lang/String;Z)Ljava/io/File;
public static synthetic fun get$default (Lapp/revanced/patcher/patch/ResourcePatchContext;Ljava/lang/String;ZILjava/lang/Object;)Ljava/io/File;
public final fun getDocument ()Lapp/revanced/patcher/patch/ResourcePatchContext$DocumentOperatable;
public final fun stageDelete (Lkotlin/jvm/functions/Function1;)Z
}
public final class app/revanced/patcher/patch/ResourcePatchContext$DocumentOperatable {
public fun <init> (Lapp/revanced/patcher/patch/ResourcePatchContext;)V
public final fun get (Ljava/io/InputStream;)Lapp/revanced/patcher/util/Document;
public final fun get (Ljava/lang/String;)Lapp/revanced/patcher/util/Document;
}
public final class app/revanced/patcher/util/Document : java/io/Closeable, org/w3c/dom/Document {
public fun adoptNode (Lorg/w3c/dom/Node;)Lorg/w3c/dom/Node;
public fun appendChild (Lorg/w3c/dom/Node;)Lorg/w3c/dom/Node;

View File

@ -27,7 +27,7 @@ repositories {
mavenLocal()
google()
maven {
// A repository must be speficied for some reason. "registry" is a dummy.
// A repository must be specified for some reason. "registry" is a dummy.
url = uri("https://maven.pkg.github.com/revanced/registry")
credentials {
username = project.findProperty("gpr.user") as String? ?: System.getenv("GITHUB_ACTOR")
@ -61,6 +61,8 @@ kotlin {
java {
targetCompatibility = JavaVersion.VERSION_11
withSourcesJar()
}
publishing {

View File

@ -1,8 +0,0 @@
package app.revanced.patcher
import java.io.File
@FunctionalInterface
interface IntegrationsConsumer {
fun acceptIntegrations(integrations: Set<File>)
}

View File

@ -1,88 +0,0 @@
@file:Suppress("unused")
package app.revanced.patcher
import app.revanced.patcher.patch.Patch
import dalvik.system.DexClassLoader
import lanchon.multidexlib2.BasicDexFileNamer
import lanchon.multidexlib2.MultiDexIO
import java.io.File
import java.net.URLClassLoader
import java.util.jar.JarFile
import java.util.logging.Logger
/**
* A set of [Patch]es.
*/
typealias PatchSet = Set<Patch<*>>
/**
* A loader of [Patch]es from patch bundles.
* This will load all [Patch]es from the given patch bundles that have a name.
*
* @param getBinaryClassNames A function that returns the binary names of all classes in a patch bundle.
* @param classLoader The [ClassLoader] to use for loading the classes.
* @param patchBundles A set of patches to initialize this instance with.
*/
sealed class PatchBundleLoader private constructor(
classLoader: ClassLoader,
patchBundles: Array<out File>,
getBinaryClassNames: (patchBundle: File) -> List<String>,
// This constructor parameter is unfortunately necessary,
// so that a reference to the mutable set is present in the constructor to be able to add patches to it.
// because the instance itself is a PatchSet, which is immutable, that is delegated by the parameter.
private val patchSet: MutableSet<Patch<*>> = mutableSetOf(),
) : PatchSet by patchSet {
private val logger = Logger.getLogger(PatchBundleLoader::class.java.name)
init {
patchBundles.asSequence().flatMap(getBinaryClassNames).map {
classLoader.loadClass(it)
}.flatMap {
it.declaredFields.filter { field ->
Patch::class.java.isAssignableFrom(field.type)
}.map { field -> field.get(null) as Patch<*> }
}.filter {
it.name != null
}.toList().let { patches ->
patchSet.addAll(patches)
}
}
/**
* A [PatchBundleLoader] for JAR files.
*
* @param patchBundles The path to patch bundles of JAR format.
*/
class Jar(vararg patchBundles: File) : PatchBundleLoader(
URLClassLoader(patchBundles.map { it.toURI().toURL() }.toTypedArray()),
patchBundles,
{ patchBundle ->
JarFile(patchBundle).entries().toList().filter { it.name.endsWith(".class") }
.map { it.name.replace('/', '.').replace(".class", "") }
},
)
/**
* A [PatchBundleLoader] for [Dex] files.
*
* @param patchBundles The path to patch bundles of DEX format.
* @param optimizedDexDirectory The directory to store optimized DEX files in.
* This parameter is deprecated and has no effect since API level 26.
*/
class Dex(vararg patchBundles: File, optimizedDexDirectory: File? = null) : PatchBundleLoader(
DexClassLoader(
patchBundles.joinToString(File.pathSeparator) { it.absolutePath },
optimizedDexDirectory?.absolutePath,
null,
PatchBundleLoader::class.java.classLoader,
),
patchBundles,
{ patchBundle ->
MultiDexIO.readDexFile(true, patchBundle, BasicDexFileNamer(), null, null).classes
.map { classDef ->
classDef.type.substring(1, classDef.length - 1)
}
},
)
}

View File

@ -1,8 +0,0 @@
package app.revanced.patcher
import app.revanced.patcher.patch.PatchResult
import kotlinx.coroutines.flow.Flow
import java.util.function.Function
@FunctionalInterface
interface PatchExecutorFunction : Function<Boolean, Flow<PatchResult>>

View File

@ -1,14 +1,29 @@
package app.revanced.patcher
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.fingerprint.LookupMap
import app.revanced.patcher.patch.*
import app.revanced.patcher.patch.ResourcePatchContext
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import java.io.Closeable
import java.io.File
import java.util.function.Function
import java.util.function.Supplier
import java.util.logging.Logger
@FunctionalInterface
interface IntegrationsConsumer {
fun acceptIntegrations(integrations: Set<File>)
}
@FunctionalInterface
interface PatchesConsumer {
fun acceptPatches(patches: PatchSet)
}
@FunctionalInterface
interface PatchExecutorFunction : Function<Boolean, Flow<PatchResult>>
/**
* A Patcher.
*
@ -25,11 +40,11 @@ class Patcher(
val context = PatcherContext(config)
init {
context.resourceContext.decodeResources(ResourceContext.ResourceMode.NONE)
context.resourceContext.decodeResources(ResourcePatchContext.ResourceMode.NONE)
}
/**
* Add [Patch]es to ReVanced [Patcher].
* Add [Patch]es to [Patcher].
*
* @param patches The [Patch]es to add.
*/
@ -59,11 +74,11 @@ class Patcher(
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
ResourcePatchContext.ResourceMode.FULL
} else if (patches.any { patch -> patch.anyRecursively { it is RawResourcePatch } }) {
ResourceContext.ResourceMode.RAW_ONLY
ResourcePatchContext.ResourceMode.RAW_ONLY
} else {
ResourceContext.ResourceMode.NONE
ResourcePatchContext.ResourceMode.NONE
}
// Check, if integrations need to be merged.
@ -85,9 +100,9 @@ class Patcher(
}
/**
* Execute [Patch]es that were added to ReVanced [Patcher].
* Execute [Patch]es that were added to [Patcher].
*
* @param returnOnError If true, ReVanced [Patcher] will return immediately if a [Patch] fails.
* @param returnOnError If true, [Patcher] will return immediately if a [Patch] fails.
* @return A pair of the name of the [Patch] and its [PatchResult].
*/
override fun apply(returnOnError: Boolean) =
@ -131,7 +146,7 @@ class Patcher(
LookupMap.initializeLookupMaps(context.bytecodeContext)
// Prevent from decoding the app manifest twice if it is not needed.
if (config.resourceMode != ResourceContext.ResourceMode.NONE) {
if (config.resourceMode != ResourcePatchContext.ResourceMode.NONE) {
context.resourceContext.decodeResources(config.resourceMode)
}
@ -204,3 +219,18 @@ class Patcher(
context.resourceContext.get(),
)
}
/**
* An exception thrown by [Patcher].
*
* @param errorMessage The exception message.
* @param cause The corresponding [Throwable].
*/
sealed class PatcherException(errorMessage: String?, cause: Throwable?) : Exception(errorMessage, cause) {
constructor(errorMessage: String) : this(errorMessage, null)
// TODO: Implement circular dependency detection.
class CircularDependencyException internal constructor(dependant: String) : PatcherException(
"Patch '$dependant' causes a circular dependency",
)
}

View File

@ -1,6 +1,6 @@
package app.revanced.patcher
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.ResourcePatchContext
import brut.androlib.Config
import java.io.File
import java.util.logging.Logger
@ -27,9 +27,9 @@ class PatcherConfig(
/**
* The mode to use for resource decoding and compiling.
*
* @see ResourceContext.ResourceMode
* @see ResourcePatchContext.ResourceMode
*/
internal var resourceMode = ResourceContext.ResourceMode.NONE
internal var resourceMode = ResourcePatchContext.ResourceMode.NONE
/**
* The configuration for decoding and compiling resources.

View File

@ -1,8 +1,8 @@
package app.revanced.patcher
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.Patch
import app.revanced.patcher.patch.ResourcePatchContext
import brut.androlib.apk.ApkInfo
import brut.directory.ExtFile
@ -31,10 +31,10 @@ class PatcherContext internal constructor(config: PatcherConfig) {
/**
* A context for the patcher containing the current state of the resources.
*/
internal val resourceContext = ResourceContext(packageMetadata, config)
internal val resourceContext = ResourcePatchContext(packageMetadata, config)
/**
* A context for the patcher containing the current state of the bytecode.
*/
internal val bytecodeContext = BytecodeContext(config)
internal val bytecodeContext = BytecodePatchContext(config)
}

View File

@ -1,15 +0,0 @@
package app.revanced.patcher
/**
* An exception thrown by ReVanced [Patcher].
*
* @param errorMessage The exception message.
* @param cause The corresponding [Throwable].
*/
sealed class PatcherException(errorMessage: String?, cause: Throwable?) : Exception(errorMessage, cause) {
constructor(errorMessage: String) : this(errorMessage, null)
class CircularDependencyException internal constructor(dependant: String) : PatcherException(
"Patch '$dependant' causes a circular dependency",
)
}

View File

@ -1,6 +0,0 @@
package app.revanced.patcher
@FunctionalInterface
interface PatchesConsumer {
fun acceptPatches(patches: PatchSet)
}

View File

@ -1,9 +0,0 @@
package app.revanced.patcher.data
import java.util.function.Supplier
/**
* A common interface for contexts such as [ResourceContext] and [BytecodeContext].
*/
sealed interface Context<T> : Supplier<T>

View File

@ -1,6 +1,6 @@
package app.revanced.patcher.fingerprint
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.ClassDef
import com.android.tools.smali.dexlib2.iface.Method
@ -50,9 +50,9 @@ internal class LookupMap : MutableMap<String, LookupMap.MethodClassList> by muta
* Initializes lookup maps for [MethodFingerprint] resolution
* using attributes of methods such as the method signature or strings.
*
* @param context The [BytecodeContext] containing the classes to initialize the lookup maps with.
* @param context The [BytecodePatchContext] containing the classes to initialize the lookup maps with.
*/
internal fun initializeLookupMaps(context: BytecodeContext) {
internal fun initializeLookupMaps(context: BytecodePatchContext) {
if (methods.isNotEmpty()) clearLookupMaps()
context.classes.forEach { classDef ->

View File

@ -1,22 +1,31 @@
package app.revanced.patcher.fingerprint
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.fingerprint.LookupMap.Maps.appendParameters
import app.revanced.patcher.fingerprint.LookupMap.Maps.initializeLookupMaps
import app.revanced.patcher.fingerprint.LookupMap.Maps.methodSignatureLookupMap
import app.revanced.patcher.fingerprint.LookupMap.Maps.methodStringsLookupMap
import app.revanced.patcher.fingerprint.LookupMap.Maps.methods
import app.revanced.patcher.fingerprint.MethodFingerprintResult.MethodFingerprintScanResult.StringsScanResult
import app.revanced.patcher.fingerprint.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.*
import app.revanced.patcher.util.proxy.ClassProxy
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.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.StringReference
import com.android.tools.smali.dexlib2.util.MethodUtil
import kotlin.reflect.full.findAnnotations
/**
* Annotations to scan a pattern [MethodFingerprint] with fuzzy algorithm.
* @param threshold if [threshold] or more of the opcodes do not match, skip.
*/
@Target(AnnotationTarget.CLASS)
annotation class FuzzyPatternScanMethod(
val threshold: Int = 1,
)
/**
* A fingerprint to resolve methods.
*
@ -25,7 +34,7 @@ import kotlin.reflect.full.findAnnotations
* @param parameters The parameters of the method. Partial matches allowed and follow the same rules as [returnType].
* @param opcodes An opcode pattern of the method's instructions. Wildcard or unknown opcodes can be specified by `null`.
* @param strings A list of the method's strings compared each using [String.contains].
* @param customFingerprint A custom condition for this fingerprint.
* @param custom A custom condition for this fingerprint.
*/
@Suppress("MemberVisibilityCanBePrivate")
class MethodFingerprint(
@ -34,7 +43,7 @@ class MethodFingerprint(
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,
internal val custom: ((methodDef: Method, classDef: ClassDef) -> Boolean)? = null,
) {
/**
* The result of the [MethodFingerprint].
@ -61,7 +70,7 @@ class MethodFingerprint(
* - Faster: Specify [accessFlags], [returnType] and [parameters].
* - Fastest: Specify [strings], with at least one string being an exact (non-partial) match.
*/
internal fun resolveUsingLookupMap(context: BytecodeContext): Boolean {
internal fun resolveUsingLookupMap(context: BytecodePatchContext): Boolean {
/**
* Lookup [MethodClassPair]s that match the methods strings present in a [MethodFingerprint].
*
@ -130,11 +139,11 @@ class MethodFingerprint(
* Resolve a [MethodFingerprint] against a [ClassDef].
*
* @param forClass The class on which to resolve the [MethodFingerprint] in.
* @param context The [BytecodeContext] to host proxies.
* @param context The [BytecodePatchContext] to host proxies.
* @return True if the resolution was successful, false otherwise.
*/
fun resolve(
context: BytecodeContext,
context: BytecodePatchContext,
forClass: ClassDef,
): Boolean {
for (method in forClass.methods)
@ -149,11 +158,11 @@ class MethodFingerprint(
*
* @param method The class on which to resolve the [MethodFingerprint] in.
* @param forClass The class on which to resolve the [MethodFingerprint].
* @param context The [BytecodeContext] to host proxies.
* @param context The [BytecodePatchContext] to host proxies.
* @return True if the resolution was successful or if the fingerprint is already resolved, false otherwise.
*/
fun resolve(
context: BytecodeContext,
context: BytecodePatchContext,
method: Method,
forClass: ClassDef,
): Boolean {
@ -192,7 +201,7 @@ class MethodFingerprint(
}
@Suppress("UNNECESSARY_NOT_NULL_ASSERTION")
if (methodFingerprint.customFingerprint != null && !methodFingerprint.customFingerprint!!(method, forClass)) {
if (methodFingerprint.custom != null && !methodFingerprint.custom!!(method, forClass)) {
return false
}
@ -289,42 +298,245 @@ class MethodFingerprint(
return true
}
}
companion object {
/**
* Resolve a list of [MethodFingerprint] using the lookup map built by [initializeLookupMaps].
*
* [MethodFingerprint] resolution is fast, but if many are present they can consume a noticeable
* amount of time because they are resolved in sequence.
*
* For apps with many fingerprints, resolving performance can be improved by:
* - Slowest: Specify [opcodes] and nothing else.
* - Fast: Specify [accessFlags], [returnType].
* - Faster: Specify [accessFlags], [returnType] and [parameters].
* - Fastest: Specify [strings], with at least one string being an exact (non-partial) match.
*/
internal fun Set<MethodFingerprint>.resolveUsingLookupMap(context: BytecodeContext) {
if (methods.isEmpty()) throw PatchException("lookup map not initialized")
/**
* Resolve a list of [MethodFingerprint] using the lookup map built by [initializeLookupMaps].
*
* [MethodFingerprint] resolution is fast, but if many are present they can consume a noticeable
* amount of time because they are resolved in sequence.
*
* For apps with many fingerprints, resolving performance can be improved by:
* - Slowest: Specify [MethodFingerprint.opcodes] and nothing else.
* - Fast: Specify [MethodFingerprint.accessFlags], [MethodFingerprint.returnType].
* - Faster: Specify [MethodFingerprint.accessFlags], [MethodFingerprint.returnType] and [MethodFingerprint.parameters].
* - Fastest: Specify [MethodFingerprint.strings], with at least one string being an exact (non-partial) match.
*/
internal fun Set<MethodFingerprint>.resolveUsingLookupMap(context: BytecodePatchContext) {
if (methods.isEmpty()) throw PatchException("lookup map not initialized")
forEach { fingerprint ->
fingerprint.resolveUsingLookupMap(context)
}
}
/**
* Resolve a list of [MethodFingerprint] against a list of [ClassDef].
*
* @param classes The classes on which to resolve the [MethodFingerprint] in.
* @param context The [BytecodeContext] to host proxies.
* @return True if the resolution was successful, false otherwise.
*/
fun Iterable<MethodFingerprint>.resolve(
context: BytecodeContext,
classes: Iterable<ClassDef>,
) = forEach { fingerprint ->
for (classDef in classes) {
if (fingerprint.resolve(context, classDef)) break
}
}
forEach { fingerprint ->
fingerprint.resolveUsingLookupMap(context)
}
}
/**
* Resolve a list of [MethodFingerprint] against a list of [ClassDef].
*
* @param classes The classes on which to resolve the [MethodFingerprint] in.
* @param context The [BytecodePatchContext] to host proxies.
* @return True if the resolution was successful, false otherwise.
*/
fun Iterable<MethodFingerprint>.resolve(
context: BytecodePatchContext,
classes: Iterable<ClassDef>,
) = forEach { fingerprint ->
for (classDef in classes) {
if (fingerprint.resolve(context, classDef)) break
}
}
/**
* Represents the result of a [MethodFingerprintResult].
*
* @param method The matching method.
* @param classDef The [ClassDef] that contains the matching [method].
* @param scanResult The result of scanning for the [MethodFingerprint].
* @param context The [BytecodePatchContext] this [MethodFingerprintResult] is attached to, to create proxies.
*/
@Suppress("MemberVisibilityCanBePrivate")
class MethodFingerprintResult(
val method: Method,
val classDef: ClassDef,
val scanResult: MethodFingerprintScanResult,
internal val context: BytecodePatchContext,
) {
/**
* Returns a mutable clone of [classDef]
*
* Please note, this method allocates a [ClassProxy].
* Use [classDef] where possible.
*/
@Suppress("MemberVisibilityCanBePrivate")
val mutableClass by lazy { context.proxy(classDef).mutableClass }
/**
* Returns a mutable clone of [method]
*
* Please note, this method allocates a [ClassProxy].
* Use [method] where possible.
*/
val mutableMethod by lazy {
mutableClass.methods.first {
MethodUtil.methodSignaturesMatch(it, this.method)
}
}
/**
* The result of scanning on the [MethodFingerprint].
* @param patternScanResult The result of the pattern scan.
* @param stringsScanResult The result of the string scan.
*/
class MethodFingerprintScanResult(
val patternScanResult: PatternScanResult?,
val stringsScanResult: StringsScanResult?,
) {
/**
* The result of scanning strings on the [MethodFingerprint].
* @param matches The list of strings that were matched.
*/
class StringsScanResult(val matches: List<StringMatch>) {
/**
* Represents a match for a string at an index.
* @param string The string that was matched.
* @param index The index of the string.
*/
class StringMatch(val string: String, val index: Int)
}
/**
* 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.
*/
class PatternScanResult(
val startIndex: Int,
val endIndex: Int,
)
}
}
/**
* A builder for [MethodFingerprint].
*
* @property returnType The method's return type compared using [String.startsWith].
* @property accessFlags The method's exact access flags using values of [AccessFlags].
* @property parameters The parameters of the method. Partial matches allowed and follow the same rules as [returnType].
* @property opcodes An opcode pattern of the method's instructions. Wildcard or unknown opcodes can be specified by `null`.
* @property strings A list of the method's strings compared each using [String.contains].
* @property customBlock A custom condition for this fingerprint.
*
* @constructor Creates a new [MethodFingerprintBuilder].
*/
class MethodFingerprintBuilder internal constructor() {
private var returnType: String? = null
private var accessFlags: Int? = null
private var parameters: List<String>? = null
private var opcodes: List<Opcode?>? = null
private var strings: List<String>? = null
private var customBlock: ((methodDef: Method, classDef: ClassDef) -> Boolean)? = null
/**
* Set the method's return type.
*
* @param returnType The method's return type compared using [String.startsWith].
*/
fun returns(returnType: String) {
this.returnType = returnType
}
/**
* Set the method's access flags.
*
* @param accessFlags The method's exact access flags using values of [AccessFlags].
*/
fun accessFlags(accessFlags: Int) {
this.accessFlags = accessFlags
}
/**
* Set the method's access flags.
*
* @param accessFlags The method's exact access flags using values of [AccessFlags].
*/
fun accessFlags(accessFlags: AccessFlags) {
this.accessFlags = accessFlags.value
}
/**
* Set the method's parameters.
*
* @param parameters The parameters of the method. Partial matches allowed and follow the same rules as [returnType].
*/
fun parameters(vararg parameters: String) {
this.parameters = parameters.toList()
}
/**
* Set the method's opcodes.
*
* @param opcodes An opcode pattern of the method's instructions.
* Wildcard or unknown opcodes can be specified by `null`.
*/
fun opcodes(vararg opcodes: Opcode?) {
this.opcodes = opcodes.toList()
}
/**
* Set the method's opcodes.
*
* @param instructions A list of the method's instructions or opcode names in SMALI format.
* - Wildcard or unknown opcodes can be specified by `null`.
* - Empty lines are ignored.
* - Each instruction must be on a new line.
* - The opcode name is enough, no need to specify the operands.
*
* @throws Exception If an unknown opcode is used.
*/
fun opcodes(instructions: String) {
this.opcodes = instructions.trimIndent().split("\n").filter {
it.isNotBlank()
}.map {
// Remove any operands.
val name = it.split(" ", limit = 1).first().trim()
if (name == "null") return@map null
opcodesByName[name] ?: throw Exception("Unknown opcode: $name")
}
}
/**
* Set the method's strings.
*
* @param strings A list of the method's strings compared each using [String.contains].
*/
fun strings(vararg strings: String) {
this.strings = strings.toList()
}
/**
* Set a custom condition for this fingerprint.
*
* @param customBlock A custom condition for this fingerprint.
*/
fun custom(customBlock: (methodDef: Method, classDef: ClassDef) -> Boolean) {
this.customBlock = customBlock
}
internal fun build() = MethodFingerprint(returnType, accessFlags, parameters, opcodes, strings, customBlock)
private companion object {
val opcodesByName = Opcode.entries.associateBy { it.name }
}
}
/**
* Create a [MethodFingerprint].
*
* @param block The block to build the [MethodFingerprint].
*
* @return The created [MethodFingerprint].
*/
fun methodFingerprint(block: MethodFingerprintBuilder.() -> Unit) =
MethodFingerprintBuilder().apply(block).build()
/**
* Create a [MethodFingerprint] and add it to the set of fingerprints.
*
* @param block The block to build the [MethodFingerprint].
*
* @return The created [MethodFingerprint].
*/
fun BytecodePatchBuilder.methodFingerprint(block: MethodFingerprintBuilder.() -> Unit) =
MethodFingerprintBuilder().apply(block).build()() // Invoke to add to its set of fingerprints.

View File

@ -1,77 +0,0 @@
package app.revanced.patcher.fingerprint
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.util.proxy.ClassProxy
import com.android.tools.smali.dexlib2.iface.ClassDef
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.util.MethodUtil
/**
* Represents the result of a [MethodFingerprintResult].
*
* @param method The matching method.
* @param classDef The [ClassDef] that contains the matching [method].
* @param scanResult The result of scanning for the [MethodFingerprint].
* @param context The [BytecodeContext] this [MethodFingerprintResult] is attached to, to create proxies.
*/
@Suppress("MemberVisibilityCanBePrivate")
class MethodFingerprintResult(
val method: Method,
val classDef: ClassDef,
val scanResult: MethodFingerprintScanResult,
internal val context: BytecodeContext,
) {
/**
* Returns a mutable clone of [classDef]
*
* Please note, this method allocates a [ClassProxy].
* Use [classDef] where possible.
*/
@Suppress("MemberVisibilityCanBePrivate")
val mutableClass by lazy { context.proxy(classDef).mutableClass }
/**
* Returns a mutable clone of [method]
*
* Please note, this method allocates a [ClassProxy].
* Use [method] where possible.
*/
val mutableMethod by lazy {
mutableClass.methods.first {
MethodUtil.methodSignaturesMatch(it, this.method)
}
}
/**
* The result of scanning on the [MethodFingerprint].
* @param patternScanResult The result of the pattern scan.
* @param stringsScanResult The result of the string scan.
*/
class MethodFingerprintScanResult(
val patternScanResult: PatternScanResult?,
val stringsScanResult: StringsScanResult?,
) {
/**
* The result of scanning strings on the [MethodFingerprint].
* @param matches The list of strings that were matched.
*/
class StringsScanResult(val matches: List<StringMatch>) {
/**
* Represents a match for a string at an index.
* @param string The string that was matched.
* @param index The index of the string.
*/
class StringMatch(val string: String, val index: Int)
}
/**
* 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.
*/
class PatternScanResult(
val startIndex: Int,
val endIndex: Int,
)
}
}

View File

@ -1,12 +0,0 @@
package app.revanced.patcher.fingerprint.annotation
import app.revanced.patcher.fingerprint.MethodFingerprint
/**
* Annotations to scan a pattern [MethodFingerprint] with fuzzy algorithm.
* @param threshold if [threshold] or more of the opcodes do not match, skip.
*/
@Target(AnnotationTarget.CLASS)
annotation class FuzzyPatternScanMethod(
val threshold: Int = 1,
)

View File

@ -1,10 +1,9 @@
package app.revanced.patcher.data
package app.revanced.patcher.patch
import app.revanced.patcher.InternalApi
import app.revanced.patcher.PatcherConfig
import app.revanced.patcher.PatcherContext
import app.revanced.patcher.PatcherResult
import app.revanced.patcher.patch.Patch
import app.revanced.patcher.util.ClassMerger.merge
import app.revanced.patcher.util.ProxyClassList
import app.revanced.patcher.util.method.MethodWalker
@ -22,14 +21,14 @@ import java.io.Flushable
import java.util.logging.Logger
/**
* A context for the patcher containing the current state of the bytecode.
* A context for patches containing the current state of the bytecode.
*
* @param config The [PatcherConfig] used to create this context.
*/
@Suppress("MemberVisibilityCanBePrivate")
class BytecodeContext internal constructor(private val config: PatcherConfig) :
Context<Set<PatcherResult.PatchedDexFile>> {
private val logger = Logger.getLogger(BytecodeContext::class.java.name)
class BytecodePatchContext internal constructor(private val config: PatcherConfig) :
PatchContext<Set<PatcherResult.PatchedDexFile>> {
private val logger = Logger.getLogger(BytecodePatchContext::class.java.name)
/**
* [Opcodes] of the supplied [PatcherConfig.apkFile].
@ -89,7 +88,7 @@ class BytecodeContext internal constructor(private val config: PatcherConfig) :
}
/**
* Create a [MethodWalker] instance for the current [BytecodeContext].
* Create a [MethodWalker] instance for the current [BytecodePatchContext].
*
* @param startMethod The method to start at.
* @return A [MethodWalker] instance.
@ -97,7 +96,7 @@ class BytecodeContext internal constructor(private val config: PatcherConfig) :
fun toMethodWalker(startMethod: Method) = MethodWalker(this, startMethod)
/**
* Compile bytecode from the [BytecodeContext].
* Compile bytecode from the [BytecodePatchContext].
*
* @return The compiled bytecode.
*/
@ -116,9 +115,10 @@ class BytecodeContext internal constructor(private val config: PatcherConfig) :
this,
BasicDexFileNamer(),
object : DexFile {
override fun getClasses() = this@BytecodeContext.classes.also(ProxyClassList::replaceClasses)
override fun getClasses() =
this@BytecodePatchContext.classes.also(ProxyClassList::replaceClasses)
override fun getOpcodes() = this@BytecodeContext.opcodes
override fun getOpcodes() = this@BytecodePatchContext.opcodes
},
DexIO.DEFAULT_MAX_DEX_POOL_SIZE,
) { _, entryName, _ -> logger.info("Compiled $entryName") }
@ -142,7 +142,7 @@ class BytecodeContext internal constructor(private val config: PatcherConfig) :
var merge = false
/**
* Merge integrations into the [BytecodeContext] and flush all [Integrations].
* Merge integrations into the [BytecodePatchContext] and flush all [Integrations].
*/
override fun flush() {
if (!merge) return
@ -168,7 +168,7 @@ class BytecodeContext internal constructor(private val config: PatcherConfig) :
logger.fine("$classDef exists. Adding missing methods and fields.")
existingClass.merge(classDef, this@BytecodeContext).let { mergedClass ->
existingClass.merge(classDef, this@BytecodePatchContext).let { mergedClass ->
// If the class was merged, replace the original class with the merged class.
if (mergedClass === existingClass) return@let
classes.apply {

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
package app.revanced.patcher.patch
import java.util.function.Supplier
/**
* A common interface for contexts such as [ResourcePatchContext] and [BytecodePatchContext].
*/
sealed interface PatchContext<T> : Supplier<T>

View File

@ -1,12 +0,0 @@
package app.revanced.patcher.patch
/**
* An exception thrown when patching.
*
* @param errorMessage The exception message.
* @param cause The corresponding [Throwable].
*/
class PatchException(errorMessage: String?, cause: Throwable?) : Exception(errorMessage, cause) {
constructor(errorMessage: String) : this(errorMessage, null)
constructor(cause: Throwable) : this(cause.message, cause)
}

View File

@ -0,0 +1,558 @@
package app.revanced.patcher.patch
import kotlin.reflect.KProperty
/**
* A patch option.
*
* @param T The value type of the option.
* @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.
*
* @constructor Create a new [PatchOption].
*/
@Suppress("MemberVisibilityCanBePrivate", "unused")
open class PatchOption<T>(
val key: String,
val default: T?,
val values: Map<String, T?>?,
val title: String?,
val description: String?,
val required: Boolean,
val valueType: String,
val validator: PatchOption<T>.(T?) -> Boolean,
) {
/**
* The value of the [PatchOption].
*/
var value: T?
/**
* Set the value of the [PatchOption].
*
* @param value The value to set.
*
* @throws PatchOptionException.ValueRequiredException If the value is required but null.
* @throws PatchOptionException.ValueValidationException If the value is invalid.
*/
set(value) {
assertRequiredButNotNull(value)
assertValid(value)
uncheckedValue = value
}
/**
* Get the value of the [PatchOption].
*
* @return The value.
*
* @throws PatchOptionException.ValueRequiredException If the value is required but null.
* @throws PatchOptionException.ValueValidationException If the value is invalid.
*/
get() {
assertRequiredButNotNull(uncheckedValue)
assertValid(uncheckedValue)
return uncheckedValue
}
// The unchecked value is used to allow setting the value without validation.
private var uncheckedValue = default
/**
* Reset the [PatchOption] to its default value.
* Override this method if you need to mutate the value instead of replacing it.
*/
open fun reset() {
uncheckedValue = default
}
private fun assertRequiredButNotNull(value: T?) {
if (required && value == null) throw PatchOptionException.ValueRequiredException(this)
}
private fun assertValid(value: T?) {
if (!validator(value)) throw PatchOptionException.ValueValidationException(value, this)
}
override fun toString() = value.toString()
operator fun getValue(
thisRef: Any?,
property: KProperty<*>,
) = value
operator fun setValue(
thisRef: Any?,
property: KProperty<*>,
value: T?,
) {
this.value = value
}
}
/**
* A collection of [PatchOption]s where patch options can be set and retrieved by key.
*
* @param options The patch options.
*
* @constructor Create a new [PatchOptions].
*/
class PatchOptions(
private val options: Map<String, PatchOption<*>>,
) : Map<String, PatchOption<*>> by options {
constructor(options: Set<PatchOption<*>>) : this(options.associateBy { it.key })
/**
* Set a patch option's value.
*
* @param key The key.
* @param value The value.
*
* @throws PatchOptionException.PatchOptionNotFoundException If the patch option does not exist.
*/
operator fun <T : Any> set(key: String, value: T?) {
val option = this[key]
try {
@Suppress("UNCHECKED_CAST")
(option as PatchOption<T>).value = value
} catch (e: ClassCastException) {
throw PatchOptionException.InvalidValueTypeException(
value?.let { it::class.java.name } ?: "null",
option.value?.let { it::class.java.name } ?: "null",
)
}
}
/**
* Get a patch option.
*
* @param key The key.
*
* @return The patch option.
*/
override fun get(key: String) = options[key] ?: throw PatchOptionException.PatchOptionNotFoundException(key)
}
/**
* Create a new [PatchOption] with a string value and add it to the current [PatchBuilder].
*
* @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 <P : PatchBuilder<*>> 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 },
) = addNewPatchOption(
key,
default,
values,
title,
description,
required,
"String",
validator,
)
/**
* Create a new [PatchOption] with an integer value and add it to the current [PatchBuilder].
*
* @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 <P : PatchBuilder<*>> 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 },
) = addNewPatchOption(
key,
default,
values,
title,
description,
required,
"Int",
validator,
)
/**
* Create a new [PatchOption] with a boolean value and add it to the current [PatchBuilder].
*
* @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 <P : PatchBuilder<*>> 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 },
) = addNewPatchOption(
key,
default,
values,
title,
description,
required,
"Boolean",
validator,
)
/**
* Create a new [PatchOption] with a float value and add it to the current [PatchBuilder].
*
* @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 <P : PatchBuilder<*>> 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 },
) = addNewPatchOption(
key,
default,
values,
title,
description,
required,
"Float",
validator,
)
/**
* Create a new [PatchOption] with a long value and add it to the current [PatchBuilder].
*
* @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 <P : PatchBuilder<*>> 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 },
) = addNewPatchOption(
key,
default,
values,
title,
description,
required,
"Long",
validator,
)
/**
* Create a new [PatchOption] with a string array value and add it to the current [PatchBuilder].
*
* @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 <P : PatchBuilder<*>> 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 },
) = addNewPatchOption(
key,
default,
values,
title,
description,
required,
"StringArray",
validator,
)
/**
* Create a new [PatchOption] with an integer array value and add it to the current [PatchBuilder].
*
* @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 <P : PatchBuilder<*>> 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 },
) = addNewPatchOption(
key,
default,
values,
title,
description,
required,
"IntArray",
validator,
)
/**
* Create a new [PatchOption] with a boolean array value and add it to the current [PatchBuilder].
*
* @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 <P : PatchBuilder<*>> 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 },
) = addNewPatchOption(
key,
default,
values,
title,
description,
required,
"BooleanArray",
validator,
)
/**
* Create a new [PatchOption] with a float array value and add it to the current [PatchBuilder].
*
* @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 <P : PatchBuilder<*>> 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 },
) = addNewPatchOption(
key,
default,
values,
title,
description,
required,
"FloatArray",
validator,
)
/**
* Create a new [PatchOption] with a long array value and add it to the current [PatchBuilder].
*
* @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 <P : PatchBuilder<*>> 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 },
) = addNewPatchOption(
key,
default,
values,
title,
description,
required,
"LongArray",
validator,
)
/**
* Create a new [PatchOption] and add it to the current [PatchBuilder].
*
* @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 <P : PatchBuilder<*>, T> P.addNewPatchOption(
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 { option(it) }
/**
* An exception thrown when using [PatchOption]s.
*
* @param errorMessage The exception message.
*/
sealed class PatchOptionException(errorMessage: String) : Exception(errorMessage, null) {
/**
* An exception thrown when a [PatchOption] is set to an invalid value.
*
* @param invalidType The type of the value that was passed.
* @param expectedType The type of the value that was expected.
*/
class InvalidValueTypeException(invalidType: String, expectedType: String) :
PatchOptionException("Type $expectedType was expected but received type $invalidType")
/**
* An exception thrown when a value did not satisfy the value conditions specified by the [PatchOption].
*
* @param value The value that failed validation.
*/
class ValueValidationException(value: Any?, option: PatchOption<*>) :
PatchOptionException("The option value \"$value\" failed validation for ${option.key}")
/**
* An exception thrown when a value is required but null was passed.
*
* @param option The [PatchOption] that requires a value.
*/
class ValueRequiredException(option: PatchOption<*>) :
PatchOptionException("The option ${option.key} requires a value, but null was passed")
/**
* An exception thrown when a [PatchOption] is not found.
*
* @param key The key of the [PatchOption].
*/
class PatchOptionNotFoundException(key: String) :
PatchOptionException("No option with key $key")
}

View File

@ -1,9 +0,0 @@
package app.revanced.patcher.patch
/**
* A result of executing a [Patch].
*
* @param patch The [Patch] that was executed.
* @param exception The [PatchException] thrown, if any.
*/
class PatchResult internal constructor(val patch: Patch<*>, val exception: PatchException? = null)

View File

@ -1,4 +1,4 @@
package app.revanced.patcher.data
package app.revanced.patcher.patch
import app.revanced.patcher.InternalApi
import app.revanced.patcher.PackageMetadata
@ -20,16 +20,16 @@ import java.nio.file.Files
import java.util.logging.Logger
/**
* A context for the patcher containing the current state of the resources.
* A context for patches containing the current state of resources.
*
* @param packageMetadata The [PackageMetadata] of the apk file.
* @param config The [PatcherConfig] used to create this context.
*/
class ResourceContext internal constructor(
class ResourcePatchContext internal constructor(
private val packageMetadata: PackageMetadata,
private val config: PatcherConfig,
) : Context<PatcherResult.PatchedResources?> {
private val logger = Logger.getLogger(ResourceContext::class.java.name)
) : PatchContext<PatcherResult.PatchedResources?> {
private val logger = Logger.getLogger(ResourcePatchContext::class.java.name)
/**
* Read and write documents in the [PatcherConfig.apkFiles].
@ -231,6 +231,6 @@ class ResourceContext internal constructor(
inner class DocumentOperatable {
operator fun get(inputStream: InputStream) = Document(inputStream)
operator fun get(path: String) = Document(this@ResourceContext[path])
operator fun get(path: String) = Document(this@ResourcePatchContext[path])
}
}

View File

@ -1,97 +0,0 @@
package app.revanced.patcher.patch.options
import app.revanced.patcher.patch.Patch
import kotlin.reflect.KProperty
/**
* A [Patch] option.
*
* @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.
* @param T The value type of the option.
*/
@Suppress("MemberVisibilityCanBePrivate", "unused")
open class PatchOption<T>(
val key: String,
val default: T?,
val values: Map<String, T?>?,
val title: String?,
val description: String?,
val required: Boolean,
val valueType: String,
val validator: PatchOption<T>.(T?) -> Boolean,
) {
/**
* The value of the [PatchOption].
*/
var value: T?
/**
* Set the value of the [PatchOption].
*
* @param value The value to set.
*
* @throws PatchOptionException.ValueRequiredException If the value is required but null.
* @throws PatchOptionException.ValueValidationException If the value is invalid.
*/
set(value) {
assertRequiredButNotNull(value)
assertValid(value)
uncheckedValue = value
}
/**
* Get the value of the [PatchOption].
*
* @return The value.
*
* @throws PatchOptionException.ValueRequiredException If the value is required but null.
* @throws PatchOptionException.ValueValidationException If the value is invalid.
*/
get() {
assertRequiredButNotNull(uncheckedValue)
assertValid(uncheckedValue)
return uncheckedValue
}
// The unchecked value is used to allow setting the value without validation.
private var uncheckedValue = default
/**
* Reset the [PatchOption] to its default value.
* Override this method if you need to mutate the value instead of replacing it.
*/
open fun reset() {
uncheckedValue = default
}
private fun assertRequiredButNotNull(value: T?) {
if (required && value == null) throw PatchOptionException.ValueRequiredException(this)
}
private fun assertValid(value: T?) {
if (!validator(value)) throw PatchOptionException.ValueValidationException(value, this)
}
override fun toString() = value.toString()
operator fun getValue(
thisRef: Any?,
property: KProperty<*>,
) = value
operator fun setValue(
thisRef: Any?,
property: KProperty<*>,
value: T?,
) {
this.value = value
}
}

View File

@ -1,41 +0,0 @@
package app.revanced.patcher.patch.options
/**
* An exception thrown when using [PatchOption]s.
*
* @param errorMessage The exception message.
*/
sealed class PatchOptionException(errorMessage: String) : Exception(errorMessage, null) {
/**
* An exception thrown when a [PatchOption] is set to an invalid value.
*
* @param invalidType The type of the value that was passed.
* @param expectedType The type of the value that was expected.
*/
class InvalidValueTypeException(invalidType: String, expectedType: String) :
PatchOptionException("Type $expectedType was expected but received type $invalidType")
/**
* An exception thrown when a value did not satisfy the value conditions specified by the [PatchOption].
*
* @param value The value that failed validation.
*/
class ValueValidationException(value: Any?, option: PatchOption<*>) :
PatchOptionException("The option value \"$value\" failed validation for ${option.key}")
/**
* An exception thrown when a value is required but null was passed.
*
* @param option The [PatchOption] that requires a value.
*/
class ValueRequiredException(option: PatchOption<*>) :
PatchOptionException("The option ${option.key} requires a value, but null was passed")
/**
* An exception thrown when a [PatchOption] is not found.
*
* @param key The key of the [PatchOption].
*/
class PatchOptionNotFoundException(key: String) :
PatchOptionException("No option with key $key")
}

View File

@ -1,46 +0,0 @@
package app.revanced.patcher.patch.options
/**
* A map of [PatchOption]s associated by their keys.
*
* @param options The [PatchOption]s to initialize with.
*/
class PatchOptions internal constructor(
private val options: MutableMap<String, PatchOption<*>> = mutableMapOf(),
) : MutableMap<String, PatchOption<*>> by options {
/**
* Register a [PatchOption]. Acts like [MutableMap.put].
* @param value The [PatchOption] to register.
*/
fun register(value: PatchOption<*>) {
options[value.key] = value
}
/**
* Set an option's value.
* @param key The key.
* @param value The value.
* @throws PatchOptionException.PatchOptionNotFoundException If the option does not exist.
*/
operator fun <T : Any> set(
key: String,
value: T?,
) {
val option = this[key]
try {
@Suppress("UNCHECKED_CAST")
(option as PatchOption<T>).value = value
} catch (e: ClassCastException) {
throw PatchOptionException.InvalidValueTypeException(
value?.let { it::class.java.name } ?: "null",
option.value?.let { it::class.java.name } ?: "null",
)
}
}
/**
* Get an option.
*/
override operator fun get(key: String) = options[key] ?: throw PatchOptionException.PatchOptionNotFoundException(key)
}

View File

@ -1,7 +1,7 @@
package app.revanced.patcher.util
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.or
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.util.ClassMerger.Utils.asMutableClass
import app.revanced.patcher.util.ClassMerger.Utils.filterAny
import app.revanced.patcher.util.ClassMerger.Utils.filterNotAny
@ -36,7 +36,7 @@ internal object ClassMerger {
*/
fun ClassDef.merge(
otherClass: ClassDef,
context: BytecodeContext,
context: BytecodePatchContext,
) = this
// .fixFieldAccess(otherClass)
// .fixMethodAccess(otherClass)
@ -95,7 +95,7 @@ internal object ClassMerger {
*/
private fun ClassDef.publicize(
reference: ClassDef,
context: BytecodeContext,
context: BytecodePatchContext,
) = if (reference.accessFlags.isPublic() && !accessFlags.isPublic()) {
this.asMutableClass().apply {
context.traverseClassHierarchy(this) {
@ -175,7 +175,7 @@ internal object ClassMerger {
* @param targetClass the class to start traversing the class hierarchy from
* @param callback function that is called for every class in the hierarchy
*/
fun BytecodeContext.traverseClassHierarchy(
fun BytecodePatchContext.traverseClassHierarchy(
targetClass: MutableClass,
callback: MutableClass.() -> Unit,
) {

View File

@ -1,6 +1,6 @@
package app.revanced.patcher.util.method
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
@ -13,7 +13,7 @@ import com.android.tools.smali.dexlib2.util.MethodUtil
* @param currentMethod The method to start from.
*/
class MethodWalker internal constructor(
private val bytecodeContext: BytecodeContext,
private val bytecodeContext: BytecodePatchContext,
private var currentMethod: Method,
) {
/**

View File

@ -1,12 +0,0 @@
package app.revanced.patcher.patch
import kotlin.test.Test
object PatchInitializationTest {
@Test
fun `initialize using constructor`() {
val patch = rawResourcePatch(name = "Resource patch test") { assert(true) }
assert(patch.name == "Resource patch test")
}
}

View File

@ -0,0 +1,67 @@
package app.revanced.patcher.patch
import app.revanced.patcher.fingerprint.methodFingerprint
import kotlin.test.Test
import kotlin.test.assertEquals
object PatchTest {
@Test
fun `can create patch with name`() {
val patch = bytecodePatch(name = "Test") {}
assertEquals("Test", patch.name)
}
@Test
fun `can create patch with compatible packages`() {
val patch = bytecodePatch(name = "Test") {
"compatible.package"("1.0.0")
}
assertEquals(1, patch.compatiblePackages!!.size)
assertEquals("compatible.package", patch.compatiblePackages!!.first().first)
}
@Test
fun `can create patch with fingerprints`() {
val externalFingerprint = methodFingerprint {}
val patch = bytecodePatch(name = "Test") {
val result by externalFingerprint()
val internalFingerprint = methodFingerprint {}
execute {
result.method
internalFingerprint.result
}
}
assertEquals(2, patch.fingerprints.size)
}
@Test
fun `can create patch with dependencies`() {
val externalPatch = resourcePatch {}
val patch = bytecodePatch(name = "Test") {
externalPatch()
resourcePatch {}
}
assertEquals(2, patch.dependencies.size)
assertEquals(externalPatch, patch.dependencies.first())
}
@Test
fun `can create patch with options`() {
val patch = bytecodePatch(name = "Test") {
val print by stringPatchOption("print")
execute {
println(print)
}
}
assertEquals(1, patch.options.size)
}
}

View File

@ -1,6 +1,6 @@
package app.revanced.patcher.patch.options
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.*
import org.junit.jupiter.api.assertDoesNotThrow
import org.junit.jupiter.api.assertThrows
import kotlin.test.Test
@ -68,11 +68,10 @@ internal class PatchOptionsTest {
@Test
fun `should be able to add options manually`() = options {
assertThrows<PatchOptionException.InvalidValueTypeException> {
set("array", get("array"))
}
assertDoesNotThrow {
register(get("array"))
bytecodePatch {
option(get("array"))
}.options["array"]
}
}