mirror of
https://github.com/ReVanced/revanced-patcher.git
synced 2026-01-12 06:16:18 +00:00
Compare commits
36 Commits
v19.3.0-de
...
v1.0.0-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b1337e4fc | ||
|
|
f4589db3a9 | ||
|
|
1af31b2aa3 | ||
|
|
14f7667156 | ||
|
|
cd57a8c9a0 | ||
|
|
0d3beb353d | ||
|
|
ddef338631 | ||
|
|
fc4b673087 | ||
|
|
8d1bb5f3d9 | ||
|
|
c8a017a4c0 | ||
|
|
51fb59a43c | ||
|
|
a78715133c | ||
|
|
e8f6973938 | ||
|
|
3cb1e01587 | ||
|
|
cb4ee207e1 | ||
|
|
ca6b94d943 | ||
|
|
6cdb6887d4 | ||
|
|
ab6453ca8a | ||
|
|
e8182c17ad | ||
|
|
49beec9fc6 | ||
|
|
3ab42a932c | ||
|
|
4d98cbc9e8 | ||
|
|
87bbde5e06 | ||
|
|
8db8893ab1 | ||
|
|
00c6ab7faf | ||
|
|
460d62a24c | ||
|
|
89e4b9f762 | ||
|
|
a8fd7c00c3 | ||
|
|
1769132a9e | ||
|
|
6c0f0823c9 | ||
|
|
23e897a7a9 | ||
|
|
7e67daf878 | ||
|
|
593c83f29f | ||
|
|
72e123dd01 | ||
|
|
599a401ed9 | ||
|
|
3f8500b059 |
@@ -1,3 +0,0 @@
|
||||
[*.{kt,kts}]
|
||||
ktlint_code_style = intellij_idea
|
||||
ktlint_standard_no-wildcard-imports = disabled
|
||||
9
.gitattributes
vendored
9
.gitattributes
vendored
@@ -1,9 +0,0 @@
|
||||
#
|
||||
# https://help.github.com/articles/dealing-with-line-endings/
|
||||
#
|
||||
# Linux start script should use lf
|
||||
/gradlew text eol=lf
|
||||
|
||||
# These are Windows script files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
|
||||
108
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
108
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@@ -1,108 +0,0 @@
|
||||
name: 🐞 Bug report
|
||||
description: Report a bug or an issue.
|
||||
title: 'bug: '
|
||||
labels: ['Bug report']
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
<p align="center">
|
||||
<picture>
|
||||
<source
|
||||
width="256px"
|
||||
media="(prefers-color-scheme: dark)"
|
||||
srcset="https://raw.githubusercontent.com/revanced/revanced-patcher/main/assets/revanced-headline/revanced-headline-vertical-dark.svg"
|
||||
>
|
||||
<img
|
||||
width="256px"
|
||||
src="https://raw.githubusercontent.com/revanced/revanced-patcher/main/assets/revanced-headline/revanced-headline-vertical-light.svg"
|
||||
>
|
||||
</picture>
|
||||
<br>
|
||||
<a href="https://revanced.app/">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/revanced/revanced-patcher/main/assets/revanced-logo/revanced-logo.svg" />
|
||||
<img height="24px" src="https://raw.githubusercontent.com/revanced/revanced-patcher/main/assets/revanced-logo/revanced-logo.svg" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://github.com/ReVanced">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" />
|
||||
<img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="http://revanced.app/discord">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://reddit.com/r/revancedapp">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://t.me/app_revanced">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://x.com/revancedapp">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/93124920/270180600-7c1b38bf-889b-4d68-bd5e-b9d86f91421a.png">
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/93124920/270108715-d80743fa-b330-4809-b1e6-79fbdc60d09c.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://www.youtube.com/@ReVanced">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<br>
|
||||
<br>
|
||||
Continuing the legacy of Vanced
|
||||
</p>
|
||||
|
||||
# ReVanced Patcher bug report
|
||||
|
||||
Before creating a new bug report, please keep the following in mind:
|
||||
|
||||
- **Do not submit a duplicate bug report**: You can review existing bug reports [here](https://github.com/ReVanced/revanced-patcher/labels/Bug%20report).
|
||||
- **Do not use the issue page for support**: If you need help or have questions, check out other platforms on [revanced.app](https://revanced.app).
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Bug description
|
||||
description: |
|
||||
- Describe your bug in detail
|
||||
- Add steps to reproduce the bug if possible (Step 1. ... Step 2. ...)
|
||||
- Add images and videos if possible
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Error logs
|
||||
description: Exceptions can be captured by running `logcat | grep AndroidRuntime` in a shell.
|
||||
render: shell
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Solution
|
||||
description: If applicable, add a possible solution to the bug.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add additional context here.
|
||||
- type: checkboxes
|
||||
id: acknowledgements
|
||||
attributes:
|
||||
label: Acknowledgements
|
||||
description: Your bug report will be closed if you don't follow the checklist below.
|
||||
options:
|
||||
- label: This issue is not a duplicate of an existing bug report.
|
||||
required: true
|
||||
- label: I have chosen an appropriate title.
|
||||
required: true
|
||||
- label: All requested information has been provided properly.
|
||||
required: true
|
||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
8
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,8 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: 📃 Documentation
|
||||
url: https://github.com/revanced/revanced-documentation/
|
||||
about: Don't know how or where to start? Check out our documentation!
|
||||
- name: 🗨 Discussions
|
||||
url: https://github.com/revanced/revanced-suggestions/discussions
|
||||
about: Got something you think should change or be added? Search for or start a new discussion!
|
||||
106
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
106
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
@@ -1,106 +0,0 @@
|
||||
name: ⭐ Feature request
|
||||
description: Create a detailed request for a new feature.
|
||||
title: 'feat: '
|
||||
labels: ['Feature request']
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
<p align="center">
|
||||
<picture>
|
||||
<source
|
||||
width="256px"
|
||||
media="(prefers-color-scheme: dark)"
|
||||
srcset="https://raw.githubusercontent.com/revanced/revanced-patcher/main/assets/revanced-headline/revanced-headline-vertical-dark.svg"
|
||||
>
|
||||
<img
|
||||
width="256px"
|
||||
src="https://raw.githubusercontent.com/revanced/revanced-patcher/main/assets/revanced-headline/revanced-headline-vertical-light.svg"
|
||||
>
|
||||
</picture>
|
||||
<br>
|
||||
<a href="https://revanced.app/">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/revanced/revanced-patcher/main/assets/revanced-logo/revanced-logo.svg" />
|
||||
<img height="24px" src="https://raw.githubusercontent.com/revanced/revanced-patcher/main/assets/revanced-logo/revanced-logo.svg" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://github.com/ReVanced">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" />
|
||||
<img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="http://revanced.app/discord">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://reddit.com/r/revancedapp">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://t.me/app_revanced">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://x.com/revancedapp">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/93124920/270180600-7c1b38bf-889b-4d68-bd5e-b9d86f91421a.png">
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/93124920/270108715-d80743fa-b330-4809-b1e6-79fbdc60d09c.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://www.youtube.com/@ReVanced">
|
||||
<picture>
|
||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
|
||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
|
||||
</picture>
|
||||
</a>
|
||||
<br>
|
||||
<br>
|
||||
Continuing the legacy of Vanced
|
||||
</p>
|
||||
|
||||
# ReVanced Patcher feature request
|
||||
|
||||
Before creating a new feature request, please keep the following in mind:
|
||||
|
||||
- **Do not submit a duplicate feature request**: You can review existing feature requests [here](https://github.com/ReVanced/revanced-patcher/labels/Feature%20request).
|
||||
- **Do not use the issue page for support**: If you need help or have questions, check out other platforms on [revanced.app](https://revanced.app).
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Feature description
|
||||
description: |
|
||||
- Describe your feature in detail
|
||||
- Add images, videos, links, examples, references, etc. if possible
|
||||
- Add the target application name in case you request a new patch
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Motivation
|
||||
description: |
|
||||
A strong motivation is necessary for a feature request to be considered.
|
||||
|
||||
- Why should this feature be implemented?
|
||||
- What is the explicit use case?
|
||||
- What are the benefits?
|
||||
- What makes this feature important?
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: acknowledgements
|
||||
attributes:
|
||||
label: Acknowledgements
|
||||
description: Your feature request will be closed if you don't follow the checklist below.
|
||||
options:
|
||||
- label: This issue is not a duplicate of an existing feature request.
|
||||
required: true
|
||||
- label: I have chosen an appropriate title.
|
||||
required: true
|
||||
- label: All requested information has been provided properly.
|
||||
required: true
|
||||
2
.github/config.yml
vendored
2
.github/config.yml
vendored
@@ -1,2 +0,0 @@
|
||||
firstPRMergeComment: >
|
||||
Thank you for contributing to ReVanced. Join us on [Discord](https://revanced.app/discord) to receive a role for your contribution.
|
||||
22
.github/dependabot.yml
vendored
22
.github/dependabot.yml
vendored
@@ -1,22 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: github-actions
|
||||
labels: []
|
||||
directory: /
|
||||
target-branch: dev
|
||||
schedule:
|
||||
interval: monthly
|
||||
|
||||
- package-ecosystem: npm
|
||||
labels: []
|
||||
directory: /
|
||||
target-branch: dev
|
||||
schedule:
|
||||
interval: monthly
|
||||
|
||||
- package-ecosystem: gradle
|
||||
labels: []
|
||||
directory: /
|
||||
target-branch: dev
|
||||
schedule:
|
||||
interval: monthly
|
||||
26
.github/workflows/pull_request.yml
vendored
26
.github/workflows/pull_request.yml
vendored
@@ -1,26 +0,0 @@
|
||||
name: Open a PR to main
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
MESSAGE: Merge branch `${{ github.head_ref || github.ref_name }}` to `main`
|
||||
|
||||
jobs:
|
||||
pull-request:
|
||||
name: Open pull request
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Open pull request
|
||||
uses: repo-sync/pull-request@v2
|
||||
with:
|
||||
destination_branch: 'main'
|
||||
pr_title: 'chore: ${{ env.MESSAGE }}'
|
||||
pr_body: 'This pull request will ${{ env.MESSAGE }}.'
|
||||
pr_draft: true
|
||||
45
.github/workflows/release.yml
vendored
45
.github/workflows/release.yml
vendored
@@ -1,7 +1,5 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
@@ -10,45 +8,32 @@ on:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# Make sure the release step uses its own credentials:
|
||||
# https://github.com/cycjimmy/semantic-release-action#private-packages
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Import GPG key
|
||||
uses: crazy-max/ghaction-import-gpg@v6
|
||||
- name: Setup JDK
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
passphrase: ${{ secrets.PASSPHRASE }}
|
||||
fingerprint: ${{ env.GPG_FINGERPRINT }}
|
||||
|
||||
- name: Cache Gradle
|
||||
uses: burrunan/gradle-cache-action@v1
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: ./gradlew build clean
|
||||
|
||||
java-version: '8'
|
||||
distribution: 'adopt'
|
||||
cache: gradle
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: "lts/*"
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Make gradlew executable
|
||||
run: chmod +x gradlew
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build
|
||||
- name: Setup semantic-release
|
||||
run: npm install -g semantic-release @semantic-release/git @semantic-release/changelog gradle-semantic-release-plugin -D
|
||||
- name: Release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
|
||||
run: npm exec semantic-release
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: npx semantic-release
|
||||
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -74,7 +74,6 @@ cmake-build-*/
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
.idea/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
@@ -116,9 +115,3 @@ gradle-app.setting
|
||||
|
||||
# Avoid ignoring test resources
|
||||
!src/test/resources/*
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
|
||||
# Gradle props, to avoid sharing the gpr key
|
||||
gradle.properties
|
||||
|
||||
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
10
.idea/codeStyles/Project.xml
generated
Normal file
10
.idea/codeStyles/Project.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<JetCodeStyleSettings>
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
<codeStyleSettings language="kotlin">
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
||||
7
.idea/discord.xml
generated
Normal file
7
.idea/discord.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DiscordProjectSettings">
|
||||
<option name="show" value="PROJECT_FILES" />
|
||||
<option name="description" value="" />
|
||||
</component>
|
||||
</project>
|
||||
15
.idea/git_toolbox_prj.xml
generated
Normal file
15
.idea/git_toolbox_prj.xml
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GitToolBoxProjectSettings">
|
||||
<option name="commitMessageIssueKeyValidationOverride">
|
||||
<BoolValueOverride>
|
||||
<option name="enabled" value="true" />
|
||||
</BoolValueOverride>
|
||||
</option>
|
||||
<option name="commitMessageValidationEnabledOverride">
|
||||
<BoolValueOverride>
|
||||
<option name="enabled" value="true" />
|
||||
</BoolValueOverride>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
10
.idea/misc.xml
generated
Normal file
10
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="FrameworkDetectionExcludesConfiguration">
|
||||
<file type="web" url="file://$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
12
.idea/vcs.xml
generated
Normal file
12
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CommitMessageInspectionProfile">
|
||||
<profile version="1.0">
|
||||
<inspection_tool class="CommitFormat" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="CommitNamingConvention" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
22
.releaserc
22
.releaserc
@@ -7,13 +7,7 @@
|
||||
}
|
||||
],
|
||||
"plugins": [
|
||||
[
|
||||
"@semantic-release/commit-analyzer", {
|
||||
"releaseRules": [
|
||||
{ "type": "build", "scope": "Needs bump", "release": "patch" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"@semantic-release/commit-analyzer",
|
||||
"@semantic-release/release-notes-generator",
|
||||
"@semantic-release/changelog",
|
||||
"gradle-semantic-release-plugin",
|
||||
@@ -26,18 +20,6 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
[
|
||||
"@saithodev/semantic-release-backmerge",
|
||||
{
|
||||
backmergeBranches: [{"from": "main", "to": "dev"}],
|
||||
clearWorkspace: true
|
||||
}
|
||||
],
|
||||
[
|
||||
"@semantic-release/github",
|
||||
{
|
||||
successComment: false
|
||||
}
|
||||
]
|
||||
"@semantic-release/github"
|
||||
]
|
||||
}
|
||||
|
||||
2111
CHANGELOG.md
2111
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1 @@
|
||||
# 💉 ReVanced Patcher
|
||||
|
||||
ReVanced Patcher used to patch Android applications.
|
||||
# Patcher
|
||||
|
||||
@@ -1,892 +0,0 @@
|
||||
public abstract interface class app/revanced/patcher/IntegrationsConsumer {
|
||||
public abstract fun acceptIntegrations (Ljava/util/List;)V
|
||||
public abstract fun acceptIntegrations (Ljava/util/Set;)V
|
||||
}
|
||||
|
||||
public abstract interface annotation class app/revanced/patcher/InternalApi : java/lang/annotation/Annotation {
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/PackageMetadata {
|
||||
public final fun getPackageName ()Ljava/lang/String;
|
||||
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;)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
|
||||
}
|
||||
|
||||
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 {
|
||||
}
|
||||
|
||||
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;
|
||||
public fun close ()V
|
||||
public fun get ()Lapp/revanced/patcher/PatcherResult;
|
||||
public synthetic fun get ()Ljava/lang/Object;
|
||||
public final fun getContext ()Lapp/revanced/patcher/PatcherContext;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/PatcherConfig {
|
||||
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 class app/revanced/patcher/PatcherContext {
|
||||
public final fun getPackageMetadata ()Lapp/revanced/patcher/PackageMetadata;
|
||||
}
|
||||
|
||||
public abstract class app/revanced/patcher/PatcherException : java/lang/Exception {
|
||||
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/Throwable;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public synthetic fun <init> (Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/PatcherResult$PatchedResources {
|
||||
public final fun getDeleteResources ()Ljava/util/Set;
|
||||
public final fun getDoNotCompress ()Ljava/util/Set;
|
||||
public final fun getOtherResources ()Ljava/io/File;
|
||||
public final fun getResourcesApk ()Ljava/io/File;
|
||||
}
|
||||
|
||||
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;
|
||||
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, java/lang/Iterable, kotlin/jvm/internal/markers/KMappedMarker {
|
||||
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
|
||||
}
|
||||
|
||||
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/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
|
||||
public static final fun or (Lcom/android/tools/smali/dexlib2/AccessFlags;I)I
|
||||
public static final fun or (Lcom/android/tools/smali/dexlib2/AccessFlags;Lcom/android/tools/smali/dexlib2/AccessFlags;)I
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/extensions/InstructionExtensions {
|
||||
public static final field INSTANCE Lapp/revanced/patcher/extensions/InstructionExtensions;
|
||||
public final fun addInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILcom/android/tools/smali/dexlib2/builder/BuilderInstruction;)V
|
||||
public final fun addInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/String;)V
|
||||
public final fun addInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Lcom/android/tools/smali/dexlib2/builder/BuilderInstruction;)V
|
||||
public final fun addInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Ljava/lang/String;)V
|
||||
public final fun addInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/String;)V
|
||||
public final fun addInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/util/List;)V
|
||||
public final fun addInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Ljava/lang/String;)V
|
||||
public final fun addInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Ljava/util/List;)V
|
||||
public final fun addInstructions (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;ILjava/util/List;)V
|
||||
public final fun addInstructions (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;Ljava/util/List;)V
|
||||
public final fun addInstructionsWithLabels (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/String;[Lapp/revanced/patcher/util/smali/ExternalLabel;)V
|
||||
public final fun getInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)Lcom/android/tools/smali/dexlib2/builder/BuilderInstruction;
|
||||
public final fun getInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)Ljava/lang/Object;
|
||||
public final fun getInstruction (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;I)Lcom/android/tools/smali/dexlib2/builder/BuilderInstruction;
|
||||
public final fun getInstruction (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;I)Ljava/lang/Object;
|
||||
public final fun getInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;)Ljava/util/List;
|
||||
public final fun removeInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)V
|
||||
public final fun removeInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)V
|
||||
public final fun removeInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;II)V
|
||||
public final fun removeInstructions (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;I)V
|
||||
public final fun removeInstructions (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;II)V
|
||||
public final fun replaceInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILcom/android/tools/smali/dexlib2/builder/BuilderInstruction;)V
|
||||
public final fun replaceInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/String;)V
|
||||
public final fun replaceInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/String;)V
|
||||
public final fun replaceInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/util/List;)V
|
||||
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 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 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
|
||||
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 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/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 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;
|
||||
public final fun getMutableMethod ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;
|
||||
public final fun getScanResult ()Lapp/revanced/patcher/fingerprint/MethodFingerprintResult$MethodFingerprintScanResult;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/fingerprint/MethodFingerprintResult$MethodFingerprintScanResult {
|
||||
public fun <init> (Lapp/revanced/patcher/fingerprint/MethodFingerprintResult$MethodFingerprintScanResult$PatternScanResult;Lapp/revanced/patcher/fingerprint/MethodFingerprintResult$MethodFingerprintScanResult$StringsScanResult;)V
|
||||
public final fun getPatternScanResult ()Lapp/revanced/patcher/fingerprint/MethodFingerprintResult$MethodFingerprintScanResult$PatternScanResult;
|
||||
public final fun getStringsScanResult ()Lapp/revanced/patcher/fingerprint/MethodFingerprintResult$MethodFingerprintScanResult$StringsScanResult;
|
||||
}
|
||||
|
||||
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 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 {
|
||||
public fun <init> (Ljava/util/List;)V
|
||||
public final fun getMatches ()Ljava/util/List;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/fingerprint/MethodFingerprintResult$MethodFingerprintScanResult$StringsScanResult$StringMatch {
|
||||
public fun <init> (Ljava/lang/String;I)V
|
||||
public final fun getIndex ()I
|
||||
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 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 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 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 getRequiresIntegrations ()Z
|
||||
public final fun getUse ()Z
|
||||
public fun hashCode ()I
|
||||
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/PatchException : java/lang/Exception {
|
||||
public fun <init> (Ljava/lang/String;)V
|
||||
public fun <init> (Ljava/lang/String;Ljava/lang/Throwable;)V
|
||||
public fun <init> (Ljava/lang/Throwable;)V
|
||||
}
|
||||
|
||||
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 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 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;
|
||||
public final fun getKey ()Ljava/lang/String;
|
||||
public final fun getRequired ()Z
|
||||
public final fun getTitle ()Ljava/lang/String;
|
||||
public final fun getValidator ()Lkotlin/jvm/functions/Function2;
|
||||
public final fun getValue ()Ljava/lang/Object;
|
||||
public final fun getValue (Ljava/lang/Object;Lkotlin/reflect/KProperty;)Ljava/lang/Object;
|
||||
public final fun getValueType ()Ljava/lang/String;
|
||||
public final fun getValues ()Ljava/util/Map;
|
||||
public fun reset ()V
|
||||
public final fun setValue (Ljava/lang/Object;)V
|
||||
public final fun setValue (Ljava/lang/Object;Lkotlin/reflect/KProperty;Ljava/lang/Object;)V
|
||||
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
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/patch/options/PatchOptionException$InvalidValueTypeException : app/revanced/patcher/patch/options/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 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/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/options/PatchOptions : java/util/Map, kotlin/jvm/internal/markers/KMutableMap {
|
||||
public fun <init> ()V
|
||||
public fun clear ()V
|
||||
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 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 synthetic fun get (Ljava/lang/Object;)Ljava/lang/Object;
|
||||
public fun get (Ljava/lang/String;)Lapp/revanced/patcher/patch/options/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 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 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 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/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;
|
||||
public fun cloneNode (Z)Lorg/w3c/dom/Node;
|
||||
public fun close ()V
|
||||
public fun compareDocumentPosition (Lorg/w3c/dom/Node;)S
|
||||
public fun createAttribute (Ljava/lang/String;)Lorg/w3c/dom/Attr;
|
||||
public fun createAttributeNS (Ljava/lang/String;Ljava/lang/String;)Lorg/w3c/dom/Attr;
|
||||
public fun createCDATASection (Ljava/lang/String;)Lorg/w3c/dom/CDATASection;
|
||||
public fun createComment (Ljava/lang/String;)Lorg/w3c/dom/Comment;
|
||||
public fun createDocumentFragment ()Lorg/w3c/dom/DocumentFragment;
|
||||
public fun createElement (Ljava/lang/String;)Lorg/w3c/dom/Element;
|
||||
public fun createElementNS (Ljava/lang/String;Ljava/lang/String;)Lorg/w3c/dom/Element;
|
||||
public fun createEntityReference (Ljava/lang/String;)Lorg/w3c/dom/EntityReference;
|
||||
public fun createProcessingInstruction (Ljava/lang/String;Ljava/lang/String;)Lorg/w3c/dom/ProcessingInstruction;
|
||||
public fun createTextNode (Ljava/lang/String;)Lorg/w3c/dom/Text;
|
||||
public fun getAttributes ()Lorg/w3c/dom/NamedNodeMap;
|
||||
public fun getBaseURI ()Ljava/lang/String;
|
||||
public fun getChildNodes ()Lorg/w3c/dom/NodeList;
|
||||
public fun getDoctype ()Lorg/w3c/dom/DocumentType;
|
||||
public fun getDocumentElement ()Lorg/w3c/dom/Element;
|
||||
public fun getDocumentURI ()Ljava/lang/String;
|
||||
public fun getDomConfig ()Lorg/w3c/dom/DOMConfiguration;
|
||||
public fun getElementById (Ljava/lang/String;)Lorg/w3c/dom/Element;
|
||||
public fun getElementsByTagName (Ljava/lang/String;)Lorg/w3c/dom/NodeList;
|
||||
public fun getElementsByTagNameNS (Ljava/lang/String;Ljava/lang/String;)Lorg/w3c/dom/NodeList;
|
||||
public fun getFeature (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
|
||||
public fun getFirstChild ()Lorg/w3c/dom/Node;
|
||||
public fun getImplementation ()Lorg/w3c/dom/DOMImplementation;
|
||||
public fun getInputEncoding ()Ljava/lang/String;
|
||||
public fun getLastChild ()Lorg/w3c/dom/Node;
|
||||
public fun getLocalName ()Ljava/lang/String;
|
||||
public fun getNamespaceURI ()Ljava/lang/String;
|
||||
public fun getNextSibling ()Lorg/w3c/dom/Node;
|
||||
public fun getNodeName ()Ljava/lang/String;
|
||||
public fun getNodeType ()S
|
||||
public fun getNodeValue ()Ljava/lang/String;
|
||||
public fun getOwnerDocument ()Lorg/w3c/dom/Document;
|
||||
public fun getParentNode ()Lorg/w3c/dom/Node;
|
||||
public fun getPrefix ()Ljava/lang/String;
|
||||
public fun getPreviousSibling ()Lorg/w3c/dom/Node;
|
||||
public fun getStrictErrorChecking ()Z
|
||||
public fun getTextContent ()Ljava/lang/String;
|
||||
public fun getUserData (Ljava/lang/String;)Ljava/lang/Object;
|
||||
public fun getXmlEncoding ()Ljava/lang/String;
|
||||
public fun getXmlStandalone ()Z
|
||||
public fun getXmlVersion ()Ljava/lang/String;
|
||||
public fun hasAttributes ()Z
|
||||
public fun hasChildNodes ()Z
|
||||
public fun importNode (Lorg/w3c/dom/Node;Z)Lorg/w3c/dom/Node;
|
||||
public fun insertBefore (Lorg/w3c/dom/Node;Lorg/w3c/dom/Node;)Lorg/w3c/dom/Node;
|
||||
public fun isDefaultNamespace (Ljava/lang/String;)Z
|
||||
public fun isEqualNode (Lorg/w3c/dom/Node;)Z
|
||||
public fun isSameNode (Lorg/w3c/dom/Node;)Z
|
||||
public fun isSupported (Ljava/lang/String;Ljava/lang/String;)Z
|
||||
public fun lookupNamespaceURI (Ljava/lang/String;)Ljava/lang/String;
|
||||
public fun lookupPrefix (Ljava/lang/String;)Ljava/lang/String;
|
||||
public fun normalize ()V
|
||||
public fun normalizeDocument ()V
|
||||
public fun removeChild (Lorg/w3c/dom/Node;)Lorg/w3c/dom/Node;
|
||||
public fun renameNode (Lorg/w3c/dom/Node;Ljava/lang/String;Ljava/lang/String;)Lorg/w3c/dom/Node;
|
||||
public fun replaceChild (Lorg/w3c/dom/Node;Lorg/w3c/dom/Node;)Lorg/w3c/dom/Node;
|
||||
public fun setDocumentURI (Ljava/lang/String;)V
|
||||
public fun setNodeValue (Ljava/lang/String;)V
|
||||
public fun setPrefix (Ljava/lang/String;)V
|
||||
public fun setStrictErrorChecking (Z)V
|
||||
public fun setTextContent (Ljava/lang/String;)V
|
||||
public fun setUserData (Ljava/lang/String;Ljava/lang/Object;Lorg/w3c/dom/UserDataHandler;)Ljava/lang/Object;
|
||||
public fun setXmlStandalone (Z)V
|
||||
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
|
||||
public synthetic fun add (Ljava/lang/Object;)Z
|
||||
public fun addAll (Ljava/util/Collection;)Z
|
||||
public fun clear ()V
|
||||
public fun contains (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)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 (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Z
|
||||
public final 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/util/method/MethodWalker {
|
||||
public final fun getMethod ()Lcom/android/tools/smali/dexlib2/iface/Method;
|
||||
public final fun nextMethod (IZ)Lapp/revanced/patcher/util/method/MethodWalker;
|
||||
public static synthetic fun nextMethod$default (Lapp/revanced/patcher/util/method/MethodWalker;IZILjava/lang/Object;)Lapp/revanced/patcher/util/method/MethodWalker;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/ClassProxy {
|
||||
public final fun getImmutableClass ()Lcom/android/tools/smali/dexlib2/iface/ClassDef;
|
||||
public final fun getMutableClass ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableAnnotation : com/android/tools/smali/dexlib2/base/BaseAnnotation {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/MutableAnnotation$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/Annotation;)V
|
||||
public fun getElements ()Ljava/util/Set;
|
||||
public fun getType ()Ljava/lang/String;
|
||||
public fun getVisibility ()I
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableAnnotation$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/Annotation;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableAnnotation;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableAnnotationElement : com/android/tools/smali/dexlib2/base/BaseAnnotationElement {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/MutableAnnotationElement$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/AnnotationElement;)V
|
||||
public fun getName ()Ljava/lang/String;
|
||||
public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/value/EncodedValue;
|
||||
public final fun setName (Ljava/lang/String;)V
|
||||
public final fun setValue (Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableAnnotationElement$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/AnnotationElement;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableAnnotationElement;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableClass : com/android/tools/smali/dexlib2/base/reference/BaseTypeReference, com/android/tools/smali/dexlib2/iface/ClassDef {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)V
|
||||
public final fun charAt (I)C
|
||||
public fun get (I)C
|
||||
public fun getAccessFlags ()I
|
||||
public fun getAnnotations ()Ljava/util/Set;
|
||||
public synthetic fun getDirectMethods ()Ljava/lang/Iterable;
|
||||
public fun getDirectMethods ()Ljava/util/Set;
|
||||
public synthetic fun getFields ()Ljava/lang/Iterable;
|
||||
public fun getFields ()Ljava/util/Set;
|
||||
public synthetic fun getInstanceFields ()Ljava/lang/Iterable;
|
||||
public fun getInstanceFields ()Ljava/util/Set;
|
||||
public fun getInterfaces ()Ljava/util/List;
|
||||
public fun getLength ()I
|
||||
public synthetic fun getMethods ()Ljava/lang/Iterable;
|
||||
public fun getMethods ()Ljava/util/Set;
|
||||
public fun getSourceFile ()Ljava/lang/String;
|
||||
public synthetic fun getStaticFields ()Ljava/lang/Iterable;
|
||||
public fun getStaticFields ()Ljava/util/Set;
|
||||
public fun getSuperclass ()Ljava/lang/String;
|
||||
public fun getType ()Ljava/lang/String;
|
||||
public synthetic fun getVirtualMethods ()Ljava/lang/Iterable;
|
||||
public fun getVirtualMethods ()Ljava/util/Set;
|
||||
public final fun length ()I
|
||||
public final fun setAccessFlags (I)V
|
||||
public final fun setSourceFile (Ljava/lang/String;)V
|
||||
public final fun setSuperClass (Ljava/lang/String;)V
|
||||
public final fun setType (Ljava/lang/String;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableClass$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableField : com/android/tools/smali/dexlib2/base/reference/BaseFieldReference, com/android/tools/smali/dexlib2/iface/Field {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/MutableField$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/Field;)V
|
||||
public fun getAccessFlags ()I
|
||||
public fun getAnnotations ()Ljava/util/Set;
|
||||
public fun getDefiningClass ()Ljava/lang/String;
|
||||
public fun getHiddenApiRestrictions ()Ljava/util/Set;
|
||||
public fun getInitialValue ()Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue;
|
||||
public synthetic fun getInitialValue ()Lcom/android/tools/smali/dexlib2/iface/value/EncodedValue;
|
||||
public fun getName ()Ljava/lang/String;
|
||||
public fun getType ()Ljava/lang/String;
|
||||
public final fun setAccessFlags (I)V
|
||||
public final fun setDefiningClass (Ljava/lang/String;)V
|
||||
public final fun setInitialValue (Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue;)V
|
||||
public final fun setName (Ljava/lang/String;)V
|
||||
public final fun setType (Ljava/lang/String;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableField$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/Field;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableField;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableMethod : com/android/tools/smali/dexlib2/base/reference/BaseMethodReference, com/android/tools/smali/dexlib2/iface/Method {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/Method;)V
|
||||
public fun getAccessFlags ()I
|
||||
public fun getAnnotations ()Ljava/util/Set;
|
||||
public fun getDefiningClass ()Ljava/lang/String;
|
||||
public fun getHiddenApiRestrictions ()Ljava/util/Set;
|
||||
public fun getImplementation ()Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;
|
||||
public synthetic fun getImplementation ()Lcom/android/tools/smali/dexlib2/iface/MethodImplementation;
|
||||
public fun getName ()Ljava/lang/String;
|
||||
public fun getParameterTypes ()Ljava/util/List;
|
||||
public fun getParameters ()Ljava/util/List;
|
||||
public fun getReturnType ()Ljava/lang/String;
|
||||
public final fun setAccessFlags (I)V
|
||||
public final fun setDefiningClass (Ljava/lang/String;)V
|
||||
public final fun setName (Ljava/lang/String;)V
|
||||
public final fun setReturnType (Ljava/lang/String;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableMethod$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableMethodParameter : com/android/tools/smali/dexlib2/base/BaseMethodParameter, com/android/tools/smali/dexlib2/iface/MethodParameter {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethodParameter$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/MethodParameter;)V
|
||||
public final fun charAt (I)C
|
||||
public fun get (I)C
|
||||
public fun getAnnotations ()Ljava/util/Set;
|
||||
public fun getLength ()I
|
||||
public fun getName ()Ljava/lang/String;
|
||||
public fun getSignature ()Ljava/lang/String;
|
||||
public fun getType ()Ljava/lang/String;
|
||||
public final fun length ()I
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/MutableMethodParameter$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/MethodParameter;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethodParameter;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableAnnotationEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseAnnotationEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableAnnotationEncodedValue$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/AnnotationEncodedValue;)V
|
||||
public fun getElements ()Ljava/util/Set;
|
||||
public fun getType ()Ljava/lang/String;
|
||||
public final fun setType (Ljava/lang/String;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableAnnotationEncodedValue$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/AnnotationEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableAnnotationEncodedValue;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableArrayEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseArrayEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableArrayEncodedValue$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/ArrayEncodedValue;)V
|
||||
public fun getValue ()Ljava/util/List;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableArrayEncodedValue$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/ArrayEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableArrayEncodedValue;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableBooleanEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseBooleanEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableBooleanEncodedValue$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/BooleanEncodedValue;)V
|
||||
public fun getValue ()Z
|
||||
public final fun setValue (Z)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableBooleanEncodedValue$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/BooleanEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableBooleanEncodedValue;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseByteEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/ByteEncodedValue;)V
|
||||
public fun getValue ()B
|
||||
public final fun setValue (B)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/ByteEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableCharEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseCharEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableCharEncodedValue$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/CharEncodedValue;)V
|
||||
public fun getValue ()C
|
||||
public final fun setValue (C)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableCharEncodedValue$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/CharEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableCharEncodedValue;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableDoubleEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseDoubleEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableDoubleEncodedValue$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/DoubleEncodedValue;)V
|
||||
public fun getValue ()D
|
||||
public final fun setValue (D)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableDoubleEncodedValue$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/DoubleEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableDoubleEncodedValue;
|
||||
}
|
||||
|
||||
public abstract interface class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue : com/android/tools/smali/dexlib2/iface/value/EncodedValue {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue$Companion;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/EncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEnumEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseEnumEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEnumEncodedValue$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/EnumEncodedValue;)V
|
||||
public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/reference/FieldReference;
|
||||
public final fun setValue (Lcom/android/tools/smali/dexlib2/iface/reference/FieldReference;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEnumEncodedValue$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/EnumEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEnumEncodedValue;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFieldEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseFieldEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFieldEncodedValue$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/FieldEncodedValue;)V
|
||||
public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/reference/FieldReference;
|
||||
public fun getValueType ()I
|
||||
public final fun setValue (Lcom/android/tools/smali/dexlib2/iface/reference/FieldReference;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFieldEncodedValue$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/FieldEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFieldEncodedValue;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFloatEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseFloatEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFloatEncodedValue$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/FloatEncodedValue;)V
|
||||
public fun getValue ()F
|
||||
public final fun setValue (F)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFloatEncodedValue$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/FloatEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFloatEncodedValue;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableIntEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseIntEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableIntEncodedValue$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/IntEncodedValue;)V
|
||||
public fun getValue ()I
|
||||
public final fun setValue (I)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableIntEncodedValue$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/IntEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableIntEncodedValue;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableLongEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseLongEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableLongEncodedValue$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/LongEncodedValue;)V
|
||||
public fun getValue ()J
|
||||
public final fun setValue (J)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableLongEncodedValue$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/LongEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableLongEncodedValue;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseMethodEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodEncodedValue$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/MethodEncodedValue;)V
|
||||
public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/reference/MethodReference;
|
||||
public final fun setValue (Lcom/android/tools/smali/dexlib2/iface/reference/MethodReference;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodEncodedValue$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/MethodEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodEncodedValue;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodHandleEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseMethodHandleEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodHandleEncodedValue$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/MethodHandleEncodedValue;)V
|
||||
public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/reference/MethodHandleReference;
|
||||
public final fun setValue (Lcom/android/tools/smali/dexlib2/iface/reference/MethodHandleReference;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodHandleEncodedValue$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/MethodHandleEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodHandleEncodedValue;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodTypeEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseMethodTypeEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodTypeEncodedValue$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/MethodTypeEncodedValue;)V
|
||||
public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/reference/MethodProtoReference;
|
||||
public final fun setValue (Lcom/android/tools/smali/dexlib2/iface/reference/MethodProtoReference;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodTypeEncodedValue$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/MethodTypeEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodTypeEncodedValue;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableNullEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseNullEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableNullEncodedValue$Companion;
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableNullEncodedValue$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/ByteEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableShortEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseShortEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableShortEncodedValue$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/ShortEncodedValue;)V
|
||||
public fun getValue ()S
|
||||
public final fun setValue (S)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableShortEncodedValue$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/ShortEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableShortEncodedValue;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableStringEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseStringEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableStringEncodedValue$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/StringEncodedValue;)V
|
||||
public fun getValue ()Ljava/lang/String;
|
||||
public final fun setValue (Ljava/lang/String;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableStringEncodedValue$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/ByteEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableTypeEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseTypeEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue {
|
||||
public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableTypeEncodedValue$Companion;
|
||||
public fun <init> (Lcom/android/tools/smali/dexlib2/iface/value/TypeEncodedValue;)V
|
||||
public fun getValue ()Ljava/lang/String;
|
||||
public final fun setValue (Ljava/lang/String;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableTypeEncodedValue$Companion {
|
||||
public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/TypeEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableTypeEncodedValue;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/smali/ExternalLabel {
|
||||
public fun <init> (Ljava/lang/String;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)V
|
||||
public final fun copy (Ljava/lang/String;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)Lapp/revanced/patcher/util/smali/ExternalLabel;
|
||||
public static synthetic fun copy$default (Lapp/revanced/patcher/util/smali/ExternalLabel;Ljava/lang/String;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;ILjava/lang/Object;)Lapp/revanced/patcher/util/smali/ExternalLabel;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/smali/InlineSmaliCompiler {
|
||||
public static final field Companion Lapp/revanced/patcher/util/smali/InlineSmaliCompiler$Companion;
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/smali/InlineSmaliCompiler$Companion {
|
||||
public final fun compile (Ljava/lang/String;Ljava/lang/String;IZ)Ljava/util/List;
|
||||
}
|
||||
|
||||
public final class app/revanced/patcher/util/smali/InlineSmaliCompilerKt {
|
||||
public static final fun toInstruction (Ljava/lang/String;Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;)Lcom/android/tools/smali/dexlib2/builder/BuilderInstruction;
|
||||
public static synthetic fun toInstruction$default (Ljava/lang/String;Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/Object;)Lcom/android/tools/smali/dexlib2/builder/BuilderInstruction;
|
||||
public static final fun toInstructions (Ljava/lang/String;Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;)Ljava/util/List;
|
||||
public static synthetic fun toInstructions$default (Ljava/lang/String;Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/Object;)Ljava/util/List;
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 11 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 11 KiB |
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 800 800" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"><g id="Logo"><g id="Ring"><circle id="Ring-Background" serif:id="Ring Background" cx="400" cy="400" r="400" style="fill:#1b1b1b;"/><path id="Ring1" serif:id="Ring" d="M400,0c220.766,0 400,179.234 400,400c-0,220.766 -179.234,400 -400,400c-220.766,-0 -400,-179.234 -400,-400c0,-220.766 179.234,-400 400,-400Zm-0,36c200.897,-0 364,163.103 364,364c0,200.897 -163.103,364 -364,364c-200.897,0 -364,-163.103 -364,-364c-0,-200.897 163.103,-364 364,-364Z" style="fill:url(#_Linear1);"/></g><g id="Shape"><path id="V-Shape" serif:id="V Shape" d="M538.74,269.872c1.481,-3.382 1.157,-7.283 -0.863,-10.373c-2.021,-3.091 -5.464,-4.954 -9.156,-4.954c-5.148,0 -10.435,0 -14.165,0c-3.1,0 -5.907,1.834 -7.153,4.672c-12.468,28.396 -78.273,178.273 -100.25,228.328c-1.246,2.838 -4.053,4.671 -7.154,4.671c-3.1,0 -5.907,-1.833 -7.153,-4.671c-21.977,-50.055 -87.782,-199.932 -100.25,-228.328c-1.246,-2.838 -4.053,-4.672 -7.153,-4.672c-3.73,0 -9.017,0 -14.164,0c-3.693,0 -7.135,1.863 -9.156,4.954c-2.02,3.09 -2.344,6.991 -0.863,10.373c23.557,53.766 101.872,232.519 117.871,269.034c1.743,3.979 5.674,6.549 10.018,6.549c6.293,-0 15.408,-0 21.701,-0c4.344,-0 8.275,-2.57 10.018,-6.549c15.999,-36.515 94.315,-215.268 117.872,-269.034Z" style="fill:#fff;"/><path id="Diamond" d="M408.119,395.312c-1.675,2.901 -4.77,4.688 -8.119,4.688c-3.349,-0 -6.444,-1.787 -8.119,-4.688c-16.997,-29.44 -56.156,-97.264 -73.153,-126.704c-1.675,-2.901 -1.675,-6.474 0,-9.375c1.675,-2.901 4.77,-4.688 8.119,-4.688c33.995,0 112.311,0 146.306,0c3.349,0 6.444,1.787 8.119,4.688c1.675,2.901 1.675,6.474 -0,9.375c-16.997,29.44 -56.156,97.264 -73.153,126.704Z" style="fill:url(#_Linear2);"/></g></g><defs><linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(4.89859e-14,800,-800,4.89859e-14,400.001,3.31681e-10)"><stop offset="0" style="stop-color:#f04e98;stop-opacity:1"/><stop offset="0.5" style="stop-color:#5f65d4;stop-opacity:1"/><stop offset="1" style="stop-color:#4e98f0;stop-opacity:1"/></linearGradient><linearGradient id="_Linear2" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.77155e-14,289.317,-282.535,1.73003e-14,400,254.545)"><stop offset="0" style="stop-color:#f04e98;stop-opacity:1"/><stop offset="0.5" style="stop-color:#5f65d4;stop-opacity:1"/><stop offset="1" style="stop-color:#4e98f0;stop-opacity:1"/></linearGradient></defs></svg>
|
||||
|
Before Width: | Height: | Size: 2.8 KiB |
@@ -1,95 +1,52 @@
|
||||
plugins {
|
||||
alias(libs.plugins.kotlin)
|
||||
alias(libs.plugins.binary.compatibility.validator)
|
||||
`maven-publish`
|
||||
signing
|
||||
kotlin("jvm") version "1.6.10"
|
||||
java
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
group = "app.revanced"
|
||||
|
||||
tasks {
|
||||
processResources {
|
||||
expand("projectVersion" to project.version)
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
testLogging {
|
||||
events("PASSED", "SKIPPED", "FAILED")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
maven { url = uri("https://jitpack.io") }
|
||||
google()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
implementation(libs.xpp3)
|
||||
implementation(libs.smali)
|
||||
implementation(libs.multidexlib2)
|
||||
implementation(libs.apktool.lib)
|
||||
implementation(libs.kotlin.reflect)
|
||||
implementation(kotlin("stdlib"))
|
||||
implementation("org.ow2.asm:asm:9.2")
|
||||
implementation("org.ow2.asm:asm-util:9.2")
|
||||
implementation("org.ow2.asm:asm-tree:9.2")
|
||||
implementation("org.ow2.asm:asm-commons:9.2")
|
||||
implementation("io.github.microutils:kotlin-logging:2.1.21")
|
||||
testImplementation("ch.qos.logback:logback-classic:1.2.11") // use your own logger!
|
||||
testImplementation(kotlin("test"))
|
||||
}
|
||||
|
||||
// TODO: Convert project to KMP.
|
||||
compileOnly(libs.android) {
|
||||
// Exclude, otherwise the org.w3c.dom API breaks.
|
||||
exclude(group = "xerces", module = "xmlParserAPIs")
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
testLogging {
|
||||
events("PASSED", "SKIPPED", "FAILED")
|
||||
}
|
||||
|
||||
testImplementation(libs.kotlin.test)
|
||||
}
|
||||
|
||||
java {
|
||||
withJavadocJar()
|
||||
withSourcesJar()
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(11)
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create<MavenPublication>("revanced-patcher-publication") {
|
||||
from(components["java"])
|
||||
|
||||
version = project.version.toString()
|
||||
|
||||
pom {
|
||||
name = "ReVanced Patcher"
|
||||
description = "Patcher used by ReVanced."
|
||||
url = "https://revanced.app"
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name = "GNU General Public License v3.0"
|
||||
url = "https://www.gnu.org/licenses/gpl-3.0.en.html"
|
||||
}
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
id = "ReVanced"
|
||||
name = "ReVanced"
|
||||
email = "contact@revanced.app"
|
||||
}
|
||||
}
|
||||
scm {
|
||||
connection = "scm:git:git://github.com/revanced/revanced-patcher.git"
|
||||
developerConnection = "scm:git:git@github.com:revanced/revanced-patcher.git"
|
||||
url = "https://github.com/revanced/revanced-patcher"
|
||||
}
|
||||
repositories {
|
||||
maven {
|
||||
name = "GitHubPackages"
|
||||
url = uri("https://maven.pkg.github.com/ReVancedTeam/revanced-patcher")
|
||||
credentials {
|
||||
username = System.getenv("GITHUB_ACTOR")
|
||||
password = System.getenv("GITHUB_TOKEN")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
signing {
|
||||
useGpgCmd()
|
||||
sign(publishing.publications["revanced-patcher-publication"])
|
||||
publications {
|
||||
register<MavenPublication>("gpr") {
|
||||
from(components["java"])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
org.gradle.parallel = true
|
||||
org.gradle.caching = true
|
||||
version = 19.3.0-dev.2
|
||||
kotlin.code.style = official
|
||||
version = 1.0.0-dev.7
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
[versions]
|
||||
android = "4.1.1.4"
|
||||
apktool-lib = "2.9.1"
|
||||
kotlin = "1.9.22"
|
||||
kotlinx-coroutines-core = "1.7.3"
|
||||
multidexlib2 = "3.0.3.r3"
|
||||
smali = "3.0.4"
|
||||
binary-compatibility-validator = "0.13.2"
|
||||
xpp3 = "1.1.4c"
|
||||
|
||||
[libraries]
|
||||
android = { module = "com.google.android:android", version.ref = "android" }
|
||||
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" }
|
||||
apktool-lib = { module = "app.revanced:apktool", version.ref = "apktool-lib" }
|
||||
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
|
||||
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines-core" }
|
||||
multidexlib2 = { module = "app.revanced:multidexlib2", version.ref = "multidexlib2" }
|
||||
smali = { module = "com.android.tools.smali:smali", version.ref = "smali" }
|
||||
xpp3 = { module = "xpp3:xpp3", version.ref = "xpp3" }
|
||||
|
||||
[plugins]
|
||||
binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" }
|
||||
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
5
gradle/wrapper/gradle-wrapper.properties
vendored
5
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
|
||||
distributionSha256Sum=3e1af3ae886920c3ac87f7a91f816c0c7c436f276a6eefdb3da152100fef72ae
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dist
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
281
gradlew
vendored
Executable file → Normal file
281
gradlew
vendored
Executable file → Normal file
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -17,98 +17,67 @@
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MSYS* | MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
@@ -118,9 +87,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
@@ -129,120 +98,88 @@ Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
||||
15
gradlew.bat
vendored
15
gradlew.bat
vendored
@@ -14,7 +14,7 @@
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@@ -25,8 +25,7 @@
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@@ -41,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
@@ -76,15 +75,13 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
6895
package-lock.json
generated
6895
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"@saithodev/semantic-release-backmerge": "^4.0.1",
|
||||
"@semantic-release/changelog": "^6.0.3",
|
||||
"@semantic-release/git": "^10.0.1",
|
||||
"gradle-semantic-release-plugin": "^1.9.1",
|
||||
"semantic-release": "^23.0.0"
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1 @@
|
||||
rootProject.name = "revanced-patcher"
|
||||
|
||||
buildCache {
|
||||
local {
|
||||
isEnabled = "CI" !in System.getenv()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package app.revanced.patcher
|
||||
|
||||
import java.io.File
|
||||
|
||||
@FunctionalInterface
|
||||
interface IntegrationsConsumer {
|
||||
fun acceptIntegrations(integrations: Set<File>)
|
||||
|
||||
@Deprecated("Use acceptIntegrations(Set<File>) instead.")
|
||||
fun acceptIntegrations(integrations: List<File>)
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package app.revanced.patcher
|
||||
|
||||
@RequiresOptIn(
|
||||
level = RequiresOptIn.Level.ERROR,
|
||||
message = "This is an internal API, don't rely on it.",
|
||||
)
|
||||
annotation class InternalApi
|
||||
@@ -1,16 +0,0 @@
|
||||
package app.revanced.patcher
|
||||
|
||||
import brut.androlib.apk.ApkInfo
|
||||
|
||||
/**
|
||||
* Metadata about a package.
|
||||
*
|
||||
* @param apkInfo The [ApkInfo] of the apk file.
|
||||
*/
|
||||
class PackageMetadata internal constructor(internal val apkInfo: ApkInfo) {
|
||||
lateinit var packageName: String
|
||||
internal set
|
||||
|
||||
lateinit var packageVersion: String
|
||||
internal set
|
||||
}
|
||||
@@ -1,136 +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
|
||||
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.
|
||||
*
|
||||
* @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.flatMap(getBinaryClassNames).asSequence().map {
|
||||
classLoader.loadClass(it)
|
||||
}.filter {
|
||||
Patch::class.java.isAssignableFrom(it)
|
||||
}.mapNotNull { patchClass ->
|
||||
patchClass.getInstance(logger, silent = true)
|
||||
}.filter {
|
||||
it.name != null
|
||||
}.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.
|
||||
*
|
||||
* @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)
|
||||
}
|
||||
},
|
||||
) {
|
||||
@Deprecated("This constructor is deprecated. Use the constructor with the second parameter instead.")
|
||||
constructor(vararg patchBundles: File) : this(*patchBundles, optimizedDexDirectory = null)
|
||||
}
|
||||
}
|
||||
@@ -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>>
|
||||
@@ -1,270 +1,70 @@
|
||||
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.fingerprint.MethodFingerprint.Companion.resolveUsingLookupMap
|
||||
import app.revanced.patcher.patch.*
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import java.io.Closeable
|
||||
import java.io.File
|
||||
import java.util.function.Supplier
|
||||
import java.util.logging.Logger
|
||||
import app.revanced.patcher.cache.Cache
|
||||
import app.revanced.patcher.patch.Patch
|
||||
import app.revanced.patcher.resolver.MethodResolver
|
||||
import app.revanced.patcher.signature.Signature
|
||||
import app.revanced.patcher.util.Io
|
||||
import org.objectweb.asm.tree.ClassNode
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
/**
|
||||
* A Patcher.
|
||||
* The Patcher class.
|
||||
* ***It is of utmost importance that the input and output streams are NEVER closed.***
|
||||
*
|
||||
* @param config The configuration to use for the patcher.
|
||||
* @param input the input stream to read from, must be a JAR
|
||||
* @param output the output stream to write to
|
||||
* @param signatures the signatures
|
||||
* @sample app.revanced.patcher.PatcherTest
|
||||
* @throws IOException if one of the streams are closed
|
||||
*/
|
||||
class Patcher(
|
||||
private val config: PatcherConfig,
|
||||
) : PatchExecutorFunction, PatchesConsumer, IntegrationsConsumer, Supplier<PatcherResult>, Closeable {
|
||||
private val logger = Logger.getLogger(Patcher::class.java.name)
|
||||
private val input: InputStream,
|
||||
private val output: OutputStream,
|
||||
signatures: Array<Signature>,
|
||||
) {
|
||||
var cache: Cache
|
||||
|
||||
/**
|
||||
* A context for the patcher containing the current state of the 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,
|
||||
),
|
||||
)
|
||||
private var io: Io
|
||||
private val patches = mutableListOf<Patch>()
|
||||
|
||||
init {
|
||||
context.resourceContext.decodeResources(ResourceContext.ResourceMode.NONE)
|
||||
val classes = mutableListOf<ClassNode>()
|
||||
io = Io(input, output, classes)
|
||||
io.readFromJar()
|
||||
cache = Cache(classes, MethodResolver(classes, signatures).resolve())
|
||||
}
|
||||
|
||||
/**
|
||||
* Add [Patch]es to ReVanced [Patcher].
|
||||
* Saves the output to the output stream.
|
||||
* Calling this method will close the input and output streams,
|
||||
* meaning this method should NEVER be called after.
|
||||
*
|
||||
* @param patches The [Patch]es to add.
|
||||
* @throws IOException if one of the streams are closed
|
||||
*/
|
||||
@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
|
||||
|
||||
val dependency = this.java.getInstance(logger)!!
|
||||
context.allPatches[this] = dependency
|
||||
|
||||
dependency.dependencies?.forEach { it.putDependenciesRecursively() }
|
||||
}
|
||||
|
||||
// Add all patches and their dependencies to the context.
|
||||
patches.forEach { patch ->
|
||||
context.executablePatches.putIfAbsent(patch::class, patch) ?: run {
|
||||
context.allPatches[patch::class] = patch
|
||||
|
||||
patch.dependencies?.forEach { it.putDependenciesRecursively() }
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Detect circular dependencies.
|
||||
|
||||
/**
|
||||
* Returns true if at least one patch or its dependencies matches the given predicate.
|
||||
*
|
||||
* @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.
|
||||
|
||||
config.resourceMode = if (patches.any { patch -> patch.anyRecursively { it is ResourcePatch } }) {
|
||||
ResourceContext.ResourceMode.FULL
|
||||
} else if (patches.any { patch -> patch.anyRecursively { it is RawResourcePatch } }) {
|
||||
ResourceContext.ResourceMode.RAW_ONLY
|
||||
} else {
|
||||
ResourceContext.ResourceMode.NONE
|
||||
}
|
||||
|
||||
// Determine, if merging integrations is required.
|
||||
for (patch in patches)
|
||||
if (patch.anyRecursively { it.requiresIntegrations }) {
|
||||
context.bytecodeContext.integrations.merge = true
|
||||
break
|
||||
}
|
||||
}
|
||||
fun save() {
|
||||
io.saveAsJar()
|
||||
}
|
||||
|
||||
/**
|
||||
* Add integrations to the [Patcher].
|
||||
*
|
||||
* @param integrations The integrations to add. Must be a DEX file or container of DEX files.
|
||||
*/
|
||||
override fun acceptIntegrations(integrations: Set<File>) {
|
||||
context.bytecodeContext.integrations.addAll(integrations)
|
||||
fun addPatches(vararg patches: Patch) {
|
||||
this.patches.addAll(patches)
|
||||
}
|
||||
|
||||
@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].
|
||||
*
|
||||
* @param returnOnError If true, ReVanced [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) =
|
||||
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<*>,
|
||||
executedPatches: LinkedHashMap<Patch<*>, PatchResult>,
|
||||
): PatchResult {
|
||||
val patchName = patch.toString()
|
||||
|
||||
executedPatches[patch]?.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"))
|
||||
fun applyPatches(stopOnError: Boolean = false): Map<String, Result<Nothing?>> {
|
||||
return buildMap {
|
||||
for (patch in patches) {
|
||||
val result: Result<Nothing?> = try {
|
||||
val pr = patch.execute(cache)
|
||||
if (pr.isSuccess()) continue
|
||||
Result.failure(Exception(pr.error()?.errorMessage() ?: "Unknown error"))
|
||||
} catch (e: Exception) {
|
||||
Result.failure(e)
|
||||
}
|
||||
|
||||
// Recursively execute all dependency patches.
|
||||
patch.dependencies?.forEach { dependencyClass ->
|
||||
val dependency = context.allPatches[dependencyClass]!!
|
||||
val result = executePatch(dependency, executedPatches)
|
||||
|
||||
result.exception?.let {
|
||||
return PatchResult(
|
||||
patch,
|
||||
PatchException(
|
||||
"'$patchName' depends on '${dependency.name ?: dependency}' " +
|
||||
"that raised an exception:\n${it.stackTraceToString()}",
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return try {
|
||||
// TODO: Implement this in a more polymorphic way.
|
||||
when (patch) {
|
||||
is BytecodePatch -> {
|
||||
patch.fingerprints.resolveUsingLookupMap(context.bytecodeContext)
|
||||
patch.execute(context.bytecodeContext)
|
||||
}
|
||||
is RawResourcePatch -> {
|
||||
patch.execute(context.resourceContext)
|
||||
}
|
||||
is ResourcePatch -> {
|
||||
patch.execute(context.resourceContext)
|
||||
}
|
||||
}
|
||||
|
||||
PatchResult(patch)
|
||||
} catch (exception: PatchException) {
|
||||
PatchResult(patch, exception)
|
||||
} catch (exception: Exception) {
|
||||
PatchResult(patch, PatchException(exception))
|
||||
}.also { executedPatches[patch] = it }
|
||||
this[patch.patchName] = result
|
||||
if (stopOnError && result.isFailure) break
|
||||
}
|
||||
|
||||
if (context.bytecodeContext.integrations.merge) context.bytecodeContext.integrations.flush()
|
||||
|
||||
LookupMap.initializeLookupMaps(context.bytecodeContext)
|
||||
|
||||
// Prevent from decoding the app manifest twice if it is not needed.
|
||||
if (config.resourceMode != ResourceContext.ResourceMode.NONE) {
|
||||
context.resourceContext.decodeResources(config.resourceMode)
|
||||
}
|
||||
|
||||
logger.info("Executing patches")
|
||||
|
||||
val executedPatches = LinkedHashMap<Patch<*>, PatchResult>() // Key is name.
|
||||
|
||||
context.executablePatches.values.sortedBy { it.name }.forEach { patch ->
|
||||
val patchResult = executePatch(patch, executedPatches)
|
||||
|
||||
// If the patch failed, emit the result, even if it is closeable.
|
||||
// Results of executed patches that are closeable will be emitted later.
|
||||
patchResult.exception?.let {
|
||||
// Propagate exception to caller instead of wrapping it in a new exception.
|
||||
emit(patchResult)
|
||||
|
||||
if (returnOnError) return@flow
|
||||
} ?: run {
|
||||
if (patch is Closeable) return@run
|
||||
|
||||
emit(patchResult)
|
||||
}
|
||||
}
|
||||
|
||||
executedPatches.values
|
||||
.filter { it.exception == null }
|
||||
.filter { it.patch is Closeable }.asReversed().forEach { executedPatch ->
|
||||
val patch = executedPatch.patch
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() = LookupMap.clearLookupMaps()
|
||||
|
||||
/**
|
||||
* Compile and save the patched APK file.
|
||||
*
|
||||
* @return The [PatcherResult] containing the patched input files.
|
||||
*/
|
||||
@OptIn(InternalApi::class)
|
||||
override fun get() =
|
||||
PatcherResult(
|
||||
context.bytecodeContext.get(),
|
||||
context.resourceContext.get(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
package app.revanced.patcher
|
||||
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import brut.androlib.Config
|
||||
import java.io.File
|
||||
import java.util.logging.Logger
|
||||
|
||||
/**
|
||||
* The configuration for the patcher.
|
||||
*
|
||||
* @param apkFile The apk file to patch.
|
||||
* @param temporaryFilesPath A path to a folder to store temporary files in.
|
||||
* @param aaptBinaryPath A path to a custom aapt binary.
|
||||
* @param frameworkFileDirectory A path to the directory to cache the framework file in.
|
||||
* @param multithreadingDexFileWriter Whether to use multiple threads for writing dex files.
|
||||
* This has impact on memory usage and performance.
|
||||
*/
|
||||
class PatcherConfig(
|
||||
internal val apkFile: File,
|
||||
private val temporaryFilesPath: File = File("revanced-temporary-files"),
|
||||
aaptBinaryPath: String? = null,
|
||||
frameworkFileDirectory: String? = null,
|
||||
internal val multithreadingDexFileWriter: Boolean = false,
|
||||
) {
|
||||
private val logger = Logger.getLogger(PatcherConfig::class.java.name)
|
||||
|
||||
/**
|
||||
* The mode to use for resource decoding and compiling.
|
||||
*
|
||||
* @see ResourceContext.ResourceMode
|
||||
*/
|
||||
internal var resourceMode = ResourceContext.ResourceMode.NONE
|
||||
|
||||
/**
|
||||
* The configuration for decoding and compiling resources.
|
||||
*/
|
||||
internal val resourceConfig =
|
||||
Config.getDefaultConfig().apply {
|
||||
useAapt2 = true
|
||||
aaptPath = aaptBinaryPath ?: ""
|
||||
frameworkDirectory = frameworkFileDirectory
|
||||
}
|
||||
|
||||
/**
|
||||
* The path to the temporary apk files directory.
|
||||
*/
|
||||
internal val apkFiles = temporaryFilesPath.resolve("apk")
|
||||
|
||||
/**
|
||||
* The path to the temporary patched files directory.
|
||||
*/
|
||||
internal val patchedFiles = temporaryFilesPath.resolve("patched")
|
||||
|
||||
/**
|
||||
* Initialize the temporary files' directories.
|
||||
* This will delete the existing temporary files directory if it exists.
|
||||
*/
|
||||
internal fun initializeTemporaryFilesDirectories() {
|
||||
temporaryFilesPath.apply {
|
||||
if (exists()) {
|
||||
logger.info("Deleting existing temporary files directory")
|
||||
|
||||
if (!deleteRecursively()) {
|
||||
logger.severe("Failed to delete existing temporary files directory")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
apkFiles.mkdirs()
|
||||
patchedFiles.mkdirs()
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package app.revanced.patcher
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.Patch
|
||||
import brut.androlib.apk.ApkInfo
|
||||
import brut.directory.ExtFile
|
||||
|
||||
/**
|
||||
* A context for the patcher containing the current state of the patcher.
|
||||
*
|
||||
* @param config The configuration for the patcher.
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
class PatcherContext internal constructor(config: PatcherConfig) {
|
||||
/**
|
||||
* [PackageMetadata] of the supplied [PatcherConfig.apkFile].
|
||||
*/
|
||||
val packageMetadata = PackageMetadata(ApkInfo(ExtFile(config.apkFile)))
|
||||
|
||||
/**
|
||||
* The map of [Patch]es associated by their [PatchClass].
|
||||
*/
|
||||
internal val executablePatches = mutableMapOf<PatchClass, Patch<*>>()
|
||||
|
||||
/**
|
||||
* The map of all [Patch]es and their dependencies associated by their [PatchClass].
|
||||
*/
|
||||
internal val allPatches = mutableMapOf<PatchClass, Patch<*>>()
|
||||
|
||||
/**
|
||||
* A context for the patcher containing the current state of the resources.
|
||||
*/
|
||||
internal val resourceContext = ResourceContext(packageMetadata, config)
|
||||
|
||||
/**
|
||||
* A context for the patcher containing the current state of the bytecode.
|
||||
*/
|
||||
internal val bytecodeContext = BytecodeContext(config)
|
||||
}
|
||||
@@ -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",
|
||||
)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
package app.revanced.patcher
|
||||
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import kotlin.jvm.internal.Intrinsics
|
||||
|
||||
/**
|
||||
* The result of a patcher.
|
||||
*
|
||||
* @param dexFiles The patched dex files.
|
||||
* @param resources The patched resources.
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
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
|
||||
}
|
||||
|
||||
@Deprecated("This method is not used anymore")
|
||||
fun getDexFiles() = component1()
|
||||
|
||||
@Deprecated("This method is not used anymore")
|
||||
fun getResourceFile() = component2()
|
||||
|
||||
@Deprecated("This method is not used anymore")
|
||||
fun getDoNotCompress() = component3()
|
||||
|
||||
/**
|
||||
* A dex file.
|
||||
*
|
||||
* @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)
|
||||
|
||||
/**
|
||||
* The resources of a patched apk.
|
||||
*
|
||||
* @param resourcesApk The compiled resources.apk file.
|
||||
* @param otherResources The directory containing other resources files.
|
||||
* @param doNotCompress List of files that should not be compressed.
|
||||
* @param deleteResources List of predicates about resources that should be deleted.
|
||||
*/
|
||||
class PatchedResources internal constructor(
|
||||
val resourcesApk: File?,
|
||||
val otherResources: File?,
|
||||
val doNotCompress: Set<String>,
|
||||
val deleteResources: Set<(String) -> Boolean>,
|
||||
)
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
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)
|
||||
}
|
||||
16
src/main/kotlin/app/revanced/patcher/cache/Cache.kt
vendored
Normal file
16
src/main/kotlin/app/revanced/patcher/cache/Cache.kt
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
package app.revanced.patcher.cache
|
||||
|
||||
import org.objectweb.asm.tree.ClassNode
|
||||
|
||||
class Cache(
|
||||
val classes: List<ClassNode>,
|
||||
val methods: MethodMap
|
||||
)
|
||||
|
||||
class MethodMap : LinkedHashMap<String, PatchData>() {
|
||||
override fun get(key: String): PatchData {
|
||||
return super.get(key) ?: throw MethodNotFoundException("Method $key was not found in the method cache")
|
||||
}
|
||||
}
|
||||
|
||||
class MethodNotFoundException(s: String) : Exception(s)
|
||||
22
src/main/kotlin/app/revanced/patcher/cache/PatchData.kt
vendored
Normal file
22
src/main/kotlin/app/revanced/patcher/cache/PatchData.kt
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
package app.revanced.patcher.cache
|
||||
|
||||
import app.revanced.patcher.resolver.MethodResolver
|
||||
import app.revanced.patcher.signature.Signature
|
||||
import org.objectweb.asm.tree.ClassNode
|
||||
import org.objectweb.asm.tree.MethodNode
|
||||
|
||||
data class PatchData(
|
||||
val declaringClass: ClassNode,
|
||||
val method: MethodNode,
|
||||
val scanData: PatternScanData
|
||||
) {
|
||||
@Suppress("Unused") // TODO(Sculas): remove this when we have coverage for this method.
|
||||
fun findParentMethod(signature: Signature): PatchData? {
|
||||
return MethodResolver.resolveMethod(declaringClass, signature)
|
||||
}
|
||||
}
|
||||
|
||||
data class PatternScanData(
|
||||
val startIndex: Int,
|
||||
val endIndex: Int
|
||||
)
|
||||
@@ -1,184 +0,0 @@
|
||||
package app.revanced.patcher.data
|
||||
|
||||
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
|
||||
import app.revanced.patcher.util.proxy.ClassProxy
|
||||
import com.android.tools.smali.dexlib2.Opcodes
|
||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||
import com.android.tools.smali.dexlib2.iface.DexFile
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import lanchon.multidexlib2.BasicDexFileNamer
|
||||
import lanchon.multidexlib2.DexIO
|
||||
import lanchon.multidexlib2.MultiDexIO
|
||||
import java.io.File
|
||||
import java.io.FileFilter
|
||||
import java.io.Flushable
|
||||
import java.util.logging.Logger
|
||||
|
||||
/**
|
||||
* A context for the patcher 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)
|
||||
|
||||
/**
|
||||
* [Opcodes] of the supplied [PatcherConfig.apkFile].
|
||||
*/
|
||||
internal lateinit var opcodes: Opcodes
|
||||
|
||||
/**
|
||||
* The list of classes.
|
||||
*/
|
||||
val classes by lazy {
|
||||
ProxyClassList(
|
||||
MultiDexIO.readDexFile(
|
||||
true,
|
||||
config.apkFile,
|
||||
BasicDexFileNamer(),
|
||||
null,
|
||||
null,
|
||||
).also { opcodes = it.opcodes }.classes.toMutableSet(),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* The [Integrations] of this [PatcherContext].
|
||||
*/
|
||||
internal val integrations = Integrations()
|
||||
|
||||
/**
|
||||
* Find a class by a given class name.
|
||||
*
|
||||
* @param className The name of the class.
|
||||
* @return A proxy for the first class that matches the class name.
|
||||
*/
|
||||
fun findClass(className: String) = findClass { it.type.contains(className) }
|
||||
|
||||
/**
|
||||
* Find a class by a given predicate.
|
||||
*
|
||||
* @param predicate A predicate to match the class.
|
||||
* @return A proxy for the first class that matches the predicate.
|
||||
*/
|
||||
fun findClass(predicate: (ClassDef) -> Boolean) =
|
||||
// if we already proxied the class matching the predicate...
|
||||
classes.proxies.firstOrNull { predicate(it.immutableClass) }
|
||||
?: // else resolve the class to a proxy and return it, if the predicate is matching a class
|
||||
classes.find(predicate)?.let { proxy(it) }
|
||||
|
||||
/**
|
||||
* Proxy a class.
|
||||
* This will allow the class to be modified.
|
||||
*
|
||||
* @param classDef The class to proxy.
|
||||
* @return A proxy for the class.
|
||||
*/
|
||||
fun proxy(classDef: ClassDef) =
|
||||
this.classes.proxies.find { it.immutableClass.type == classDef.type } ?: let {
|
||||
ClassProxy(classDef).also { this.classes.add(it) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a [MethodWalker] instance for the current [BytecodeContext].
|
||||
*
|
||||
* @param startMethod The method to start at.
|
||||
* @return A [MethodWalker] instance.
|
||||
*/
|
||||
fun toMethodWalker(startMethod: Method) = MethodWalker(this, startMethod)
|
||||
|
||||
/**
|
||||
* Compile bytecode from the [BytecodeContext].
|
||||
*
|
||||
* @return The compiled bytecode.
|
||||
*/
|
||||
@InternalApi
|
||||
override fun get(): Set<PatcherResult.PatchedDexFile> {
|
||||
logger.info("Compiling patched dex files")
|
||||
|
||||
val patchedDexFileResults =
|
||||
config.patchedFiles.resolve("dex").also {
|
||||
it.deleteRecursively() // Make sure the directory is empty.
|
||||
it.mkdirs()
|
||||
}.apply {
|
||||
MultiDexIO.writeDexFile(
|
||||
true,
|
||||
if (config.multithreadingDexFileWriter) -1 else 1,
|
||||
this,
|
||||
BasicDexFileNamer(),
|
||||
object : DexFile {
|
||||
override fun getClasses() = this@BytecodeContext.classes.also(ProxyClassList::replaceClasses)
|
||||
|
||||
override fun getOpcodes() = this@BytecodeContext.opcodes
|
||||
},
|
||||
DexIO.DEFAULT_MAX_DEX_POOL_SIZE,
|
||||
) { _, entryName, _ -> logger.info("Compiled $entryName") }
|
||||
}.listFiles(FileFilter { it.isFile })!!.map {
|
||||
PatcherResult.PatchedDexFile(it.name, it.inputStream())
|
||||
}.toSet()
|
||||
|
||||
System.gc()
|
||||
|
||||
return patchedDexFileResults
|
||||
}
|
||||
|
||||
/**
|
||||
* The integrations of a [PatcherContext].
|
||||
*/
|
||||
internal inner class Integrations : MutableList<File> by mutableListOf(), Flushable {
|
||||
/**
|
||||
* Whether to merge integrations.
|
||||
* Set to true, if the field requiresIntegrations of any supplied [Patch] is true.
|
||||
*/
|
||||
var merge = false
|
||||
|
||||
/**
|
||||
* Merge integrations into the [BytecodeContext] and flush all [Integrations].
|
||||
*/
|
||||
override fun flush() {
|
||||
if (!merge) return
|
||||
|
||||
logger.info("Merging integrations")
|
||||
|
||||
val classMap = classes.associateBy { it.type }
|
||||
|
||||
this@Integrations.forEach { integrations ->
|
||||
MultiDexIO.readDexFile(
|
||||
true,
|
||||
integrations,
|
||||
BasicDexFileNamer(),
|
||||
null,
|
||||
null,
|
||||
).classes.forEach classDef@{ classDef ->
|
||||
val existingClass =
|
||||
classMap[classDef.type] ?: run {
|
||||
logger.fine("Adding $classDef")
|
||||
classes.add(classDef)
|
||||
return@classDef
|
||||
}
|
||||
|
||||
logger.fine("$classDef exists. Adding missing methods and fields.")
|
||||
|
||||
existingClass.merge(classDef, this@BytecodeContext).let { mergedClass ->
|
||||
// If the class was merged, replace the original class with the merged class.
|
||||
if (mergedClass === existingClass) return@let
|
||||
classes.apply {
|
||||
remove(existingClass)
|
||||
add(mergedClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -1,256 +0,0 @@
|
||||
package app.revanced.patcher.data
|
||||
|
||||
import app.revanced.patcher.InternalApi
|
||||
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
|
||||
import brut.androlib.res.Framework
|
||||
import brut.androlib.res.ResourcesDecoder
|
||||
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
|
||||
import java.util.logging.Logger
|
||||
|
||||
/**
|
||||
* A context for the patcher containing the current state of the resources.
|
||||
*
|
||||
* @param packageMetadata The [PackageMetadata] of the apk file.
|
||||
* @param config The [PatcherConfig] used to create this context.
|
||||
*/
|
||||
class ResourceContext internal constructor(
|
||||
private val packageMetadata: PackageMetadata,
|
||||
private val config: PatcherConfig,
|
||||
) : Context<PatcherResult.PatchedResources?>, Iterable<File> {
|
||||
private val logger = Logger.getLogger(ResourceContext::class.java.name)
|
||||
|
||||
/**
|
||||
* Read and write documents in the [PatcherConfig.apkFiles].
|
||||
*/
|
||||
val document = DocumentOperatable()
|
||||
|
||||
@Deprecated("Use document instead.")
|
||||
val xmlEditor = XmlFileHolder()
|
||||
|
||||
/**
|
||||
* Predicate to delete resources from [PatcherConfig.apkFiles].
|
||||
*/
|
||||
private val deleteResources = mutableSetOf<(String) -> Boolean>()
|
||||
|
||||
/**
|
||||
* Decode resources of [PatcherConfig.apkFile].
|
||||
*
|
||||
* @param mode The [ResourceMode] to use.
|
||||
*/
|
||||
internal fun decodeResources(mode: ResourceMode) =
|
||||
with(packageMetadata.apkInfo) {
|
||||
config.initializeTemporaryFilesDirectories()
|
||||
|
||||
// Needed to decode resources.
|
||||
val resourcesDecoder = ResourcesDecoder(config.resourceConfig, this)
|
||||
|
||||
if (mode == ResourceMode.FULL) {
|
||||
logger.info("Decoding resources")
|
||||
|
||||
resourcesDecoder.decodeResources(config.apkFiles)
|
||||
resourcesDecoder.decodeManifest(config.apkFiles)
|
||||
|
||||
// Needed to record uncompressed files.
|
||||
val apkDecoder = ApkDecoder(config.resourceConfig, this)
|
||||
apkDecoder.recordUncompressedFiles(resourcesDecoder.resFileMapping)
|
||||
|
||||
usesFramework =
|
||||
UsesFramework().apply {
|
||||
ids = resourcesDecoder.resTable.listFramePackages().map { it.id }
|
||||
}
|
||||
} else {
|
||||
logger.info("Decoding app manifest")
|
||||
|
||||
// Decode manually instead of using resourceDecoder.decodeManifest
|
||||
// because it does not support decoding to an OutputStream.
|
||||
XmlPullStreamDecoder(
|
||||
AndroidManifestResourceParser(resourcesDecoder.resTable),
|
||||
resourcesDecoder.resXmlSerializer,
|
||||
).decodeManifest(
|
||||
apkFile.directory.getFileInput("AndroidManifest.xml"),
|
||||
// Older Android versions do not support OutputStream.nullOutputStream()
|
||||
object : OutputStream() {
|
||||
override fun write(b: Int) { // Do nothing.
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
// Get the package name and version from the manifest using the XmlPullStreamDecoder.
|
||||
// XmlPullStreamDecoder.decodeManifest() sets metadata.apkInfo.
|
||||
packageMetadata.let { metadata ->
|
||||
metadata.packageName = resourcesDecoder.resTable.packageRenamed
|
||||
versionInfo.let {
|
||||
metadata.packageVersion = it.versionName ?: it.versionCode
|
||||
}
|
||||
|
||||
/*
|
||||
The ResTable if flagged as sparse if the main package is not loaded, which is the case here,
|
||||
because ResourcesDecoder.decodeResources loads the main package
|
||||
and not XmlPullStreamDecoder.decodeManifest.
|
||||
See ARSCDecoder.readTableType for more info.
|
||||
|
||||
Set this to false again to prevent the ResTable from being flagged as sparse falsely.
|
||||
*/
|
||||
metadata.apkInfo.sparseResources = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile resources in [PatcherConfig.apkFiles].
|
||||
*
|
||||
* @return The [PatcherResult.PatchedResources].
|
||||
*/
|
||||
@InternalApi
|
||||
override fun get(): PatcherResult.PatchedResources? {
|
||||
if (config.resourceMode == ResourceMode.NONE) return null
|
||||
|
||||
logger.info("Compiling modified resources")
|
||||
|
||||
val resources = config.patchedFiles.resolve("resources").also { it.mkdirs() }
|
||||
|
||||
val resourcesApkFile =
|
||||
if (config.resourceMode == ResourceMode.FULL) {
|
||||
resources.resolve("resources.apk").apply {
|
||||
// Compile the resources.apk file.
|
||||
AaptInvoker(
|
||||
config.resourceConfig,
|
||||
packageMetadata.apkInfo,
|
||||
).invokeAapt(
|
||||
resources.resolve("resources.apk"),
|
||||
config.apkFiles.resolve("AndroidManifest.xml").also {
|
||||
ResXmlPatcher.fixingPublicAttrsInProviderAttributes(it)
|
||||
},
|
||||
config.apkFiles.resolve("res"),
|
||||
null,
|
||||
null,
|
||||
packageMetadata.apkInfo.usesFramework.let { usesFramework ->
|
||||
usesFramework.ids.map { id ->
|
||||
Framework(config.resourceConfig).getFrameworkApk(id, usesFramework.tag)
|
||||
}.toTypedArray()
|
||||
},
|
||||
)
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
val otherFiles =
|
||||
config.apkFiles.listFiles()!!.filter {
|
||||
// Excluded because present in resources.other.
|
||||
// TODO: We are reusing config.apkFiles as a temporarily directory for extracting resources.
|
||||
// This is not ideal as it could conflict with files such as the ones that we filter here.
|
||||
// The problem is that ResourceContext#get returns a File relative to config.apkFiles,
|
||||
// and we need to extract files to that directory.
|
||||
// A solution would be to use config.apkFiles as the working directory for the patching process.
|
||||
// Once all patches have been executed, we can move the decoded resources to a new directory.
|
||||
// The filters wouldn't be needed anymore.
|
||||
// For now, we assume that the files we filter here are not needed for the patching process.
|
||||
it.name != "AndroidManifest.xml" &&
|
||||
it.name != "res" &&
|
||||
// Generated by Androlib.
|
||||
it.name != "build"
|
||||
}
|
||||
|
||||
val otherResourceFiles =
|
||||
if (otherFiles.isNotEmpty()) {
|
||||
// Move the other resources files.
|
||||
resources.resolve("other").also { it.mkdirs() }.apply {
|
||||
otherFiles.forEach { file ->
|
||||
Files.move(file.toPath(), resolve(file.name).toPath())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
return PatcherResult.PatchedResources(
|
||||
resourcesApkFile,
|
||||
otherResourceFiles,
|
||||
packageMetadata.apkInfo.doNotCompress?.toSet() ?: emptySet(),
|
||||
deleteResources,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a file from [PatcherConfig.apkFiles].
|
||||
*
|
||||
* @param path The path of the file.
|
||||
* @param copy Whether to copy the file from [PatcherConfig.apkFile] if it does not exist yet in [PatcherConfig.apkFiles].
|
||||
*/
|
||||
operator fun get(
|
||||
path: String,
|
||||
copy: Boolean = true,
|
||||
) = config.apkFiles.resolve(path).apply {
|
||||
if (copy && !exists()) {
|
||||
with(ExtFile(config.apkFile).directory) {
|
||||
if (containsFile(path) || containsDir(path)) {
|
||||
copyToDir(config.apkFiles, path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stage a file to be deleted from [PatcherConfig.apkFile].
|
||||
*
|
||||
* @param shouldDelete The predicate to stage the file for deletion given its name.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
internal enum class ResourceMode {
|
||||
/**
|
||||
* Decode and compile all resources.
|
||||
*/
|
||||
FULL,
|
||||
|
||||
/**
|
||||
* Only extract resources from the APK.
|
||||
* The AndroidManifest.xml and resources inside /res are not decoded or compiled.
|
||||
*/
|
||||
RAW_ONLY,
|
||||
|
||||
/**
|
||||
* Do not decode or compile any resources.
|
||||
*/
|
||||
NONE,
|
||||
}
|
||||
|
||||
inner class DocumentOperatable {
|
||||
operator fun get(inputStream: InputStream) = Document(inputStream)
|
||||
|
||||
operator fun get(path: String) = Document(this@ResourceContext[path])
|
||||
}
|
||||
|
||||
@Deprecated("Use DocumentOperatable instead.")
|
||||
inner class XmlFileHolder {
|
||||
operator fun get(inputStream: InputStream) = DomFileEditor(inputStream)
|
||||
|
||||
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,33 +0,0 @@
|
||||
package app.revanced.patcher.extensions
|
||||
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
/**
|
||||
* Create a label for the instruction at given index.
|
||||
*
|
||||
* @param index The index to create the label for the instruction at.
|
||||
* @return The label.
|
||||
*/
|
||||
fun MutableMethod.newLabel(index: Int) = implementation!!.newLabelForIndex(index)
|
||||
|
||||
/**
|
||||
* Perform a bitwise OR operation between an [AccessFlags] and an [Int].
|
||||
*
|
||||
* @param other The [Int] to perform the operation with.
|
||||
*/
|
||||
infix fun Int.or(other: AccessFlags) = this or other.value
|
||||
|
||||
/**
|
||||
* Perform a bitwise OR operation between two [AccessFlags].
|
||||
*
|
||||
* @param other The other [AccessFlags] to perform the operation with.
|
||||
*/
|
||||
infix fun AccessFlags.or(other: AccessFlags) = value or other.value
|
||||
|
||||
/**
|
||||
* Perform a bitwise OR operation between an [Int] and an [AccessFlags].
|
||||
*
|
||||
* @param other The [AccessFlags] to perform the operation with.
|
||||
*/
|
||||
infix fun AccessFlags.or(other: Int) = value or other
|
||||
@@ -1,351 +0,0 @@
|
||||
package app.revanced.patcher.extensions
|
||||
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patcher.util.smali.toInstruction
|
||||
import app.revanced.patcher.util.smali.toInstructions
|
||||
import com.android.tools.smali.dexlib2.builder.BuilderInstruction
|
||||
import com.android.tools.smali.dexlib2.builder.BuilderOffsetInstruction
|
||||
import com.android.tools.smali.dexlib2.builder.Label
|
||||
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
|
||||
import com.android.tools.smali.dexlib2.builder.instruction.*
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||
|
||||
object InstructionExtensions {
|
||||
/**
|
||||
* Add instructions to a method at the given index.
|
||||
*
|
||||
* @param index The index to add the instructions at.
|
||||
* @param instructions The instructions to add.
|
||||
*/
|
||||
fun MutableMethodImplementation.addInstructions(
|
||||
index: Int,
|
||||
instructions: List<BuilderInstruction>,
|
||||
) = instructions.asReversed().forEach { addInstruction(index, it) }
|
||||
|
||||
/**
|
||||
* Add instructions to a method.
|
||||
* The instructions will be added at the end of the method.
|
||||
*
|
||||
* @param instructions The instructions to add.
|
||||
*/
|
||||
fun MutableMethodImplementation.addInstructions(instructions: List<BuilderInstruction>) =
|
||||
instructions.forEach { this.addInstruction(it) }
|
||||
|
||||
/**
|
||||
* Remove instructions from a method at the given index.
|
||||
*
|
||||
* @param index The index to remove the instructions at.
|
||||
* @param count The amount of instructions to remove.
|
||||
*/
|
||||
fun MutableMethodImplementation.removeInstructions(
|
||||
index: Int,
|
||||
count: Int,
|
||||
) = repeat(count) {
|
||||
removeInstruction(index)
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the first instructions from a method.
|
||||
*
|
||||
* @param count The amount of instructions to remove.
|
||||
*/
|
||||
fun MutableMethodImplementation.removeInstructions(count: Int) = removeInstructions(0, count)
|
||||
|
||||
/**
|
||||
* Replace instructions at the given index with the given instructions.
|
||||
* The amount of instructions to replace is the amount of instructions in the given list.
|
||||
*
|
||||
* @param index The index to replace the instructions at.
|
||||
* @param instructions The instructions to replace the instructions with.
|
||||
*/
|
||||
fun MutableMethodImplementation.replaceInstructions(
|
||||
index: Int,
|
||||
instructions: List<BuilderInstruction>,
|
||||
) {
|
||||
// Remove the instructions at the given index.
|
||||
removeInstructions(index, instructions.size)
|
||||
|
||||
// Add the instructions at the given index.
|
||||
addInstructions(index, instructions)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an instruction to a method at the given index.
|
||||
*
|
||||
* @param index The index to add the instruction at.
|
||||
* @param instruction The instruction to add.
|
||||
*/
|
||||
fun MutableMethod.addInstruction(
|
||||
index: Int,
|
||||
instruction: BuilderInstruction,
|
||||
) = implementation!!.addInstruction(index, instruction)
|
||||
|
||||
/**
|
||||
* Add an instruction to a method.
|
||||
*
|
||||
* @param instruction The instructions to add.
|
||||
*/
|
||||
fun MutableMethod.addInstruction(instruction: BuilderInstruction) = implementation!!.addInstruction(instruction)
|
||||
|
||||
/**
|
||||
* Add an instruction to a method at the given index.
|
||||
*
|
||||
* @param index The index to add the instruction at.
|
||||
* @param smaliInstructions The instruction to add.
|
||||
*/
|
||||
fun MutableMethod.addInstruction(
|
||||
index: Int,
|
||||
smaliInstructions: String,
|
||||
) = implementation!!.addInstruction(index, smaliInstructions.toInstruction(this))
|
||||
|
||||
/**
|
||||
* Add an instruction to a method.
|
||||
*
|
||||
* @param smaliInstructions The instruction to add.
|
||||
*/
|
||||
fun MutableMethod.addInstruction(smaliInstructions: String) = implementation!!.addInstruction(smaliInstructions.toInstruction(this))
|
||||
|
||||
/**
|
||||
* Add instructions to a method at the given index.
|
||||
*
|
||||
* @param index The index to add the instructions at.
|
||||
* @param instructions The instructions to add.
|
||||
*/
|
||||
fun MutableMethod.addInstructions(
|
||||
index: Int,
|
||||
instructions: List<BuilderInstruction>,
|
||||
) = implementation!!.addInstructions(index, instructions)
|
||||
|
||||
/**
|
||||
* Add instructions to a method.
|
||||
*
|
||||
* @param instructions The instructions to add.
|
||||
*/
|
||||
fun MutableMethod.addInstructions(instructions: List<BuilderInstruction>) = implementation!!.addInstructions(instructions)
|
||||
|
||||
/**
|
||||
* Add instructions to a method.
|
||||
*
|
||||
* @param smaliInstructions The instructions to add.
|
||||
*/
|
||||
fun MutableMethod.addInstructions(
|
||||
index: Int,
|
||||
smaliInstructions: String,
|
||||
) = implementation!!.addInstructions(index, smaliInstructions.toInstructions(this))
|
||||
|
||||
/**
|
||||
* Add instructions to a method.
|
||||
*
|
||||
* @param smaliInstructions The instructions to add.
|
||||
*/
|
||||
fun MutableMethod.addInstructions(smaliInstructions: String) = implementation!!.addInstructions(smaliInstructions.toInstructions(this))
|
||||
|
||||
/**
|
||||
* Add instructions to a method at the given index.
|
||||
*
|
||||
* @param index The index to add the instructions at.
|
||||
* @param smaliInstructions The instructions to add.
|
||||
* @param externalLabels A list of [ExternalLabel] for instructions outside of [smaliInstructions].
|
||||
*/
|
||||
// Special function for adding instructions with external labels.
|
||||
fun MutableMethod.addInstructionsWithLabels(
|
||||
index: Int,
|
||||
smaliInstructions: String,
|
||||
vararg externalLabels: ExternalLabel,
|
||||
) {
|
||||
// Create reference dummy instructions for the instructions.
|
||||
val nopSmali =
|
||||
StringBuilder(smaliInstructions).also { builder ->
|
||||
externalLabels.forEach { (name, _) ->
|
||||
builder.append("\n:$name\nnop")
|
||||
}
|
||||
}.toString()
|
||||
|
||||
// Compile the instructions with the dummy labels
|
||||
val compiledInstructions = nopSmali.toInstructions(this)
|
||||
|
||||
// Add the compiled list of instructions to the method.
|
||||
addInstructions(
|
||||
index,
|
||||
compiledInstructions.subList(0, compiledInstructions.size - externalLabels.size),
|
||||
)
|
||||
|
||||
implementation!!.apply {
|
||||
this@apply.instructions.subList(index, index + compiledInstructions.size - externalLabels.size)
|
||||
.forEachIndexed { compiledInstructionIndex, compiledInstruction ->
|
||||
// If the compiled instruction is not an offset instruction, skip it.
|
||||
if (compiledInstruction !is BuilderOffsetInstruction) return@forEachIndexed
|
||||
|
||||
/**
|
||||
* Creates a new label for the instruction
|
||||
* and replaces it with the label of the [compiledInstruction] at [compiledInstructionIndex].
|
||||
*/
|
||||
fun Instruction.makeNewLabel() {
|
||||
fun replaceOffset(
|
||||
i: BuilderOffsetInstruction,
|
||||
label: Label,
|
||||
): BuilderOffsetInstruction {
|
||||
return when (i) {
|
||||
is BuilderInstruction10t -> BuilderInstruction10t(i.opcode, label)
|
||||
is BuilderInstruction20t -> BuilderInstruction20t(i.opcode, label)
|
||||
is BuilderInstruction21t -> BuilderInstruction21t(i.opcode, i.registerA, label)
|
||||
is BuilderInstruction22t ->
|
||||
BuilderInstruction22t(
|
||||
i.opcode,
|
||||
i.registerA,
|
||||
i.registerB,
|
||||
label,
|
||||
)
|
||||
is BuilderInstruction30t -> BuilderInstruction30t(i.opcode, label)
|
||||
is BuilderInstruction31t -> BuilderInstruction31t(i.opcode, i.registerA, label)
|
||||
else -> throw IllegalStateException(
|
||||
"A non-offset instruction was given, this should never happen!",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Create the final label.
|
||||
val label = newLabelForIndex(this@apply.instructions.indexOf(this))
|
||||
|
||||
// Create the final instruction with the new label.
|
||||
val newInstruction =
|
||||
replaceOffset(
|
||||
compiledInstruction,
|
||||
label,
|
||||
)
|
||||
|
||||
// Replace the instruction pointing to the dummy label
|
||||
// with the new instruction pointing to the real instruction.
|
||||
replaceInstruction(index + compiledInstructionIndex, newInstruction)
|
||||
}
|
||||
|
||||
// If the compiled instruction targets its own instruction,
|
||||
// which means it points to some of its own, simply an offset has to be applied.
|
||||
val labelIndex = compiledInstruction.target.location.index
|
||||
if (labelIndex < compiledInstructions.size - externalLabels.size) {
|
||||
// Get the targets index (insertion index + the index of the dummy instruction).
|
||||
this.instructions[index + labelIndex].makeNewLabel()
|
||||
return@forEachIndexed
|
||||
}
|
||||
|
||||
// Since the compiled instruction points to a dummy instruction,
|
||||
// we can find the real instruction which it was created for by calculation.
|
||||
|
||||
// Get the index of the instruction in the externalLabels list
|
||||
// which the dummy instruction was created for.
|
||||
// This works because we created the dummy instructions in the same order as the externalLabels list.
|
||||
val (_, instruction) = externalLabels[(compiledInstructions.size - 1) - labelIndex]
|
||||
instruction.makeNewLabel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an instruction at the given index.
|
||||
*
|
||||
* @param index The index to remove the instruction at.
|
||||
*/
|
||||
fun MutableMethod.removeInstruction(index: Int) = implementation!!.removeInstruction(index)
|
||||
|
||||
/**
|
||||
* Remove instructions at the given index.
|
||||
*
|
||||
* @param index The index to remove the instructions at.
|
||||
* @param count The amount of instructions to remove.
|
||||
*/
|
||||
fun MutableMethod.removeInstructions(
|
||||
index: Int,
|
||||
count: Int,
|
||||
) = implementation!!.removeInstructions(index, count)
|
||||
|
||||
/**
|
||||
* Remove instructions at the given index.
|
||||
*
|
||||
* @param count The amount of instructions to remove.
|
||||
*/
|
||||
fun MutableMethod.removeInstructions(count: Int) = implementation!!.removeInstructions(count)
|
||||
|
||||
/**
|
||||
* Replace an instruction at the given index.
|
||||
*
|
||||
* @param index The index to replace the instruction at.
|
||||
* @param instruction The instruction to replace the instruction with.
|
||||
*/
|
||||
fun MutableMethod.replaceInstruction(
|
||||
index: Int,
|
||||
instruction: BuilderInstruction,
|
||||
) = implementation!!.replaceInstruction(index, instruction)
|
||||
|
||||
/**
|
||||
* Replace an instruction at the given index.
|
||||
*
|
||||
* @param index The index to replace the instruction at.
|
||||
* @param smaliInstruction The smali instruction to replace the instruction with.
|
||||
*/
|
||||
fun MutableMethod.replaceInstruction(
|
||||
index: Int,
|
||||
smaliInstruction: String,
|
||||
) = implementation!!.replaceInstruction(index, smaliInstruction.toInstruction(this))
|
||||
|
||||
/**
|
||||
* Replace instructions at the given index.
|
||||
*
|
||||
* @param index The index to replace the instructions at.
|
||||
* @param instructions The instructions to replace the instructions with.
|
||||
*/
|
||||
fun MutableMethod.replaceInstructions(
|
||||
index: Int,
|
||||
instructions: List<BuilderInstruction>,
|
||||
) = implementation!!.replaceInstructions(index, instructions)
|
||||
|
||||
/**
|
||||
* Replace instructions at the given index.
|
||||
*
|
||||
* @param index The index to replace the instructions at.
|
||||
* @param smaliInstructions The smali instructions to replace the instructions with.
|
||||
*/
|
||||
fun MutableMethod.replaceInstructions(
|
||||
index: Int,
|
||||
smaliInstructions: String,
|
||||
) = implementation!!.replaceInstructions(index, smaliInstructions.toInstructions(this))
|
||||
|
||||
/**
|
||||
* Get an instruction at the given index.
|
||||
*
|
||||
* @param index The index to get the instruction at.
|
||||
* @return The instruction.
|
||||
*/
|
||||
fun MutableMethodImplementation.getInstruction(index: Int): BuilderInstruction = instructions[index]
|
||||
|
||||
/**
|
||||
* Get an instruction at the given index.
|
||||
*
|
||||
* @param index The index to get the instruction at.
|
||||
* @param T The type of instruction to return.
|
||||
* @return The instruction.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T> MutableMethodImplementation.getInstruction(index: Int): T = getInstruction(index) as T
|
||||
|
||||
/**
|
||||
* Get an instruction at the given index.
|
||||
* @param index The index to get the instruction at.
|
||||
* @return The instruction.
|
||||
*/
|
||||
fun MutableMethod.getInstruction(index: Int): BuilderInstruction = implementation!!.getInstruction(index)
|
||||
|
||||
/**
|
||||
* Get an instruction at the given index.
|
||||
* @param index The index to get the instruction at.
|
||||
* @param T The type of instruction to return.
|
||||
* @return The instruction.
|
||||
*/
|
||||
fun <T> MutableMethod.getInstruction(index: Int): T = implementation!!.getInstruction<T>(index)
|
||||
|
||||
/**
|
||||
* Get the instructions of a method.
|
||||
* @return The instructions.
|
||||
*/
|
||||
fun MutableMethod.getInstructions(): MutableList<BuilderInstruction> = implementation!!.instructions
|
||||
}
|
||||
@@ -1,16 +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].
|
||||
*/
|
||||
@Deprecated(
|
||||
message = "Use the property instead.",
|
||||
replaceWith = ReplaceWith("this.fuzzyPatternScanMethod"),
|
||||
)
|
||||
val MethodFingerprint.fuzzyPatternScanMethod
|
||||
get() = this.fuzzyPatternScanMethod
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
package app.revanced.patcher.fingerprint
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
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 java.util.*
|
||||
|
||||
internal typealias MethodClassPair = Pair<Method, ClassDef>
|
||||
|
||||
/**
|
||||
* Lookup map for methods.
|
||||
*/
|
||||
internal class LookupMap : MutableMap<String, LookupMap.MethodClassList> by mutableMapOf() {
|
||||
/**
|
||||
* Adds a [MethodClassPair] to the list associated with the given key.
|
||||
* If the key does not exist, a new list is created and the [MethodClassPair] is added to it.
|
||||
*/
|
||||
fun add(
|
||||
key: String,
|
||||
methodClassPair: MethodClassPair,
|
||||
) {
|
||||
getOrPut(key) { MethodClassList() }.add(methodClassPair)
|
||||
}
|
||||
|
||||
/**
|
||||
* List of methods and the class they are a member of.
|
||||
*/
|
||||
internal class MethodClassList : LinkedList<MethodClassPair>()
|
||||
|
||||
companion object Maps {
|
||||
/**
|
||||
* A list of methods and the class they are a member of.
|
||||
*/
|
||||
internal val methods = MethodClassList()
|
||||
|
||||
/**
|
||||
* Lookup map for methods keyed to the methods access flags, return type and parameter.
|
||||
*/
|
||||
internal val methodSignatureLookupMap = LookupMap()
|
||||
|
||||
/**
|
||||
* Lookup map for methods associated by strings referenced in the method.
|
||||
*/
|
||||
internal val methodStringsLookupMap = LookupMap()
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
internal fun initializeLookupMaps(context: BytecodeContext) {
|
||||
if (methods.isNotEmpty()) clearLookupMaps()
|
||||
|
||||
context.classes.forEach { classDef ->
|
||||
classDef.methods.forEach { method ->
|
||||
val methodClassPair = method to classDef
|
||||
|
||||
// For fingerprints with no access or return type specified.
|
||||
methods += methodClassPair
|
||||
|
||||
val accessFlagsReturnKey = method.accessFlags.toString() + method.returnType.first()
|
||||
|
||||
// Add <access><returnType> as the key.
|
||||
methodSignatureLookupMap.add(accessFlagsReturnKey, methodClassPair)
|
||||
|
||||
// Add <access><returnType>[parameters] as the key.
|
||||
methodSignatureLookupMap.add(
|
||||
buildString {
|
||||
append(accessFlagsReturnKey)
|
||||
appendParameters(method.parameterTypes)
|
||||
},
|
||||
methodClassPair,
|
||||
)
|
||||
|
||||
// Add strings contained in the method as the key.
|
||||
method.implementation?.instructions?.forEach instructions@{ instruction ->
|
||||
if (instruction.opcode != Opcode.CONST_STRING && instruction.opcode != Opcode.CONST_STRING_JUMBO) {
|
||||
return@instructions
|
||||
}
|
||||
|
||||
val string = ((instruction as ReferenceInstruction).reference as StringReference).string
|
||||
|
||||
methodStringsLookupMap.add(string, methodClassPair)
|
||||
}
|
||||
|
||||
// In the future, the class type could be added to the lookup map.
|
||||
// This would require MethodFingerprint to be changed to include the class type.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the internal lookup maps created in [initializeLookupMaps].
|
||||
*/
|
||||
internal fun clearLookupMaps() {
|
||||
methods.clear()
|
||||
methodSignatureLookupMap.clear()
|
||||
methodStringsLookupMap.clear()
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a string based on the parameter reference types of this method.
|
||||
*/
|
||||
internal fun StringBuilder.appendParameters(parameters: Iterable<CharSequence>) {
|
||||
// Maximum parameters to use in the signature key.
|
||||
// Some apps have methods with an incredible number of parameters (over 100 parameters have been seen).
|
||||
// To keep the signature map from becoming needlessly bloated,
|
||||
// group together in the same map entry all methods with the same access/return and 5 or more parameters.
|
||||
// The value of 5 was chosen based on local performance testing and is not set in stone.
|
||||
val maxSignatureParameters = 5
|
||||
// Must append a unique value before the parameters to distinguish this key includes the parameters.
|
||||
// If this is not appended, then methods with no parameters
|
||||
// will collide with different keys that specify access/return but omit the parameters.
|
||||
append("p:")
|
||||
parameters.forEachIndexed { index, parameter ->
|
||||
if (index >= maxSignatureParameters) return
|
||||
append(parameter.first())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,357 +0,0 @@
|
||||
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
|
||||
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 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
|
||||
|
||||
/**
|
||||
* A fingerprint to resolve methods.
|
||||
*
|
||||
* @param returnType The method's return type compared using [String.startsWith].
|
||||
* @param accessFlags The method's exact access flags using values of [AccessFlags].
|
||||
* @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.
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
abstract 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 customFingerprint: ((methodDef: Method, classDef: ClassDef) -> Boolean)? = null,
|
||||
) {
|
||||
/**
|
||||
* The result of the [MethodFingerprint].
|
||||
*/
|
||||
var result: MethodFingerprintResult? = null
|
||||
private set
|
||||
|
||||
/**
|
||||
* The [FuzzyPatternScanMethod] annotation of the [MethodFingerprint].
|
||||
*
|
||||
* If the annotation is not present, this property is null.
|
||||
*/
|
||||
val fuzzyPatternScanMethod = this::class.findAnnotationRecursively(FuzzyPatternScanMethod::class)
|
||||
|
||||
/**
|
||||
* Resolve a [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 resolveUsingLookupMap(context: BytecodeContext): Boolean {
|
||||
/**
|
||||
* Lookup [MethodClassPair]s that match the methods strings present in a [MethodFingerprint].
|
||||
*
|
||||
* @return A list of [MethodClassPair]s that match the methods strings present in a [MethodFingerprint].
|
||||
*/
|
||||
fun MethodFingerprint.methodStringsLookup(): LookupMap.MethodClassList? {
|
||||
strings?.forEach {
|
||||
val methods = methodStringsLookupMap[it]
|
||||
if (methods != null) return methods
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup [MethodClassPair]s that match the method signature present in a [MethodFingerprint].
|
||||
*
|
||||
* @return A list of [MethodClassPair]s that match the method signature present in a [MethodFingerprint].
|
||||
*/
|
||||
fun MethodFingerprint.methodSignatureLookup(): LookupMap.MethodClassList {
|
||||
if (accessFlags == null) return methods
|
||||
|
||||
var returnTypeValue = returnType
|
||||
if (returnTypeValue == null) {
|
||||
if (AccessFlags.CONSTRUCTOR.isSet(accessFlags)) {
|
||||
// Constructors always have void return type
|
||||
returnTypeValue = "V"
|
||||
} else {
|
||||
return methods
|
||||
}
|
||||
}
|
||||
|
||||
val key =
|
||||
buildString {
|
||||
append(accessFlags)
|
||||
append(returnTypeValue.first())
|
||||
if (parameters != null) appendParameters(parameters)
|
||||
}
|
||||
return methodSignatureLookupMap[key] ?: return LookupMap.MethodClassList()
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a [MethodFingerprint] using a list of [MethodClassPair].
|
||||
*
|
||||
* @return True if the resolution was successful, false otherwise.
|
||||
*/
|
||||
fun MethodFingerprint.resolveUsingMethodClassPair(methodClasses: LookupMap.MethodClassList): Boolean {
|
||||
methodClasses.forEach { classAndMethod ->
|
||||
if (resolve(context, classAndMethod.first, classAndMethod.second)) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
val methodsWithSameStrings = methodStringsLookup()
|
||||
if (methodsWithSameStrings != null) {
|
||||
if (resolveUsingMethodClassPair(methodsWithSameStrings)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// No strings declared or none matched (partial matches are allowed).
|
||||
// Use signature matching.
|
||||
return resolveUsingMethodClassPair(methodSignatureLookup())
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a [MethodFingerprint] against a [ClassDef].
|
||||
*
|
||||
* @param forClass The class on which to resolve the [MethodFingerprint] in.
|
||||
* @param context The [BytecodeContext] to host proxies.
|
||||
* @return True if the resolution was successful, false otherwise.
|
||||
*/
|
||||
fun resolve(
|
||||
context: BytecodeContext,
|
||||
forClass: ClassDef,
|
||||
): Boolean {
|
||||
for (method in forClass.methods)
|
||||
if (resolve(context, method, forClass)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a [MethodFingerprint] against a [Method].
|
||||
*
|
||||
* @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.
|
||||
* @return True if the resolution was successful or if the fingerprint is already resolved, false otherwise.
|
||||
*/
|
||||
fun resolve(
|
||||
context: BytecodeContext,
|
||||
method: Method,
|
||||
forClass: ClassDef,
|
||||
): Boolean {
|
||||
val methodFingerprint = this
|
||||
|
||||
if (methodFingerprint.result != null) return true
|
||||
|
||||
if (methodFingerprint.returnType != null && !method.returnType.startsWith(methodFingerprint.returnType)) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (methodFingerprint.accessFlags != null && methodFingerprint.accessFlags != method.accessFlags) {
|
||||
return false
|
||||
}
|
||||
|
||||
fun parametersEqual(
|
||||
parameters1: Iterable<CharSequence>,
|
||||
parameters2: Iterable<CharSequence>,
|
||||
): Boolean {
|
||||
if (parameters1.count() != parameters2.count()) return false
|
||||
val iterator1 = parameters1.iterator()
|
||||
parameters2.forEach {
|
||||
if (!it.startsWith(iterator1.next())) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if (methodFingerprint.parameters != null &&
|
||||
!parametersEqual(
|
||||
methodFingerprint.parameters, // TODO: parseParameters()
|
||||
method.parameterTypes,
|
||||
)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
@Suppress("UNNECESSARY_NOT_NULL_ASSERTION")
|
||||
if (methodFingerprint.customFingerprint != null && !methodFingerprint.customFingerprint!!(method, forClass)) {
|
||||
return false
|
||||
}
|
||||
|
||||
val stringsScanResult: StringsScanResult? =
|
||||
if (methodFingerprint.strings != null) {
|
||||
StringsScanResult(
|
||||
buildList {
|
||||
val implementation = method.implementation ?: return false
|
||||
|
||||
val stringsList = methodFingerprint.strings.toMutableList()
|
||||
|
||||
implementation.instructions.forEachIndexed { instructionIndex, instruction ->
|
||||
if (
|
||||
instruction.opcode != Opcode.CONST_STRING &&
|
||||
instruction.opcode != Opcode.CONST_STRING_JUMBO
|
||||
) {
|
||||
return@forEachIndexed
|
||||
}
|
||||
|
||||
val string = ((instruction as ReferenceInstruction).reference as StringReference).string
|
||||
val index = stringsList.indexOfFirst(string::contains)
|
||||
if (index == -1) return@forEachIndexed
|
||||
|
||||
add(StringsScanResult.StringMatch(string, instructionIndex))
|
||||
stringsList.removeAt(index)
|
||||
}
|
||||
|
||||
if (stringsList.isNotEmpty()) return false
|
||||
},
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
val patternScanResult =
|
||||
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? {
|
||||
val instructions = this.implementation!!.instructions
|
||||
val fingerprintFuzzyPatternScanThreshold = fingerprint.fuzzyPatternScanMethod?.threshold ?: 0
|
||||
|
||||
val pattern = fingerprint.opcodes!!
|
||||
val instructionLength = instructions.count()
|
||||
val patternLength = pattern.count()
|
||||
|
||||
for (index in 0 until instructionLength) {
|
||||
var patternIndex = 0
|
||||
var threshold = fingerprintFuzzyPatternScanThreshold
|
||||
|
||||
while (index + patternIndex < instructionLength) {
|
||||
val originalOpcode = instructions.elementAt(index + patternIndex).opcode
|
||||
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
|
||||
if (threshold-- == 0) break
|
||||
}
|
||||
|
||||
if (patternIndex < patternLength - 1) {
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
method.patternScan(methodFingerprint) ?: return false
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
methodFingerprint.result =
|
||||
MethodFingerprintResult(
|
||||
method,
|
||||
forClass,
|
||||
MethodFingerprintResult.MethodFingerprintScanResult(
|
||||
patternScanResult,
|
||||
stringsScanResult,
|
||||
),
|
||||
context,
|
||||
)
|
||||
|
||||
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")
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,94 +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.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
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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,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,
|
||||
)
|
||||
@@ -1,61 +0,0 @@
|
||||
package app.revanced.patcher.patch
|
||||
|
||||
import app.revanced.patcher.PatchClass
|
||||
import app.revanced.patcher.Patcher
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
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())
|
||||
}
|
||||
@@ -1,124 +1,7 @@
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
package app.revanced.patcher.patch
|
||||
|
||||
import app.revanced.patcher.PatchClass
|
||||
import app.revanced.patcher.Patcher
|
||||
import app.revanced.patcher.data.Context
|
||||
import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively
|
||||
import app.revanced.patcher.patch.options.PatchOptions
|
||||
import java.io.Closeable
|
||||
import app.revanced.patcher.cache.Cache
|
||||
|
||||
/**
|
||||
* A patch.
|
||||
*
|
||||
* If an implementation of [Patch] also implements [Closeable]
|
||||
* it will be closed in reverse execution order of patches executed by [Patcher].
|
||||
*
|
||||
* @param T The [Context] type this patch will work on.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
val options = PatchOptions()
|
||||
|
||||
/**
|
||||
* The execution function of the patch.
|
||||
*
|
||||
* @param context The [Context] the patch will work on.
|
||||
* @return The result of executing 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
|
||||
}
|
||||
|
||||
/**
|
||||
* A package a [Patch] is compatible with.
|
||||
*
|
||||
* @param name The name of the package.
|
||||
* @param versions The versions of the package.
|
||||
*/
|
||||
class CompatiblePackage(
|
||||
val name: String,
|
||||
val versions: Set<String>? = null,
|
||||
)
|
||||
abstract class Patch(val patchName: String) {
|
||||
abstract fun execute(cache: Cache): PatchResult
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -1,9 +1,33 @@
|
||||
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)
|
||||
interface PatchResult {
|
||||
fun error(): PatchResultError? {
|
||||
if (this is PatchResultError) {
|
||||
return this
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun success(): PatchResultSuccess? {
|
||||
if (this is PatchResultSuccess) {
|
||||
return this
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun isError(): Boolean {
|
||||
return this is PatchResultError
|
||||
}
|
||||
|
||||
fun isSuccess(): Boolean {
|
||||
return this is PatchResultSuccess
|
||||
}
|
||||
}
|
||||
|
||||
class PatchResultError(private val errorMessage: String) : PatchResult {
|
||||
fun errorMessage(): String {
|
||||
return errorMessage
|
||||
}
|
||||
}
|
||||
|
||||
class PatchResultSuccess : PatchResult
|
||||
@@ -1,43 +0,0 @@
|
||||
package app.revanced.patcher.patch
|
||||
|
||||
import app.revanced.patcher.PatchClass
|
||||
import app.revanced.patcher.Patcher
|
||||
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)
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package app.revanced.patcher.patch
|
||||
|
||||
import app.revanced.patcher.PatchClass
|
||||
import app.revanced.patcher.Patcher
|
||||
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)
|
||||
}
|
||||
@@ -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> = [],
|
||||
)
|
||||
@@ -1,477 +0,0 @@
|
||||
package app.revanced.patcher.patch.options
|
||||
|
||||
import app.revanced.patcher.patch.Patch
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
/**
|
||||
* A [Patch] option.
|
||||
*
|
||||
* @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.
|
||||
* @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
|
||||
}
|
||||
|
||||
@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] with a string set 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 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)
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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 identifier.
|
||||
* @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)
|
||||
}
|
||||
162
src/main/kotlin/app/revanced/patcher/resolver/MethodResolver.kt
Normal file
162
src/main/kotlin/app/revanced/patcher/resolver/MethodResolver.kt
Normal file
@@ -0,0 +1,162 @@
|
||||
package app.revanced.patcher.resolver
|
||||
|
||||
import app.revanced.patcher.cache.MethodMap
|
||||
import app.revanced.patcher.cache.PatchData
|
||||
import app.revanced.patcher.cache.PatternScanData
|
||||
import app.revanced.patcher.signature.Signature
|
||||
import app.revanced.patcher.util.ExtraTypes
|
||||
import mu.KotlinLogging
|
||||
import org.objectweb.asm.Type
|
||||
import org.objectweb.asm.tree.*
|
||||
|
||||
private val logger = KotlinLogging.logger("MethodResolver")
|
||||
|
||||
internal class MethodResolver(private val classList: List<ClassNode>, private val signatures: Array<Signature>) {
|
||||
fun resolve(): MethodMap {
|
||||
val methodMap = MethodMap()
|
||||
|
||||
for ((classNode, methods) in classList) {
|
||||
for (method in methods) {
|
||||
for (signature in signatures) {
|
||||
if (methodMap.containsKey(signature.name)) { // method already found for this sig
|
||||
logger.trace { "Sig ${signature.name} already found, skipping." }
|
||||
continue
|
||||
}
|
||||
logger.trace { "Resolving sig ${signature.name}: ${classNode.name} / ${method.name}" }
|
||||
val (r, sr) = cmp(method, signature)
|
||||
if (!r || sr == null) {
|
||||
logger.trace { "Compare result for sig ${signature.name} has failed!" }
|
||||
continue
|
||||
}
|
||||
logger.trace { "Method for sig ${signature.name} found!" }
|
||||
methodMap[signature.name] = PatchData(
|
||||
classNode,
|
||||
method,
|
||||
PatternScanData(
|
||||
// sadly we cannot create contracts for a data class, so we must assert
|
||||
sr.startIndex!!,
|
||||
sr.endIndex!!
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (signature in signatures) {
|
||||
if (methodMap.containsKey(signature.name)) continue
|
||||
logger.error { "Could not find method for sig ${signature.name}!" }
|
||||
}
|
||||
|
||||
return methodMap
|
||||
}
|
||||
|
||||
// These functions do not require the constructor values, so they can be static.
|
||||
companion object {
|
||||
fun resolveMethod(classNode: ClassNode, signature: Signature): PatchData? {
|
||||
for (method in classNode.methods) {
|
||||
val (r, sr) = cmp(method, signature)
|
||||
if (!r || sr == null) continue
|
||||
return PatchData(
|
||||
classNode,
|
||||
method,
|
||||
PatternScanData(0, 0) // opcode list is always ignored.
|
||||
)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun cmp(method: MethodNode, signature: Signature): Pair<Boolean, ScanResult?> {
|
||||
signature.returns?.let { _ ->
|
||||
val methodReturns = Type.getReturnType(method.desc).convertObject()
|
||||
if (signature.returns != methodReturns) {
|
||||
logger.trace {
|
||||
"""
|
||||
Comparing sig ${signature.name}: invalid return type:
|
||||
expected ${signature.returns},
|
||||
got $methodReturns
|
||||
""".trimIndent()
|
||||
}
|
||||
return@cmp false to null
|
||||
}
|
||||
}
|
||||
|
||||
signature.accessors?.let { _ ->
|
||||
if (signature.accessors != method.access) {
|
||||
logger.trace {
|
||||
"""
|
||||
Comparing sig ${signature.name}: invalid accessors:
|
||||
expected ${signature.accessors},
|
||||
got ${method.access}
|
||||
""".trimIndent()
|
||||
}
|
||||
return@cmp false to null
|
||||
}
|
||||
}
|
||||
|
||||
signature.parameters?.let { _ ->
|
||||
val parameters = Type.getArgumentTypes(method.desc).convertObjects()
|
||||
if (!signature.parameters.contentEquals(parameters)) {
|
||||
logger.trace {
|
||||
"""
|
||||
Comparing sig ${signature.name}: invalid parameter types:
|
||||
expected ${signature.parameters.joinToString()}},
|
||||
got ${parameters.joinToString()}
|
||||
""".trimIndent()
|
||||
}
|
||||
return@cmp false to null
|
||||
}
|
||||
}
|
||||
|
||||
signature.opcodes?.let { _ ->
|
||||
val result = method.instructions.scanFor(signature.opcodes)
|
||||
if (!result.found) {
|
||||
logger.trace { "Comparing sig ${signature.name}: invalid opcode pattern" }
|
||||
return@cmp false to null
|
||||
}
|
||||
return@cmp true to result
|
||||
}
|
||||
|
||||
return true to ScanResult(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private operator fun ClassNode.component1() = this
|
||||
private operator fun ClassNode.component2() = this.methods
|
||||
|
||||
private fun InsnList.scanFor(pattern: IntArray): ScanResult {
|
||||
for (i in 0 until this.size()) {
|
||||
var occurrence = 0
|
||||
while (i + occurrence < this.size()) {
|
||||
val n = this[i + occurrence]
|
||||
if (
|
||||
!n.anyOf(
|
||||
LabelNode::class.java,
|
||||
LineNumberNode::class.java
|
||||
) &&
|
||||
n.opcode != pattern[occurrence]
|
||||
) break
|
||||
if (++occurrence >= pattern.size) {
|
||||
val current = i + occurrence
|
||||
return ScanResult(true, current - pattern.size, current)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ScanResult(false)
|
||||
}
|
||||
|
||||
private fun Type.convertObject(): Type {
|
||||
return when (this.sort) {
|
||||
Type.OBJECT -> ExtraTypes.Any
|
||||
Type.ARRAY -> ExtraTypes.ArrayAny
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
private fun Array<Type>.convertObjects(): Array<Type> {
|
||||
return this.map { it.convertObject() }.toTypedArray()
|
||||
}
|
||||
|
||||
private fun AbstractInsnNode.anyOf(vararg types: Class<*>): Boolean =
|
||||
types.any { this@anyOf.javaClass == it }
|
||||
@@ -0,0 +1,7 @@
|
||||
package app.revanced.patcher.resolver
|
||||
|
||||
internal data class ScanResult(
|
||||
val found: Boolean,
|
||||
val startIndex: Int? = 0,
|
||||
val endIndex: Int? = 0
|
||||
)
|
||||
27
src/main/kotlin/app/revanced/patcher/signature/Signature.kt
Normal file
27
src/main/kotlin/app/revanced/patcher/signature/Signature.kt
Normal file
@@ -0,0 +1,27 @@
|
||||
package app.revanced.patcher.signature
|
||||
|
||||
import org.objectweb.asm.Type
|
||||
|
||||
/**
|
||||
* An ASM signature list for the Patcher.
|
||||
*
|
||||
* @param name The name of the method.
|
||||
* Do not use the actual method name, instead try to guess what the method name originally was.
|
||||
* If you are unable to guess a method name, doing something like "patch-name-1" is fine too.
|
||||
* For example: "override-codec-1".
|
||||
* This method name will be mapped to the method matching the signature.
|
||||
* Even though this is technically not needed for the `findParentMethod` method,
|
||||
* it is still recommended giving the method a name, so it can be identified easily.
|
||||
* @param returns The return type/signature of the method.
|
||||
* @param accessors The accessors of the method.
|
||||
* @param parameters The parameter types of the method.
|
||||
* @param opcodes The opcode pattern of the method, used to find the method by pattern scanning.
|
||||
*/
|
||||
@Suppress("ArrayInDataClass")
|
||||
data class Signature(
|
||||
val name: String,
|
||||
val returns: Type?,
|
||||
val accessors: Int?,
|
||||
val parameters: Array<Type>?,
|
||||
val opcodes: IntArray?
|
||||
)
|
||||
@@ -1,238 +0,0 @@
|
||||
package app.revanced.patcher.util
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.util.ClassMerger.Utils.asMutableClass
|
||||
import app.revanced.patcher.util.ClassMerger.Utils.filterAny
|
||||
import app.revanced.patcher.util.ClassMerger.Utils.filterNotAny
|
||||
import app.revanced.patcher.util.ClassMerger.Utils.isPublic
|
||||
import app.revanced.patcher.util.ClassMerger.Utils.toPublic
|
||||
import app.revanced.patcher.util.ClassMerger.Utils.traverseClassHierarchy
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass.Companion.toMutable
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableField
|
||||
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.iface.ClassDef
|
||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
import java.util.logging.Logger
|
||||
import kotlin.reflect.KFunction2
|
||||
|
||||
/**
|
||||
* Experimental class to merge a [ClassDef] with another.
|
||||
* Note: This will not consider method implementations or if the class is missing a superclass or interfaces.
|
||||
*/
|
||||
internal object ClassMerger {
|
||||
private val logger = Logger.getLogger(ClassMerger::class.java.name)
|
||||
|
||||
/**
|
||||
* Merge a class with [otherClass].
|
||||
*
|
||||
* @param otherClass The class to merge with
|
||||
* @param context The context to traverse the class hierarchy in.
|
||||
* @return The merged class or the original class if no merge was needed.
|
||||
*/
|
||||
fun ClassDef.merge(
|
||||
otherClass: ClassDef,
|
||||
context: BytecodeContext,
|
||||
) = this
|
||||
// .fixFieldAccess(otherClass)
|
||||
// .fixMethodAccess(otherClass)
|
||||
.addMissingFields(otherClass)
|
||||
.addMissingMethods(otherClass)
|
||||
.publicize(otherClass, context)
|
||||
|
||||
/**
|
||||
* Add methods which are missing but existing in [fromClass].
|
||||
*
|
||||
* @param fromClass The class to add missing methods from.
|
||||
*/
|
||||
private fun ClassDef.addMissingMethods(fromClass: ClassDef): ClassDef {
|
||||
val missingMethods =
|
||||
fromClass.methods.let { fromMethods ->
|
||||
methods.filterNot { method ->
|
||||
fromMethods.any { fromMethod ->
|
||||
MethodUtil.methodSignaturesMatch(fromMethod, method)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (missingMethods.isEmpty()) return this
|
||||
|
||||
logger.fine("Found ${missingMethods.size} missing methods")
|
||||
|
||||
return asMutableClass().apply {
|
||||
methods.addAll(missingMethods.map { it.toMutable() })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add fields which are missing but existing in [fromClass].
|
||||
*
|
||||
* @param fromClass The class to add missing fields from.
|
||||
*/
|
||||
private fun ClassDef.addMissingFields(fromClass: ClassDef): ClassDef {
|
||||
val missingFields =
|
||||
fields.filterNotAny(fromClass.fields) { field, fromField ->
|
||||
fromField.name == field.name
|
||||
}
|
||||
|
||||
if (missingFields.isEmpty()) return this
|
||||
|
||||
logger.fine("Found ${missingFields.size} missing fields")
|
||||
|
||||
return asMutableClass().apply {
|
||||
fields.addAll(missingFields.map { it.toMutable() })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a class and its super class public recursively.
|
||||
* @param reference The class to check the [AccessFlags] of.
|
||||
* @param context The context to traverse the class hierarchy in.
|
||||
*/
|
||||
private fun ClassDef.publicize(
|
||||
reference: ClassDef,
|
||||
context: BytecodeContext,
|
||||
) = if (reference.accessFlags.isPublic() && !accessFlags.isPublic()) {
|
||||
this.asMutableClass().apply {
|
||||
context.traverseClassHierarchy(this) {
|
||||
if (accessFlags.isPublic()) return@traverseClassHierarchy
|
||||
|
||||
logger.fine("Publicizing ${this.type}")
|
||||
|
||||
accessFlags = accessFlags.toPublic()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this
|
||||
}
|
||||
|
||||
/**
|
||||
* Publicize fields if they are public in [reference].
|
||||
*
|
||||
* @param reference The class to check the [AccessFlags] of the fields in.
|
||||
*/
|
||||
private fun ClassDef.fixFieldAccess(reference: ClassDef): ClassDef {
|
||||
val brokenFields =
|
||||
fields.filterAny(reference.fields) { field, referenceField ->
|
||||
if (field.name != referenceField.name) return@filterAny false
|
||||
|
||||
referenceField.accessFlags.isPublic() && !field.accessFlags.isPublic()
|
||||
}
|
||||
|
||||
if (brokenFields.isEmpty()) return this
|
||||
|
||||
logger.fine("Found ${brokenFields.size} broken fields")
|
||||
|
||||
/**
|
||||
* Make a field public.
|
||||
*/
|
||||
fun MutableField.publicize() {
|
||||
accessFlags = accessFlags.toPublic()
|
||||
}
|
||||
|
||||
return asMutableClass().apply {
|
||||
fields.filter { brokenFields.contains(it) }.forEach(MutableField::publicize)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Publicize methods if they are public in [reference].
|
||||
*
|
||||
* @param reference The class to check the [AccessFlags] of the methods in.
|
||||
*/
|
||||
private fun ClassDef.fixMethodAccess(reference: ClassDef): ClassDef {
|
||||
val brokenMethods =
|
||||
methods.filterAny(reference.methods) { method, referenceMethod ->
|
||||
if (!MethodUtil.methodSignaturesMatch(method, referenceMethod)) return@filterAny false
|
||||
|
||||
referenceMethod.accessFlags.isPublic() && !method.accessFlags.isPublic()
|
||||
}
|
||||
|
||||
if (brokenMethods.isEmpty()) return this
|
||||
|
||||
logger.fine("Found ${brokenMethods.size} methods")
|
||||
|
||||
/**
|
||||
* Make a method public.
|
||||
*/
|
||||
fun MutableMethod.publicize() {
|
||||
accessFlags = accessFlags.toPublic()
|
||||
}
|
||||
|
||||
return asMutableClass().apply {
|
||||
methods.filter { brokenMethods.contains(it) }.forEach(MutableMethod::publicize)
|
||||
}
|
||||
}
|
||||
|
||||
private object Utils {
|
||||
/**
|
||||
* traverse the class hierarchy starting from the given root class
|
||||
*
|
||||
* @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(
|
||||
targetClass: MutableClass,
|
||||
callback: MutableClass.() -> Unit,
|
||||
) {
|
||||
callback(targetClass)
|
||||
this.findClass(targetClass.superclass ?: return)?.mutableClass?.let {
|
||||
traverseClassHierarchy(it, callback)
|
||||
}
|
||||
}
|
||||
|
||||
fun ClassDef.asMutableClass() = if (this is MutableClass) this else this.toMutable()
|
||||
|
||||
/**
|
||||
* Check if the [AccessFlags.PUBLIC] flag is set.
|
||||
*
|
||||
* @return True, if the flag is set.
|
||||
*/
|
||||
fun Int.isPublic() = AccessFlags.PUBLIC.isSet(this)
|
||||
|
||||
/**
|
||||
* Make [AccessFlags] public.
|
||||
*
|
||||
* @return The new [AccessFlags].
|
||||
*/
|
||||
fun Int.toPublic() = this.or(AccessFlags.PUBLIC).and(AccessFlags.PRIVATE.value.inv())
|
||||
|
||||
/**
|
||||
* Filter [this] on [needles] matching the given [predicate].
|
||||
*
|
||||
* @param needles The needles to filter [this] with.
|
||||
* @param predicate The filter.
|
||||
* @return The [this] filtered on [needles] matching the given [predicate].
|
||||
*/
|
||||
fun <HayType, NeedleType> Iterable<HayType>.filterAny(
|
||||
needles: Iterable<NeedleType>,
|
||||
predicate: (HayType, NeedleType) -> Boolean,
|
||||
) = Iterable<HayType>::filter.any(this, needles, predicate)
|
||||
|
||||
/**
|
||||
* Filter [this] on [needles] not matching the given [predicate].
|
||||
*
|
||||
* @param needles The needles to filter [this] with.
|
||||
* @param predicate The filter.
|
||||
* @return The [this] filtered on [needles] not matching the given [predicate].
|
||||
*/
|
||||
fun <HayType, NeedleType> Iterable<HayType>.filterNotAny(
|
||||
needles: Iterable<NeedleType>,
|
||||
predicate: (HayType, NeedleType) -> Boolean,
|
||||
) = Iterable<HayType>::filterNot.any(this, needles, predicate)
|
||||
|
||||
fun <HayType, NeedleType> KFunction2<Iterable<HayType>, (HayType) -> Boolean, List<HayType>>.any(
|
||||
haystack: Iterable<HayType>,
|
||||
needles: Iterable<NeedleType>,
|
||||
predicate: (HayType, NeedleType) -> Boolean,
|
||||
) = this(haystack) { hay ->
|
||||
needles.any { needle ->
|
||||
predicate(hay, needle)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package app.revanced.patcher.util
|
||||
|
||||
import org.w3c.dom.Document
|
||||
import java.io.Closeable
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import javax.xml.parsers.DocumentBuilderFactory
|
||||
import javax.xml.transform.TransformerFactory
|
||||
import javax.xml.transform.dom.DOMSource
|
||||
import javax.xml.transform.stream.StreamResult
|
||||
|
||||
class Document internal constructor(
|
||||
inputStream: InputStream,
|
||||
) : Document by DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(inputStream), Closeable {
|
||||
private var file: File? = null
|
||||
|
||||
init {
|
||||
normalize()
|
||||
}
|
||||
|
||||
internal constructor(file: File) : this(file.inputStream()) {
|
||||
this.file = file
|
||||
readerCount.merge(file, 1, Int::plus)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
file?.let {
|
||||
if (readerCount[it]!! > 1) {
|
||||
throw IllegalStateException(
|
||||
"Two or more instances are currently reading $it." +
|
||||
"To be able to close this instance, no other instances may be reading $it at the same time.",
|
||||
)
|
||||
} else {
|
||||
readerCount.remove(it)
|
||||
}
|
||||
|
||||
it.outputStream().use { stream ->
|
||||
TransformerFactory.newInstance()
|
||||
.newTransformer()
|
||||
.transform(DOMSource(this), StreamResult(stream))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
private val readerCount = mutableMapOf<File, Int>()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
12
src/main/kotlin/app/revanced/patcher/util/ExtraTypes.kt
Normal file
12
src/main/kotlin/app/revanced/patcher/util/ExtraTypes.kt
Normal file
@@ -0,0 +1,12 @@
|
||||
package app.revanced.patcher.util
|
||||
|
||||
import org.objectweb.asm.Type
|
||||
|
||||
object ExtraTypes {
|
||||
/**
|
||||
* Any object type.
|
||||
* Should be used instead of types such as: "Ljava/lang/String;"
|
||||
*/
|
||||
val Any: Type = Type.getType(Object::class.java)
|
||||
val ArrayAny: Type = Type.getType(Array<Any>::class.java)
|
||||
}
|
||||
94
src/main/kotlin/app/revanced/patcher/util/Io.kt
Normal file
94
src/main/kotlin/app/revanced/patcher/util/Io.kt
Normal file
@@ -0,0 +1,94 @@
|
||||
package app.revanced.patcher.util
|
||||
|
||||
import org.objectweb.asm.ClassReader
|
||||
import org.objectweb.asm.ClassWriter
|
||||
import org.objectweb.asm.tree.ClassNode
|
||||
import java.io.BufferedInputStream
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.util.jar.JarEntry
|
||||
import java.util.jar.JarInputStream
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipInputStream
|
||||
import java.util.zip.ZipOutputStream
|
||||
|
||||
internal class Io(
|
||||
private val input: InputStream,
|
||||
private val output: OutputStream,
|
||||
private val classes: MutableList<ClassNode>
|
||||
) {
|
||||
private val bufferedInputStream = BufferedInputStream(input)
|
||||
|
||||
fun readFromJar() {
|
||||
bufferedInputStream.mark(Integer.MAX_VALUE)
|
||||
// create a BufferedInputStream in order to read the input stream again when calling saveAsJar(..)
|
||||
val jis = JarInputStream(bufferedInputStream)
|
||||
|
||||
// read all entries from the input stream
|
||||
// we use JarEntry because we only read .class files
|
||||
lateinit var jarEntry: JarEntry
|
||||
while (jis.nextJarEntry.also { if (it != null) jarEntry = it } != null) {
|
||||
// if the current entry ends with .class (indicating a java class file), add it to our list of classes to return
|
||||
if (jarEntry.name.endsWith(".class")) {
|
||||
// create a new ClassNode
|
||||
val classNode = ClassNode()
|
||||
// read the bytes with a ClassReader into the ClassNode
|
||||
ClassReader(jis.readBytes()).accept(classNode, ClassReader.EXPAND_FRAMES)
|
||||
// add it to our list
|
||||
classes.add(classNode)
|
||||
}
|
||||
|
||||
// finally, close the entry
|
||||
jis.closeEntry()
|
||||
}
|
||||
|
||||
// at last reset the buffered input stream
|
||||
bufferedInputStream.reset()
|
||||
}
|
||||
|
||||
fun saveAsJar() {
|
||||
val jis = ZipInputStream(bufferedInputStream)
|
||||
val jos = ZipOutputStream(output)
|
||||
val classReaders = mutableMapOf<String, ClassReader>()
|
||||
|
||||
// first write all non .class zip entries from the original input stream to the output stream
|
||||
// we read it first to close the input stream as fast as possible
|
||||
// TODO(oSumAtrIX): There is currently no way to remove non .class files.
|
||||
lateinit var zipEntry: ZipEntry
|
||||
while (jis.nextEntry.also { if (it != null) zipEntry = it } != null) {
|
||||
if (zipEntry.name.endsWith(".class")) {
|
||||
classReaders[zipEntry.name] = ClassReader(jis.readBytes())
|
||||
continue
|
||||
}
|
||||
|
||||
// create a new zipEntry and write the contents of the zipEntry to the output stream and close it
|
||||
jos.putNextEntry(ZipEntry(zipEntry))
|
||||
jos.write(jis.readBytes())
|
||||
jos.closeEntry()
|
||||
}
|
||||
|
||||
// finally, close the input stream
|
||||
jis.close()
|
||||
bufferedInputStream.close()
|
||||
input.close()
|
||||
|
||||
// now write all the patched classes to the output stream
|
||||
for (patchedClass in classes) {
|
||||
// create a new entry of the patched class
|
||||
val name = patchedClass.name + ".class"
|
||||
jos.putNextEntry(JarEntry(name))
|
||||
|
||||
// parse the patched class to a byte array and write it to the output stream
|
||||
val cw = ClassWriter(classReaders[name]!!, ClassWriter.COMPUTE_MAXS)
|
||||
patchedClass.accept(cw)
|
||||
jos.write(cw.toByteArray())
|
||||
|
||||
// close the newly created jar entry
|
||||
jos.closeEntry()
|
||||
}
|
||||
|
||||
// finally, close the rest of the streams
|
||||
jos.close()
|
||||
output.close()
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package app.revanced.patcher.util
|
||||
|
||||
import app.revanced.patcher.util.proxy.ClassProxy
|
||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||
|
||||
/**
|
||||
* A class that represents a set of classes and proxies.
|
||||
*
|
||||
* @param classes The classes to be backed by proxies.
|
||||
*/
|
||||
class ProxyClassList internal constructor(classes: MutableSet<ClassDef>) : MutableSet<ClassDef> by classes {
|
||||
internal val proxies = mutableListOf<ClassProxy>()
|
||||
|
||||
/**
|
||||
* Add a [ClassProxy].
|
||||
*/
|
||||
fun add(classProxy: ClassProxy) = proxies.add(classProxy)
|
||||
|
||||
/**
|
||||
* Replace all classes with their mutated versions.
|
||||
*/
|
||||
internal fun replaceClasses() =
|
||||
proxies.removeIf { proxy ->
|
||||
// If the proxy is unused, return false to keep it in the proxies list.
|
||||
if (!proxy.resolved) return@removeIf false
|
||||
|
||||
// If it has been used, replace the original class with the mutable class.
|
||||
remove(proxy.immutableClass)
|
||||
add(proxy.mutableClass)
|
||||
|
||||
// Return true to remove the proxy from the proxies list.
|
||||
return@removeIf true
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package app.revanced.patcher.util.method
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
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
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
|
||||
/**
|
||||
* Find a method from another method via instruction offsets.
|
||||
* @param bytecodeContext The context to use when resolving the next method reference.
|
||||
* @param currentMethod The method to start from.
|
||||
*/
|
||||
class MethodWalker internal constructor(
|
||||
private val bytecodeContext: BytecodeContext,
|
||||
private var currentMethod: Method,
|
||||
) {
|
||||
/**
|
||||
* Get the method which was walked last.
|
||||
*
|
||||
* It is possible to cast this method to a [MutableMethod], if the method has been walked mutably.
|
||||
*
|
||||
* @return The method which was walked last.
|
||||
*/
|
||||
fun getMethod(): Method {
|
||||
return currentMethod
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk to a method defined at the offset in the instruction list of the current method.
|
||||
*
|
||||
* The current method will be mutable.
|
||||
*
|
||||
* @param offset The offset of the instruction. This instruction must be of format 35c.
|
||||
* @param walkMutable If this is true, the class of the method will be resolved mutably.
|
||||
* @return The same [MethodWalker] instance with the method at [offset].
|
||||
*/
|
||||
fun nextMethod(
|
||||
offset: Int,
|
||||
walkMutable: Boolean = false,
|
||||
): MethodWalker {
|
||||
currentMethod.implementation?.instructions?.let { instructions ->
|
||||
val instruction = instructions.elementAt(offset)
|
||||
|
||||
val newMethod = (instruction as ReferenceInstruction).reference as MethodReference
|
||||
val proxy = bytecodeContext.findClass(newMethod.definingClass)!!
|
||||
|
||||
val methods = if (walkMutable) proxy.mutableClass.methods else proxy.immutableClass.methods
|
||||
currentMethod =
|
||||
methods.first {
|
||||
return@first MethodUtil.methodSignaturesMatch(it, newMethod)
|
||||
}
|
||||
return this
|
||||
}
|
||||
throw MethodNotFoundException("This method can not be walked at offset $offset inside the method ${currentMethod.name}")
|
||||
}
|
||||
|
||||
internal class MethodNotFoundException(exception: String) : Exception(exception)
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package app.revanced.patcher.util.proxy
|
||||
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||
|
||||
/**
|
||||
* A proxy class for a [ClassDef].
|
||||
*
|
||||
* A class proxy simply holds a reference to the original class
|
||||
* and allocates a mutable clone for the original class if needed.
|
||||
* @param immutableClass The class to proxy.
|
||||
*/
|
||||
class ClassProxy internal constructor(
|
||||
val immutableClass: ClassDef,
|
||||
) {
|
||||
/**
|
||||
* Weather the proxy was actually used.
|
||||
*/
|
||||
internal var resolved = false
|
||||
|
||||
/**
|
||||
* The mutable clone of the original class.
|
||||
*
|
||||
* Note: This is only allocated if the proxy is actually used.
|
||||
*/
|
||||
val mutableClass by lazy {
|
||||
resolved = true
|
||||
if (immutableClass is MutableClass) {
|
||||
immutableClass
|
||||
} else {
|
||||
MutableClass(immutableClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package app.revanced.patcher.util.proxy.mutableTypes
|
||||
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableAnnotationElement.Companion.toMutable
|
||||
import com.android.tools.smali.dexlib2.base.BaseAnnotation
|
||||
import com.android.tools.smali.dexlib2.iface.Annotation
|
||||
|
||||
class MutableAnnotation(annotation: Annotation) : BaseAnnotation() {
|
||||
private val visibility = annotation.visibility
|
||||
private val type = annotation.type
|
||||
private val _elements by lazy { annotation.elements.map { element -> element.toMutable() }.toMutableSet() }
|
||||
|
||||
override fun getType(): String {
|
||||
return type
|
||||
}
|
||||
|
||||
override fun getElements(): MutableSet<MutableAnnotationElement> {
|
||||
return _elements
|
||||
}
|
||||
|
||||
override fun getVisibility(): Int {
|
||||
return visibility
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun Annotation.toMutable(): MutableAnnotation {
|
||||
return MutableAnnotation(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package app.revanced.patcher.util.proxy.mutableTypes
|
||||
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.encodedValue.MutableEncodedValue
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.encodedValue.MutableEncodedValue.Companion.toMutable
|
||||
import com.android.tools.smali.dexlib2.base.BaseAnnotationElement
|
||||
import com.android.tools.smali.dexlib2.iface.AnnotationElement
|
||||
import com.android.tools.smali.dexlib2.iface.value.EncodedValue
|
||||
|
||||
class MutableAnnotationElement(annotationElement: AnnotationElement) : BaseAnnotationElement() {
|
||||
private var name = annotationElement.name
|
||||
private var value = annotationElement.value.toMutable()
|
||||
|
||||
fun setName(name: String) {
|
||||
this.name = name
|
||||
}
|
||||
|
||||
fun setValue(value: MutableEncodedValue) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
override fun getName(): String {
|
||||
return name
|
||||
}
|
||||
|
||||
override fun getValue(): EncodedValue {
|
||||
return value
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun AnnotationElement.toMutable(): MutableAnnotationElement {
|
||||
return MutableAnnotationElement(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
package app.revanced.patcher.util.proxy.mutableTypes
|
||||
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableAnnotation.Companion.toMutable
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||
import com.android.tools.smali.dexlib2.base.reference.BaseTypeReference
|
||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||
import com.android.tools.smali.dexlib2.util.FieldUtil
|
||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
import com.google.common.collect.Iterables
|
||||
|
||||
class MutableClass(classDef: ClassDef) : ClassDef, BaseTypeReference() {
|
||||
// Class
|
||||
private var type = classDef.type
|
||||
private var sourceFile = classDef.sourceFile
|
||||
private var accessFlags = classDef.accessFlags
|
||||
private var superclass = classDef.superclass
|
||||
|
||||
private val _interfaces by lazy { classDef.interfaces.toMutableList() }
|
||||
private val _annotations by lazy {
|
||||
classDef.annotations.map { annotation -> annotation.toMutable() }.toMutableSet()
|
||||
}
|
||||
|
||||
// Methods
|
||||
private val _methods by lazy { classDef.methods.map { method -> method.toMutable() }.toMutableSet() }
|
||||
private val _directMethods by lazy { Iterables.filter(_methods, MethodUtil.METHOD_IS_DIRECT).toMutableSet() }
|
||||
private val _virtualMethods by lazy { Iterables.filter(_methods, MethodUtil.METHOD_IS_VIRTUAL).toMutableSet() }
|
||||
|
||||
// Fields
|
||||
private val _fields by lazy { classDef.fields.map { field -> field.toMutable() }.toMutableSet() }
|
||||
private val _staticFields by lazy { Iterables.filter(_fields, FieldUtil.FIELD_IS_STATIC).toMutableSet() }
|
||||
private val _instanceFields by lazy { Iterables.filter(_fields, FieldUtil.FIELD_IS_INSTANCE).toMutableSet() }
|
||||
|
||||
fun setType(type: String) {
|
||||
this.type = type
|
||||
}
|
||||
|
||||
fun setSourceFile(sourceFile: String?) {
|
||||
this.sourceFile = sourceFile
|
||||
}
|
||||
|
||||
fun setAccessFlags(accessFlags: Int) {
|
||||
this.accessFlags = accessFlags
|
||||
}
|
||||
|
||||
fun setSuperClass(superclass: String?) {
|
||||
this.superclass = superclass
|
||||
}
|
||||
|
||||
override fun getType(): String {
|
||||
return type
|
||||
}
|
||||
|
||||
override fun getAccessFlags(): Int {
|
||||
return accessFlags
|
||||
}
|
||||
|
||||
override fun getSourceFile(): String? {
|
||||
return sourceFile
|
||||
}
|
||||
|
||||
override fun getSuperclass(): String? {
|
||||
return superclass
|
||||
}
|
||||
|
||||
override fun getInterfaces(): MutableList<String> {
|
||||
return _interfaces
|
||||
}
|
||||
|
||||
override fun getAnnotations(): MutableSet<MutableAnnotation> {
|
||||
return _annotations
|
||||
}
|
||||
|
||||
override fun getStaticFields(): MutableSet<MutableField> {
|
||||
return _staticFields
|
||||
}
|
||||
|
||||
override fun getInstanceFields(): MutableSet<MutableField> {
|
||||
return _instanceFields
|
||||
}
|
||||
|
||||
override fun getFields(): MutableSet<MutableField> {
|
||||
return _fields
|
||||
}
|
||||
|
||||
override fun getDirectMethods(): MutableSet<MutableMethod> {
|
||||
return _directMethods
|
||||
}
|
||||
|
||||
override fun getVirtualMethods(): MutableSet<MutableMethod> {
|
||||
return _virtualMethods
|
||||
}
|
||||
|
||||
override fun getMethods(): MutableSet<MutableMethod> {
|
||||
return _methods
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun ClassDef.toMutable(): MutableClass {
|
||||
return MutableClass(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package app.revanced.patcher.util.proxy.mutableTypes
|
||||
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableAnnotation.Companion.toMutable
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.encodedValue.MutableEncodedValue
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.encodedValue.MutableEncodedValue.Companion.toMutable
|
||||
import com.android.tools.smali.dexlib2.HiddenApiRestriction
|
||||
import com.android.tools.smali.dexlib2.base.reference.BaseFieldReference
|
||||
import com.android.tools.smali.dexlib2.iface.Field
|
||||
|
||||
class MutableField(field: Field) : Field, BaseFieldReference() {
|
||||
private var definingClass = field.definingClass
|
||||
private var name = field.name
|
||||
private var type = field.type
|
||||
private var accessFlags = field.accessFlags
|
||||
|
||||
private var initialValue = field.initialValue?.toMutable()
|
||||
private val _annotations by lazy { field.annotations.map { annotation -> annotation.toMutable() }.toMutableSet() }
|
||||
private val _hiddenApiRestrictions by lazy { field.hiddenApiRestrictions }
|
||||
|
||||
fun setDefiningClass(definingClass: String) {
|
||||
this.definingClass = definingClass
|
||||
}
|
||||
|
||||
fun setName(name: String) {
|
||||
this.name = name
|
||||
}
|
||||
|
||||
fun setType(type: String) {
|
||||
this.type = type
|
||||
}
|
||||
|
||||
fun setAccessFlags(accessFlags: Int) {
|
||||
this.accessFlags = accessFlags
|
||||
}
|
||||
|
||||
fun setInitialValue(initialValue: MutableEncodedValue?) {
|
||||
this.initialValue = initialValue
|
||||
}
|
||||
|
||||
override fun getDefiningClass(): String {
|
||||
return this.definingClass
|
||||
}
|
||||
|
||||
override fun getName(): String {
|
||||
return this.name
|
||||
}
|
||||
|
||||
override fun getType(): String {
|
||||
return this.type
|
||||
}
|
||||
|
||||
override fun getAnnotations(): MutableSet<MutableAnnotation> {
|
||||
return this._annotations
|
||||
}
|
||||
|
||||
override fun getAccessFlags(): Int {
|
||||
return this.accessFlags
|
||||
}
|
||||
|
||||
override fun getHiddenApiRestrictions(): MutableSet<HiddenApiRestriction> {
|
||||
return this._hiddenApiRestrictions
|
||||
}
|
||||
|
||||
override fun getInitialValue(): MutableEncodedValue? {
|
||||
return this.initialValue
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun Field.toMutable(): MutableField {
|
||||
return MutableField(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
package app.revanced.patcher.util.proxy.mutableTypes
|
||||
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableAnnotation.Companion.toMutable
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethodParameter.Companion.toMutable
|
||||
import com.android.tools.smali.dexlib2.HiddenApiRestriction
|
||||
import com.android.tools.smali.dexlib2.base.reference.BaseMethodReference
|
||||
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
|
||||
class MutableMethod(method: Method) : Method, BaseMethodReference() {
|
||||
private var definingClass = method.definingClass
|
||||
private var name = method.name
|
||||
private var accessFlags = method.accessFlags
|
||||
private var returnType = method.returnType
|
||||
|
||||
// Create own mutable MethodImplementation (due to not being able to change members like register count)
|
||||
private val _implementation by lazy { method.implementation?.let { MutableMethodImplementation(it) } }
|
||||
private val _annotations by lazy { method.annotations.map { annotation -> annotation.toMutable() }.toMutableSet() }
|
||||
private val _parameters by lazy { method.parameters.map { parameter -> parameter.toMutable() }.toMutableList() }
|
||||
private val _parameterTypes by lazy { method.parameterTypes.toMutableList() }
|
||||
private val _hiddenApiRestrictions by lazy { method.hiddenApiRestrictions }
|
||||
|
||||
fun setDefiningClass(definingClass: String) {
|
||||
this.definingClass = definingClass
|
||||
}
|
||||
|
||||
fun setName(name: String) {
|
||||
this.name = name
|
||||
}
|
||||
|
||||
fun setAccessFlags(accessFlags: Int) {
|
||||
this.accessFlags = accessFlags
|
||||
}
|
||||
|
||||
fun setReturnType(returnType: String) {
|
||||
this.returnType = returnType
|
||||
}
|
||||
|
||||
override fun getDefiningClass(): String {
|
||||
return definingClass
|
||||
}
|
||||
|
||||
override fun getName(): String {
|
||||
return name
|
||||
}
|
||||
|
||||
override fun getParameterTypes(): MutableList<CharSequence> {
|
||||
return _parameterTypes
|
||||
}
|
||||
|
||||
override fun getReturnType(): String {
|
||||
return returnType
|
||||
}
|
||||
|
||||
override fun getAnnotations(): MutableSet<MutableAnnotation> {
|
||||
return _annotations
|
||||
}
|
||||
|
||||
override fun getAccessFlags(): Int {
|
||||
return accessFlags
|
||||
}
|
||||
|
||||
override fun getHiddenApiRestrictions(): MutableSet<HiddenApiRestriction> {
|
||||
return _hiddenApiRestrictions
|
||||
}
|
||||
|
||||
override fun getParameters(): MutableList<MutableMethodParameter> {
|
||||
return _parameters
|
||||
}
|
||||
|
||||
override fun getImplementation(): MutableMethodImplementation? {
|
||||
return _implementation
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun Method.toMutable(): MutableMethod {
|
||||
return MutableMethod(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package app.revanced.patcher.util.proxy.mutableTypes
|
||||
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableAnnotation.Companion.toMutable
|
||||
import com.android.tools.smali.dexlib2.base.BaseMethodParameter
|
||||
import com.android.tools.smali.dexlib2.iface.MethodParameter
|
||||
|
||||
// TODO: finish overriding all members if necessary
|
||||
class MutableMethodParameter(parameter: MethodParameter) : MethodParameter, BaseMethodParameter() {
|
||||
private var type = parameter.type
|
||||
private var name = parameter.name
|
||||
private var signature = parameter.signature
|
||||
private val _annotations by lazy {
|
||||
parameter.annotations.map { annotation -> annotation.toMutable() }.toMutableSet()
|
||||
}
|
||||
|
||||
override fun getType(): String {
|
||||
return type
|
||||
}
|
||||
|
||||
override fun getName(): String? {
|
||||
return name
|
||||
}
|
||||
|
||||
override fun getSignature(): String? {
|
||||
return signature
|
||||
}
|
||||
|
||||
override fun getAnnotations(): MutableSet<MutableAnnotation> {
|
||||
return _annotations
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun MethodParameter.toMutable(): MutableMethodParameter {
|
||||
return MutableMethodParameter(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
||||
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableAnnotationElement.Companion.toMutable
|
||||
import com.android.tools.smali.dexlib2.base.value.BaseAnnotationEncodedValue
|
||||
import com.android.tools.smali.dexlib2.iface.AnnotationElement
|
||||
import com.android.tools.smali.dexlib2.iface.value.AnnotationEncodedValue
|
||||
|
||||
class MutableAnnotationEncodedValue(annotationEncodedValue: AnnotationEncodedValue) :
|
||||
BaseAnnotationEncodedValue(),
|
||||
MutableEncodedValue {
|
||||
private var type = annotationEncodedValue.type
|
||||
|
||||
private val _elements by lazy {
|
||||
annotationEncodedValue.elements.map { annotationElement -> annotationElement.toMutable() }.toMutableSet()
|
||||
}
|
||||
|
||||
override fun getType(): String {
|
||||
return this.type
|
||||
}
|
||||
|
||||
fun setType(type: String) {
|
||||
this.type = type
|
||||
}
|
||||
|
||||
override fun getElements(): MutableSet<out AnnotationElement> {
|
||||
return _elements
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun AnnotationEncodedValue.toMutable(): MutableAnnotationEncodedValue {
|
||||
return MutableAnnotationEncodedValue(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
||||
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.encodedValue.MutableEncodedValue.Companion.toMutable
|
||||
import com.android.tools.smali.dexlib2.base.value.BaseArrayEncodedValue
|
||||
import com.android.tools.smali.dexlib2.iface.value.ArrayEncodedValue
|
||||
import com.android.tools.smali.dexlib2.iface.value.EncodedValue
|
||||
|
||||
class MutableArrayEncodedValue(arrayEncodedValue: ArrayEncodedValue) : BaseArrayEncodedValue(), MutableEncodedValue {
|
||||
private val _value by lazy {
|
||||
arrayEncodedValue.value.map { encodedValue -> encodedValue.toMutable() }.toMutableList()
|
||||
}
|
||||
|
||||
override fun getValue(): MutableList<out EncodedValue> {
|
||||
return _value
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun ArrayEncodedValue.toMutable(): MutableArrayEncodedValue {
|
||||
return MutableArrayEncodedValue(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
||||
|
||||
import com.android.tools.smali.dexlib2.base.value.BaseBooleanEncodedValue
|
||||
import com.android.tools.smali.dexlib2.iface.value.BooleanEncodedValue
|
||||
|
||||
class MutableBooleanEncodedValue(booleanEncodedValue: BooleanEncodedValue) :
|
||||
BaseBooleanEncodedValue(),
|
||||
MutableEncodedValue {
|
||||
private var value = booleanEncodedValue.value
|
||||
|
||||
override fun getValue(): Boolean {
|
||||
return this.value
|
||||
}
|
||||
|
||||
fun setValue(value: Boolean) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun BooleanEncodedValue.toMutable(): MutableBooleanEncodedValue {
|
||||
return MutableBooleanEncodedValue(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
||||
|
||||
import com.android.tools.smali.dexlib2.base.value.BaseByteEncodedValue
|
||||
import com.android.tools.smali.dexlib2.iface.value.ByteEncodedValue
|
||||
|
||||
class MutableByteEncodedValue(byteEncodedValue: ByteEncodedValue) : BaseByteEncodedValue(), MutableEncodedValue {
|
||||
private var value = byteEncodedValue.value
|
||||
|
||||
override fun getValue(): Byte {
|
||||
return this.value
|
||||
}
|
||||
|
||||
fun setValue(value: Byte) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun ByteEncodedValue.toMutable(): MutableByteEncodedValue {
|
||||
return MutableByteEncodedValue(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
||||
|
||||
import com.android.tools.smali.dexlib2.base.value.BaseCharEncodedValue
|
||||
import com.android.tools.smali.dexlib2.iface.value.CharEncodedValue
|
||||
|
||||
class MutableCharEncodedValue(charEncodedValue: CharEncodedValue) : BaseCharEncodedValue(), MutableEncodedValue {
|
||||
private var value = charEncodedValue.value
|
||||
|
||||
override fun getValue(): Char {
|
||||
return this.value
|
||||
}
|
||||
|
||||
fun setValue(value: Char) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun CharEncodedValue.toMutable(): MutableCharEncodedValue {
|
||||
return MutableCharEncodedValue(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
||||
|
||||
import com.android.tools.smali.dexlib2.base.value.BaseDoubleEncodedValue
|
||||
import com.android.tools.smali.dexlib2.iface.value.DoubleEncodedValue
|
||||
|
||||
class MutableDoubleEncodedValue(doubleEncodedValue: DoubleEncodedValue) :
|
||||
BaseDoubleEncodedValue(),
|
||||
MutableEncodedValue {
|
||||
private var value = doubleEncodedValue.value
|
||||
|
||||
override fun getValue(): Double {
|
||||
return this.value
|
||||
}
|
||||
|
||||
fun setValue(value: Double) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun DoubleEncodedValue.toMutable(): MutableDoubleEncodedValue {
|
||||
return MutableDoubleEncodedValue(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
||||
|
||||
import com.android.tools.smali.dexlib2.ValueType
|
||||
import com.android.tools.smali.dexlib2.iface.value.*
|
||||
|
||||
interface MutableEncodedValue : EncodedValue {
|
||||
companion object {
|
||||
fun EncodedValue.toMutable(): MutableEncodedValue {
|
||||
return when (this.valueType) {
|
||||
ValueType.TYPE -> MutableTypeEncodedValue(this as TypeEncodedValue)
|
||||
ValueType.FIELD -> MutableFieldEncodedValue(this as FieldEncodedValue)
|
||||
ValueType.METHOD -> MutableMethodEncodedValue(this as MethodEncodedValue)
|
||||
ValueType.ENUM -> MutableEnumEncodedValue(this as EnumEncodedValue)
|
||||
ValueType.ARRAY -> MutableArrayEncodedValue(this as ArrayEncodedValue)
|
||||
ValueType.ANNOTATION -> MutableAnnotationEncodedValue(this as AnnotationEncodedValue)
|
||||
ValueType.BYTE -> MutableByteEncodedValue(this as ByteEncodedValue)
|
||||
ValueType.SHORT -> MutableShortEncodedValue(this as ShortEncodedValue)
|
||||
ValueType.CHAR -> MutableCharEncodedValue(this as CharEncodedValue)
|
||||
ValueType.INT -> MutableIntEncodedValue(this as IntEncodedValue)
|
||||
ValueType.LONG -> MutableLongEncodedValue(this as LongEncodedValue)
|
||||
ValueType.FLOAT -> MutableFloatEncodedValue(this as FloatEncodedValue)
|
||||
ValueType.DOUBLE -> MutableDoubleEncodedValue(this as DoubleEncodedValue)
|
||||
ValueType.METHOD_TYPE -> MutableMethodTypeEncodedValue(this as MethodTypeEncodedValue)
|
||||
ValueType.METHOD_HANDLE -> MutableMethodHandleEncodedValue(this as MethodHandleEncodedValue)
|
||||
ValueType.STRING -> MutableStringEncodedValue(this as StringEncodedValue)
|
||||
ValueType.BOOLEAN -> MutableBooleanEncodedValue(this as BooleanEncodedValue)
|
||||
ValueType.NULL -> MutableNullEncodedValue()
|
||||
else -> this as MutableEncodedValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
||||
|
||||
import com.android.tools.smali.dexlib2.base.value.BaseEnumEncodedValue
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
import com.android.tools.smali.dexlib2.iface.value.EnumEncodedValue
|
||||
|
||||
class MutableEnumEncodedValue(enumEncodedValue: EnumEncodedValue) : BaseEnumEncodedValue(), MutableEncodedValue {
|
||||
private var value = enumEncodedValue.value
|
||||
|
||||
override fun getValue(): FieldReference {
|
||||
return this.value
|
||||
}
|
||||
|
||||
fun setValue(value: FieldReference) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun EnumEncodedValue.toMutable(): MutableEnumEncodedValue {
|
||||
return MutableEnumEncodedValue(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
||||
|
||||
import com.android.tools.smali.dexlib2.ValueType
|
||||
import com.android.tools.smali.dexlib2.base.value.BaseFieldEncodedValue
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
import com.android.tools.smali.dexlib2.iface.value.FieldEncodedValue
|
||||
|
||||
class MutableFieldEncodedValue(fieldEncodedValue: FieldEncodedValue) : BaseFieldEncodedValue(), MutableEncodedValue {
|
||||
private var value = fieldEncodedValue.value
|
||||
|
||||
override fun getValueType(): Int {
|
||||
return ValueType.FIELD
|
||||
}
|
||||
|
||||
override fun getValue(): FieldReference {
|
||||
return this.value
|
||||
}
|
||||
|
||||
fun setValue(value: FieldReference) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun FieldEncodedValue.toMutable(): MutableFieldEncodedValue {
|
||||
return MutableFieldEncodedValue(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
||||
|
||||
import com.android.tools.smali.dexlib2.base.value.BaseFloatEncodedValue
|
||||
import com.android.tools.smali.dexlib2.iface.value.FloatEncodedValue
|
||||
|
||||
class MutableFloatEncodedValue(floatEncodedValue: FloatEncodedValue) : BaseFloatEncodedValue(), MutableEncodedValue {
|
||||
private var value = floatEncodedValue.value
|
||||
|
||||
override fun getValue(): Float {
|
||||
return this.value
|
||||
}
|
||||
|
||||
fun setValue(value: Float) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun FloatEncodedValue.toMutable(): MutableFloatEncodedValue {
|
||||
return MutableFloatEncodedValue(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
||||
|
||||
import com.android.tools.smali.dexlib2.base.value.BaseIntEncodedValue
|
||||
import com.android.tools.smali.dexlib2.iface.value.IntEncodedValue
|
||||
|
||||
class MutableIntEncodedValue(intEncodedValue: IntEncodedValue) : BaseIntEncodedValue(), MutableEncodedValue {
|
||||
private var value = intEncodedValue.value
|
||||
|
||||
override fun getValue(): Int {
|
||||
return this.value
|
||||
}
|
||||
|
||||
fun setValue(value: Int) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun IntEncodedValue.toMutable(): MutableIntEncodedValue {
|
||||
return MutableIntEncodedValue(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
||||
|
||||
import com.android.tools.smali.dexlib2.base.value.BaseLongEncodedValue
|
||||
import com.android.tools.smali.dexlib2.iface.value.LongEncodedValue
|
||||
|
||||
class MutableLongEncodedValue(longEncodedValue: LongEncodedValue) : BaseLongEncodedValue(), MutableEncodedValue {
|
||||
private var value = longEncodedValue.value
|
||||
|
||||
override fun getValue(): Long {
|
||||
return this.value
|
||||
}
|
||||
|
||||
fun setValue(value: Long) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun LongEncodedValue.toMutable(): MutableLongEncodedValue {
|
||||
return MutableLongEncodedValue(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
||||
|
||||
import com.android.tools.smali.dexlib2.base.value.BaseMethodEncodedValue
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import com.android.tools.smali.dexlib2.iface.value.MethodEncodedValue
|
||||
|
||||
class MutableMethodEncodedValue(methodEncodedValue: MethodEncodedValue) :
|
||||
BaseMethodEncodedValue(),
|
||||
MutableEncodedValue {
|
||||
private var value = methodEncodedValue.value
|
||||
|
||||
override fun getValue(): MethodReference {
|
||||
return this.value
|
||||
}
|
||||
|
||||
fun setValue(value: MethodReference) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun MethodEncodedValue.toMutable(): MutableMethodEncodedValue {
|
||||
return MutableMethodEncodedValue(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
|
||||
|
||||
import com.android.tools.smali.dexlib2.base.value.BaseMethodHandleEncodedValue
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodHandleReference
|
||||
import com.android.tools.smali.dexlib2.iface.value.MethodHandleEncodedValue
|
||||
|
||||
class MutableMethodHandleEncodedValue(methodHandleEncodedValue: MethodHandleEncodedValue) :
|
||||
BaseMethodHandleEncodedValue(),
|
||||
MutableEncodedValue {
|
||||
private var value = methodHandleEncodedValue.value
|
||||
|
||||
override fun getValue(): MethodHandleReference {
|
||||
return this.value
|
||||
}
|
||||
|
||||
fun setValue(value: MethodHandleReference) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun MethodHandleEncodedValue.toMutable(): MutableMethodHandleEncodedValue {
|
||||
return MutableMethodHandleEncodedValue(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user