Compare commits

..

652 Commits

Author SHA1 Message Date
semantic-release-bot
86db64edff chore(release): 14.2.0-dev.2 [skip ci]
# [14.2.0-dev.2](https://github.com/ReVanced/revanced-patcher/compare/v14.2.0-dev.1...v14.2.0-dev.2) (2023-08-26)

### Features

* log when merging integrations ([983563e](983563efb6))
2023-08-26 17:16:08 +00:00
oSumAtrIX
983563efb6 feat: log when merging integrations 2023-08-26 19:14:29 +02:00
oSumAtrIX
37abb2db99 build: package the Java sources 2023-08-26 19:10:29 +02:00
semantic-release-bot
5ba0b47e60 chore(release): 14.2.0-dev.1 [skip ci]
# [14.2.0-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v14.1.0...v14.2.0-dev.1) (2023-08-25)

### Features

* load patches in lexicographical order ([e8f2087](e8f2087a6f))
2023-08-25 15:12:46 +00:00
oSumAtrIX
e8f2087a6f feat: load patches in lexicographical order
This feature was lost in past commits
2023-08-25 17:10:44 +02:00
semantic-release-bot
6ce99f5cdf chore(release): 14.1.0 [skip ci]
# [14.1.0](https://github.com/ReVanced/revanced-patcher/compare/v14.0.0...v14.1.0) (2023-08-24)

### Bug Fixes

* move version properties file to correct package ([e985676](e985676c2d))

### Features

* properly make use of logging facade ([ba56a6a](ba56a6a2ee))
2023-08-24 02:50:15 +00:00
oSumAtrIX
13c0c9cdd3 chore: merge branch dev to main (#220) 2023-08-24 04:48:39 +02:00
semantic-release-bot
58ffdb60d7 chore(release): 14.1.0-dev.1 [skip ci]
# [14.1.0-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v14.0.1-dev.1...v14.1.0-dev.1) (2023-08-24)

### Features

* properly make use of logging facade ([ba56a6a](ba56a6a2ee))
2023-08-24 02:45:16 +00:00
oSumAtrIX
ba56a6a2ee feat: properly make use of logging facade
This deprecates the primary constructor of `PatcherOptions` with the `logger` parameter
2023-08-24 04:43:16 +02:00
oSumAtrIX
ccccf5b1d2 build: migrate dependencies to version catalogs 2023-08-23 04:30:31 +02:00
semantic-release-bot
b507ac0a54 chore(release): 14.0.1-dev.1 [skip ci]
## [14.0.1-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v14.0.0...v14.0.1-dev.1) (2023-08-23)

### Bug Fixes

* move version properties file to correct package ([e985676](e985676c2d))
2023-08-23 01:39:26 +00:00
oSumAtrIX
e985676c2d fix: move version properties file to correct package 2023-08-23 03:36:48 +02:00
oSumAtrIX
f7f4ba6c55 build: update dependencies 2023-08-23 03:36:48 +02:00
semantic-release-bot
4292f43814 chore(release): 14.0.0 [skip ci]
# [14.0.0](https://github.com/ReVanced/revanced-patcher/compare/v13.0.0...v14.0.0) (2023-08-22)

### Bug Fixes

* log decoding resources after logging deleting resource cache directory ([db62a16](db62a1607b))
* only emit closed patches that did not throw an exception with the `@Patch` annotation ([5938f6b](5938f6b7ea))
* supply the parent classloader to `DexClassLoader` ([0f15077](0f15077225))

### Code Refactoring

* improve structure and public API ([6b8977f](6b8977f178))

### Features

* do not log instantiation of ReVanced Patcher ([273dd8d](273dd8d388))

### BREAKING CHANGES

* Various public APIs have been changed. The `Version` annotation has been removed. Patches do not return anything anymore and instead throw `PatchException`. Multiple patch bundles can now be loaded in a single ClassLoader to bypass class loader isolation.
2023-08-22 17:16:51 +00:00
oSumAtrIX
30bd4fd9fe chore: merge branch dev to main (#217) 2023-08-22 19:15:09 +02:00
semantic-release-bot
76de39369d chore(release): 14.0.0-dev.4 [skip ci]
# [14.0.0-dev.4](https://github.com/ReVanced/revanced-patcher/compare/v14.0.0-dev.3...v14.0.0-dev.4) (2023-08-22)

### Bug Fixes

* only emit closed patches that did not throw an exception with the `@Patch` annotation ([5938f6b](5938f6b7ea))
2023-08-22 17:04:25 +00:00
oSumAtrIX
88a703ce36 build: bump dependencies 2023-08-22 19:01:59 +02:00
oSumAtrIX
5938f6b7ea fix: only emit closed patches that did not throw an exception with the @Patch annotation 2023-08-22 19:00:34 +02:00
semantic-release-bot
5c0c0d6c37 chore(release): 14.0.0-dev.3 [skip ci]
# [14.0.0-dev.3](https://github.com/ReVanced/revanced-patcher/compare/v14.0.0-dev.2...v14.0.0-dev.3) (2023-08-20)

### Bug Fixes

* supply the parent classloader to `DexClassLoader` ([0f15077](0f15077225))

### Features

* do not log instantiation of ReVanced Patcher ([273dd8d](273dd8d388))
2023-08-20 17:16:00 +00:00
oSumAtrIX
0f15077225 fix: supply the parent classloader to DexClassLoader 2023-08-20 19:14:10 +02:00
oSumAtrIX
273dd8d388 feat: do not log instantiation of ReVanced Patcher 2023-08-20 19:14:09 +02:00
semantic-release-bot
1795f376ef chore(release): 14.0.0-dev.2 [skip ci]
# [14.0.0-dev.2](https://github.com/ReVanced/revanced-patcher/compare/v14.0.0-dev.1...v14.0.0-dev.2) (2023-08-19)
2023-08-19 15:26:18 +00:00
oSumAtrIX
e7360a7692 build(Needs bump): Bump dependencies
This fixes an issue with a library not working on Android
2023-08-19 17:23:31 +02:00
semantic-release-bot
e1fc86934f chore(release): 14.0.0-dev.1 [skip ci]
# [14.0.0-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v13.0.0...v14.0.0-dev.1) (2023-08-18)

### Bug Fixes

* log decoding resources after logging deleting resource cache directory ([db62a16](db62a1607b))

### Code Refactoring

* improve structure and public API ([6b8977f](6b8977f178))

### BREAKING CHANGES

* Various public APIs have been changed. The `Version` annotation has been removed. Patches do not return anything anymore and instead throw `PatchException`. Multiple patch bundles can now be loaded in a single ClassLoader to bypass class loader isolation.
2023-08-18 23:47:18 +00:00
oSumAtrIX
6b8977f178 refactor: improve structure and public API
This commit introduces a couple changes besides the refactor. Executing patches can be cancelled, multiple bundles loaded into the same class loader and `Patch.execute` does not have to return anymore.

BREAKING CHANGE: Various public APIs have been changed. The `Version` annotation has been removed. Patches do not return anything anymore and instead throw `PatchException`. Multiple patch bundles can now be loaded in a single ClassLoader to bypass class loader isolation.
2023-08-19 01:45:27 +02:00
oSumAtrIX
12c6c73de0 build: add mavenLocal to repositories 2023-08-16 16:53:47 +02:00
oSumAtrIX
db62a1607b fix: log decoding resources after logging deleting resource cache directory 2023-08-16 16:53:45 +02:00
semantic-release-bot
58bb879ef5 chore(release): 13.0.0 [skip ci]
# [13.0.0](https://github.com/ReVanced/revanced-patcher/compare/v12.1.1...v13.0.0) (2023-08-14)

### Bug Fixes

* decode in correct order ([8fb2f2d](8fb2f2dc1d))
* disable correct loggers ([c2d89c6](c2d89c622e))
* get framework ids to compile resources ([f2cb7ee](f2cb7ee7df))
* only enable logging for ReVanced ([783ccf8](783ccf8529))
* set package metadata correctly ([02d6ff1](02d6ff15fe))

* build(Needs bump)!: Bump dependencies ([d5f89a9](d5f89a903f))

### BREAKING CHANGES

* This bump updates smali, a crucial dependency
2023-08-14 02:11:55 +00:00
oSumAtrIX
254912438a chore: merge branch dev to main (#213) 2023-08-14 04:10:17 +02:00
semantic-release-bot
0e48918bcc chore(release): 13.0.0-dev.3 [skip ci]
# [13.0.0-dev.3](https://github.com/ReVanced/revanced-patcher/compare/v13.0.0-dev.2...v13.0.0-dev.3) (2023-08-14)

### Bug Fixes

* decode in correct order ([8fb2f2d](8fb2f2dc1d))
* only enable logging for ReVanced ([783ccf8](783ccf8529))
2023-08-14 02:04:54 +00:00
oSumAtrIX
783ccf8529 fix: only enable logging for ReVanced 2023-08-14 04:02:39 +02:00
oSumAtrIX
8fb2f2dc1d fix: decode in correct order 2023-08-14 04:02:24 +02:00
semantic-release-bot
2a8cc283c7 chore(release): 13.0.0-dev.2 [skip ci]
# [13.0.0-dev.2](https://github.com/ReVanced/revanced-patcher/compare/v13.0.0-dev.1...v13.0.0-dev.2) (2023-08-12)

### Bug Fixes

* disable correct loggers ([c2d89c6](c2d89c622e))
* get framework ids to compile resources ([f2cb7ee](f2cb7ee7df))
* set package metadata correctly ([02d6ff1](02d6ff15fe))
2023-08-12 00:25:18 +00:00
oSumAtrIX
433fe3af9f build(Needs bump): Bump dependencies 2023-08-12 02:23:03 +02:00
oSumAtrIX
c2d89c622e fix: disable correct loggers 2023-08-12 02:22:52 +02:00
oSumAtrIX
02d6ff15fe fix: set package metadata correctly 2023-08-12 02:19:28 +02:00
oSumAtrIX
f2cb7ee7df fix: get framework ids to compile resources 2023-08-12 02:18:43 +02:00
oSumAtrIX
a2ac44dcc1 chore: use more generic inline docs 2023-08-12 02:15:26 +02:00
semantic-release-bot
3cf9d74efa chore(release): 13.0.0-dev.1 [skip ci]
# [13.0.0-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v12.1.1...v13.0.0-dev.1) (2023-08-11)

* build(Needs bump)!: Bump dependencies ([d5f89a9](d5f89a903f))

### BREAKING CHANGES

* This bump updates smali, a crucial dependency
2023-08-11 00:53:46 +00:00
oSumAtrIX
d5f89a903f build(Needs bump)!: Bump dependencies
BREAKING CHANGE: This bump updates smali, a crucial dependency
2023-08-11 02:51:37 +02:00
semantic-release-bot
496c2242bc chore(release): 12.1.1 [skip ci]
## [12.1.1](https://github.com/ReVanced/revanced-patcher/compare/v12.1.0...v12.1.1) (2023-08-03)

### Bug Fixes

* clear method lookup maps before initializing them ([#210](https://github.com/ReVanced/revanced-patcher/issues/210)) ([746544f](746544f9d5))
2023-08-03 18:34:22 +00:00
oSumAtrIX
98fbff87df chore: merge branch dev to main (#211) 2023-08-03 20:32:45 +02:00
semantic-release-bot
ddb51a1c45 chore(release): 12.1.1-dev.2 [skip ci]
## [12.1.1-dev.2](https://github.com/ReVanced/revanced-patcher/compare/v12.1.1-dev.1...v12.1.1-dev.2) (2023-08-03)
2023-08-03 18:16:10 +00:00
oSumAtrIX
8df1155215 build(Needs bump): Bump compatibility 2023-08-03 20:14:01 +02:00
semantic-release-bot
53f2a61409 chore(release): 12.1.1-dev.1 [skip ci]
## [12.1.1-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v12.1.0...v12.1.1-dev.1) (2023-08-03)

### Bug Fixes

* clear method lookup maps before initializing them ([#210](https://github.com/ReVanced/revanced-patcher/issues/210)) ([746544f](746544f9d5))
2023-08-03 11:43:51 +00:00
aAbed
746544f9d5 fix: clear method lookup maps before initializing them (#210)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-08-03 13:42:00 +02:00
semantic-release-bot
c65c3df11c chore(release): 12.1.0 [skip ci]
# [12.1.0](https://github.com/ReVanced/revanced-patcher/compare/v12.0.0...v12.1.0) (2023-08-03)

### Features

* add `MutableMethod.getInstructions` extension function ([fae4029](fae4029cfc))
2023-08-03 02:43:21 +00:00
oSumAtrIX
b29b8f12b3 chore: merge branch dev to main (#209) 2023-08-03 04:18:23 +02:00
semantic-release-bot
d6945677c4 chore(release): 12.1.0-dev.2 [skip ci]
# [12.1.0-dev.2](https://github.com/ReVanced/revanced-patcher/compare/v12.1.0-dev.1...v12.1.0-dev.2) (2023-08-03)
2023-08-03 02:16:55 +00:00
oSumAtrIX
aedf4aea08 build(Needs bump): Update dependencies 2023-08-03 04:15:09 +02:00
semantic-release-bot
dc28d414dc chore(release): 12.1.0-dev.1 [skip ci]
# [12.1.0-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v12.0.0...v12.1.0-dev.1) (2023-08-01)

### Features

* add `MutableMethod.getInstructions` extension function ([fae4029](fae4029cfc))
2023-08-01 22:14:09 +00:00
oSumAtrIX
9755bab298 refactor: remove unnecessary annotation 2023-08-02 00:12:24 +02:00
oSumAtrIX
fae4029cfc feat: add MutableMethod.getInstructions extension function 2023-08-02 00:11:56 +02:00
oSumAtrIX
1790f0d706 ci: Change bumping commit scope 2023-07-30 02:50:41 +02:00
semantic-release-bot
0ba2c51676 chore(release): 12.0.0 [skip ci]
# [12.0.0](https://github.com/ReVanced/revanced-patcher/compare/v11.0.4...v12.0.0) (2023-07-30)

### Bug Fixes

* correct access flags of `PackageMetadata` ([416d691](416d69142f))
* set resource table via resource decoder ([e0f8e1b](e0f8e1b71a))

### Features

* Deprecate `Version` annotation ([c9bbcf2](c9bbcf2bf2))
* remove `Path` option ([#202](https://github.com/ReVanced/revanced-patcher/issues/202)) ([69e4a49](69e4a49065))

### BREAKING CHANGES

* This removes the previously available `Path` option
2023-07-30 00:10:57 +00:00
oSumAtrIX
03cd97b49c chore: merge branch dev to main (#203) 2023-07-30 02:09:12 +02:00
semantic-release-bot
16a162c1dd chore(release): 12.0.0-dev.2 [skip ci]
# [12.0.0-dev.2](https://github.com/ReVanced/revanced-patcher/compare/v12.0.0-dev.1...v12.0.0-dev.2) (2023-07-28)

### Features

* Deprecate `Version` annotation ([400442f](400442f70e))
2023-07-28 20:19:02 +02:00
oSumAtrIX
c9bbcf2bf2 feat: Deprecate Version annotation 2023-07-28 20:19:01 +02:00
semantic-release-bot
86e1bf6078 chore(release): 12.0.0-dev.1 [skip ci]
# [12.0.0-dev.1](https://github.com/ReVanced/revanced-patcher/compare/v11.0.4...v12.0.0-dev.1) (2023-07-26)

### Bug Fixes

* correct access flags of `PackageMetadata` ([416d691](416d69142f))
* set resource table via resource decoder ([e0f8e1b](e0f8e1b71a))

### Features

* remove `Path` option ([#202](https://github.com/ReVanced/revanced-patcher/issues/202)) ([69e4a49](69e4a49065))

### BREAKING CHANGES

* This removes the previously available `Path` option
2023-07-26 04:30:48 +00:00
oSumAtrIX
1bca84ef0b refactor: move code out of try block 2023-07-26 06:28:48 +02:00
oSumAtrIX
e0f8e1b71a fix: set resource table via resource decoder 2023-07-26 06:28:48 +02:00
oSumAtrIX
416d69142f fix: correct access flags of PackageMetadata 2023-07-26 06:28:48 +02:00
oSumAtrIX
426807aeaa refactor: remove unnecessary changes to default config 2023-07-26 06:28:47 +02:00
oSumAtrIX
90cb075a97 build(needs-bump): update dependencies 2023-07-26 06:28:47 +02:00
oSumAtrIX
ac2ca8fbd3 ci: bump on scope needs-bump 2023-07-26 06:28:47 +02:00
Palm
69e4a49065 feat: remove Path option (#202)
BREAKING CHANGE: This removes the previously available `Path` option
2023-07-26 04:11:21 +02:00
oSumAtrIX
a4a030f2b2 build: update gradle 2023-07-06 18:15:40 +02:00
semantic-release-bot
dcc4ecd237 chore(release): 11.0.4 [skip ci]
## [11.0.4](https://github.com/revanced/revanced-patcher/compare/v11.0.3...v11.0.4) (2023-07-01)

### Bug Fixes

* clear method lookup maps ([#198](https://github.com/revanced/revanced-patcher/issues/198)) ([9d81baf](9d81baf4b4))
2023-07-01 00:42:50 +00:00
oSumAtrIX
57f3036a96 chore: merge branch dev to main (#199) 2023-07-01 02:41:21 +02:00
semantic-release-bot
753e55dfc3 chore(release): 11.0.4-dev.1 [skip ci]
## [11.0.4-dev.1](https://github.com/revanced/revanced-patcher/compare/v11.0.3...v11.0.4-dev.1) (2023-07-01)

### Bug Fixes

* clear method lookup maps ([#198](https://github.com/revanced/revanced-patcher/issues/198)) ([9d81baf](9d81baf4b4))
2023-07-01 00:37:30 +00:00
LisoUseInAIKyrios
9d81baf4b4 fix: clear method lookup maps (#198) 2023-07-01 02:35:49 +02:00
semantic-release-bot
7cb4d4c596 chore(release): 11.0.3 [skip ci]
## [11.0.3](https://github.com/revanced/revanced-patcher/compare/v11.0.2...v11.0.3) (2023-06-30)

### Bug Fixes

* NPE on method lookup ([#195](https://github.com/revanced/revanced-patcher/issues/195)) ([fcef434](fcef4342e8))
2023-06-30 23:56:27 +00:00
oSumAtrIX
2c8565508e chore: merge branch dev to main (#196) 2023-07-01 01:54:46 +02:00
semantic-release-bot
c7f156e4c9 chore(release): 11.0.3-dev.1 [skip ci]
## [11.0.3-dev.1](https://github.com/revanced/revanced-patcher/compare/v11.0.2...v11.0.3-dev.1) (2023-06-28)

### Bug Fixes

* NPE on method lookup ([#195](https://github.com/revanced/revanced-patcher/issues/195)) ([fcef434](fcef4342e8))
2023-06-28 19:57:40 +00:00
LisoUseInAIKyrios
fcef4342e8 fix: NPE on method lookup (#195) 2023-06-28 21:56:03 +02:00
semantic-release-bot
72783a5e74 chore(release): 11.0.2 [skip ci]
## [11.0.2](https://github.com/revanced/revanced-patcher/compare/v11.0.1...v11.0.2) (2023-06-27)

### Bug Fixes

* catch exceptions from closing patches ([d5d6f85](d5d6f85084))
* do not load annotations as patches ([519359a](519359a9eb))
* only close succeeded patches ([b8151eb](b8151ebccb))
* use `versionCode` if `versionName` is unavailable ([6e1b647](6e1b6479b6))

### Performance Improvements

* resolve fingerprints using method maps ([#185](https://github.com/revanced/revanced-patcher/issues/185)) ([d718134](d718134ab2))
2023-06-27 02:32:47 +00:00
oSumAtrIX
a379b69eeb chore: merge branch dev to main (#191) 2023-06-27 04:31:09 +02:00
semantic-release-bot
0a8ccba33e chore(release): 11.0.2-dev.4 [skip ci]
## [11.0.2-dev.4](https://github.com/revanced/revanced-patcher/compare/v11.0.2-dev.3...v11.0.2-dev.4) (2023-06-27)

### Bug Fixes

* do not load annotations as patches ([519359a](519359a9eb))
2023-06-27 02:11:33 +00:00
oSumAtrIX
519359a9eb fix: do not load annotations as patches 2023-06-27 04:09:03 +02:00
semantic-release-bot
b615ed6aab chore(release): 11.0.2-dev.3 [skip ci]
## [11.0.2-dev.3](https://github.com/revanced/revanced-patcher/compare/v11.0.2-dev.2...v11.0.2-dev.3) (2023-06-27)

### Performance Improvements

* resolve fingerprints using method maps ([#185](https://github.com/revanced/revanced-patcher/issues/185)) ([d718134](d718134ab2))
2023-06-27 02:08:29 +00:00
LisoUseInAIKyrios
d718134ab2 perf: resolve fingerprints using method maps (#185)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-06-27 04:06:51 +02:00
semantic-release-bot
5e681ed381 chore(release): 11.0.2-dev.2 [skip ci]
## [11.0.2-dev.2](https://github.com/revanced/revanced-patcher/compare/v11.0.2-dev.1...v11.0.2-dev.2) (2023-06-18)

### Bug Fixes

* use `versionCode` if `versionName` is unavailable ([6e1b647](6e1b6479b6))
2023-06-18 14:41:34 +00:00
oSumAtrIX
6e1b6479b6 fix: use versionCode if versionName is unavailable 2023-06-18 16:39:49 +02:00
semantic-release-bot
f3c9e28a62 chore(release): 11.0.2-dev.1 [skip ci]
## [11.0.2-dev.1](https://github.com/revanced/revanced-patcher/compare/v11.0.1...v11.0.2-dev.1) (2023-06-14)

### Bug Fixes

* catch exceptions from closing patches ([d5d6f85](d5d6f85084))
* only close succeeded patches ([b8151eb](b8151ebccb))
2023-06-14 00:16:26 +00:00
oSumAtrIX
d5d6f85084 fix: catch exceptions from closing patches 2023-06-14 02:14:37 +02:00
oSumAtrIX
b8151ebccb fix: only close succeeded patches 2023-06-14 01:43:19 +02:00
semantic-release-bot
5650e34432 chore(release): 11.0.1 [skip ci]
## [11.0.1](https://github.com/revanced/revanced-patcher/compare/v11.0.0...v11.0.1) (2023-06-12)

### Bug Fixes

* revert using `OutputStream.nullOutputStream` ([f02a426](f02a42610b))
2023-06-12 03:36:10 +00:00
oSumAtrIX
c893d16d52 chore: merge branch dev to main (#190) 2023-06-12 05:34:23 +02:00
semantic-release-bot
34f08bf206 chore(release): 11.0.1-dev.1 [skip ci]
## [11.0.1-dev.1](https://github.com/revanced/revanced-patcher/compare/v11.0.0...v11.0.1-dev.1) (2023-06-12)

### Bug Fixes

* revert using `OutputStream.nullOutputStream` ([f02a426](f02a42610b))
2023-06-12 03:33:53 +00:00
oSumAtrIX
f02a42610b fix: revert using OutputStream.nullOutputStream
Older Android versions don't support this API
2023-06-12 05:32:13 +02:00
oSumAtrIX
c95e6fa92f ci: add cache step 2023-06-12 02:55:09 +02:00
oSumAtrIX
fd738e723b ci: build before running semantic-release 2023-06-12 01:52:52 +02:00
oSumAtrIX
b1d1956323 ci: remove unnecessary steps 2023-06-12 01:47:26 +02:00
semantic-release-bot
725a8012ac chore(release): 11.0.0 [skip ci]
# [11.0.0](https://github.com/revanced/revanced-patcher/compare/v10.0.0...v11.0.0) (2023-06-10)

### Bug Fixes

* add imports to fix failing tests ([43d6868](43d6868d1f))

* refactor!: move extension functions to their corresponding classes ([a12fe7d](a12fe7dd9e))
* refactor!: use proper extension function names ([efdd01a](efdd01a988))
* fix!: implement extension functions consistently ([aacf900](aacf900764))

### BREAKING CHANGES

* This changes the import paths for extension functions.
* This changes the names of extension functions
* This changes the name of functions
2023-06-10 23:11:52 +00:00
oSumAtrIX
bb9a73e53b chore: merge branch dev to main (#187) 2023-06-11 01:10:59 +02:00
semantic-release-bot
ef2de35a74 chore(release): 11.0.0-dev.2 [skip ci]
# [11.0.0-dev.2](https://github.com/revanced/revanced-patcher/compare/v11.0.0-dev.1...v11.0.0-dev.2) (2023-06-09)

### Bug Fixes

* add imports to fix failing tests ([43d6868](43d6868d1f))
2023-06-09 23:56:16 +00:00
oSumAtrIX
2a453d51a8 refactor: rename helper methods for tests 2023-06-10 01:55:05 +02:00
oSumAtrIX
43d6868d1f fix: add imports to fix failing tests 2023-06-10 01:43:09 +02:00
semantic-release-bot
cea9379b32 chore(release): 11.0.0-dev.1 [skip ci]
# [11.0.0-dev.1](https://github.com/revanced/revanced-patcher/compare/v10.0.0...v11.0.0-dev.1) (2023-06-07)

* refactor!: move extension functions to their corresponding classes ([a12fe7d](a12fe7dd9e))
* refactor!: use proper extension function names ([efdd01a](efdd01a988))
* fix!: implement extension functions consistently ([aacf900](aacf900764))

### BREAKING CHANGES

* This changes the import paths for extension functions.
* This changes the names of extension functions
* This changes the name of functions
2023-06-07 01:45:31 +00:00
oSumAtrIX
a12fe7dd9e refactor!: move extension functions to their corresponding classes
BREAKING CHANGE: This changes the import paths for extension functions.
2023-06-07 03:43:17 +02:00
oSumAtrIX
efdd01a988 refactor!: use proper extension function names
BREAKING CHANGE: This changes the names of extension functions
2023-06-07 03:43:13 +02:00
oSumAtrIX
eafe1c631f refactor: use existing null output stream 2023-06-07 03:32:19 +02:00
oSumAtrIX
aacf900764 fix!: implement extension functions consistently
BREAKING CHANGE: This changes the name of functions
2023-06-07 03:32:19 +02:00
semantic-release-bot
f82494e9bb chore(release): 10.0.0 [skip ci]
# [10.0.0](https://github.com/revanced/revanced-patcher/compare/v9.0.0...v10.0.0) (2023-06-07)

* fix!: check for two methods parameters orders (#183) ([b6d6a75](b6d6a7591b)), closes [#183](https://github.com/revanced/revanced-patcher/issues/183)

### BREAKING CHANGES

* This requires changes to `MethodFingerprint`
2023-06-07 00:59:13 +00:00
oSumAtrIX
1e0ffa176e chore: merge branch dev to main 2023-06-07 02:58:23 +02:00
semantic-release-bot
b7eb2d2249 chore(release): 10.0.0-dev.1 [skip ci]
# [10.0.0-dev.1](https://github.com/revanced/revanced-patcher/compare/v9.0.0...v10.0.0-dev.1) (2023-06-07)

* fix!: check for two methods parameters orders (#183) ([b6d6a75](b6d6a7591b)), closes [#183](https://github.com/revanced/revanced-patcher/issues/183)

### BREAKING CHANGES

* This requires changes to `MethodFingerprint`
2023-06-07 00:52:08 +00:00
LisoUseInAIKyrios
b6d6a7591b fix!: check for two methods parameters orders (#183)
BREAKING CHANGE: This requires changes to `MethodFingerprint`
2023-06-07 02:50:38 +02:00
semantic-release-bot
8f1c835299 chore(release): 9.0.0 [skip ci]
# [9.0.0](https://github.com/revanced/revanced-patcher/compare/v8.0.0...v9.0.0) (2023-05-23)

* refactor!: rename parameter ([526a3d7](526a3d7c35))

### BREAKING CHANGES

* This changes named parameters.
2023-05-23 23:58:07 +00:00
oSumAtrIX
a188c16a99 chore: merge branch dev to main (#177) 2023-05-24 01:56:40 +02:00
semantic-release-bot
3e6804f06c chore(release): 9.0.0-dev.1 [skip ci]
# [9.0.0-dev.1](https://github.com/revanced/revanced-patcher/compare/v8.0.0...v9.0.0-dev.1) (2023-05-23)

* refactor!: rename parameter ([526a3d7](526a3d7c35))

### BREAKING CHANGES

* This changes named parameters.
2023-05-23 23:50:12 +00:00
oSumAtrIX
526a3d7c35 refactor!: rename parameter
BREAKING CHANGE: This changes named parameters.
2023-05-24 01:49:07 +02:00
oSumAtrIX
28fc6a2ddd refactor: apply Kotlin idioms 2023-05-24 01:45:46 +02:00
semantic-release-bot
d4f08d7bff chore(release): 8.0.0 [skip ci]
# [8.0.0](https://github.com/revanced/revanced-patcher/compare/v7.1.1...v8.0.0) (2023-05-13)

* feat!: add `classDef` parameter to `MethodFingerprint` (#175) ([a205220](a2052202b2)), closes [#175](https://github.com/revanced/revanced-patcher/issues/175)

### BREAKING CHANGES

* This changes the signature of the `customFingerprint` function.
2023-05-13 23:58:31 +00:00
oSumAtrIX
ca9fe322eb chore: merge branch dev to main (#174) 2023-05-14 01:57:34 +02:00
Jim Man
239ea0bcaa refactor: simplify loading patches (#172) 2023-05-14 01:55:26 +02:00
semantic-release-bot
7f02b8df48 chore(release): 8.0.0-dev.1 [skip ci]
# [8.0.0-dev.1](https://github.com/revanced/revanced-patcher/compare/v7.1.1...v8.0.0-dev.1) (2023-05-10)

* feat!: add `classDef` parameter to `MethodFingerprint` (#175) ([a205220](a2052202b2)), closes [#175](https://github.com/revanced/revanced-patcher/issues/175)

### BREAKING CHANGES

* This changes the signature of the `customFingerprint` function.
2023-05-10 23:38:38 +00:00
badawoll
a2052202b2 feat!: add classDef parameter to MethodFingerprint (#175)
BREAKING CHANGE: This changes the signature of the `customFingerprint` function.
2023-05-11 01:37:17 +02:00
oSumAtrIX
223cea7021 build: use Java SDK 17 for building 2023-05-09 08:16:15 +02:00
semantic-release-bot
ac9337f694 chore(release): 7.1.1 [skip ci]
## [7.1.1](https://github.com/revanced/revanced-patcher/compare/v7.1.0...v7.1.1) (2023-05-07)

### Bug Fixes

* remove `count` instead of `count + 1` instructions with `removeInstructions` ([#167](https://github.com/revanced/revanced-patcher/issues/167)) ([98f8eed](98f8eedecd))
2023-05-07 23:06:19 +00:00
oSumAtrIX
549651d04a chore: merge branch dev to main (#171) 2023-05-08 01:05:17 +02:00
semantic-release-bot
966bbd902e chore(release): 7.1.1-dev.1 [skip ci]
## [7.1.1-dev.1](https://github.com/revanced/revanced-patcher/compare/v7.1.0...v7.1.1-dev.1) (2023-05-07)

### Bug Fixes

* remove `count` instead of `count + 1` instructions with `removeInstructions` ([#167](https://github.com/revanced/revanced-patcher/issues/167)) ([98f8eed](98f8eedecd))
2023-05-07 23:04:09 +00:00
oSumAtrIX
81e6f8784e docs: fix heading 2023-05-08 01:03:11 +02:00
oSumAtrIX
9c53877888 build: downgrade to JDK version 11
This is to properly support Android
2023-05-08 01:03:11 +02:00
rstular
98f8eedecd fix: remove count instead of count + 1 instructions with removeInstructions (#167)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>

BREAKING-CHANGE: This alters the behaviour of the function. Instead of removing `count + 1` instructions, this now removes `count` instructions.
2023-05-08 01:03:09 +02:00
semantic-release-bot
4ed429d25c chore(release): 7.1.0 [skip ci]
# [7.1.0](https://github.com/revanced/revanced-patcher/compare/v7.0.0...v7.1.0) (2023-05-05)

### Features

* add appreciation message for new contributors ([d674362](d67436271d))
* add overload to get instruction as type ([49c173d](49c173dc14))
2023-05-05 23:06:29 +00:00
oSumAtrIX
119d05f469 chore: merge branch dev to main (#161) 2023-05-06 01:05:01 +02:00
semantic-release-bot
2432fde6bf chore(release): 7.1.0-dev.2 [skip ci]
# [7.1.0-dev.2](https://github.com/revanced/revanced-patcher/compare/v7.1.0-dev.1...v7.1.0-dev.2) (2023-05-05)

### Features

* add overload to get instruction as type ([49c173d](49c173dc14))
2023-05-05 21:38:29 +00:00
oSumAtrIX
49c173dc14 feat: add overload to get instruction as type 2023-05-05 23:36:30 +02:00
oSumAtrIX
d83e9372bb chore: update gradle and dependencies 2023-04-30 05:27:22 +02:00
semantic-release-bot
7e8cd3bede chore(release): 7.1.0-dev.1 [skip ci]
# [7.1.0-dev.1](https://github.com/revanced/revanced-patcher/compare/v7.0.0...v7.1.0-dev.1) (2023-04-30)

### Features

* add appreciation message for new contributors ([d674362](d67436271d))
2023-04-30 01:16:45 +00:00
oSumAtrIX
d67436271d feat: add appreciation message for new contributors 2023-04-30 03:15:12 +02:00
oSumAtrIX
aa07f35f06 chore: bump dependencies 2023-04-03 03:04:05 +02:00
oSumAtrIX
77e0536838 build: update Kotlin to 1.8.10 2023-03-31 17:19:40 +02:00
oSumAtrIX
a49e78234b chore: remove project files
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-03-02 19:23:41 +01:00
semantic-release-bot
a3ae825e48 chore(release): 7.0.0 [skip ci]
# [7.0.0](https://github.com/revanced/revanced-patcher/compare/v6.4.3...v7.0.0) (2023-02-26)

* feat!: merge integrations only when necessary ([6e24a85](6e24a85eab))

### BREAKING CHANGES

* `Patcher.addFiles` is now renamed to `Patcher.addIntegrations`

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-02-26 23:42:48 +00:00
oSumAtrIX
146c8504ed chore: merge branch dev to main (#159) 2023-02-27 00:41:27 +01:00
semantic-release-bot
2eb125ad69 chore(release): 7.0.0-dev.1 [skip ci]
# [7.0.0-dev.1](https://github.com/revanced/revanced-patcher/compare/v6.4.3...v7.0.0-dev.1) (2023-02-26)

* feat!: merge integrations only when necessary ([6e24a85](6e24a85eab))

### BREAKING CHANGES

* `Patcher.addFiles` is now renamed to `Patcher.addIntegrations`

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-02-26 23:24:38 +00:00
oSumAtrIX
6e24a85eab feat!: merge integrations only when necessary
BREAKING CHANGE: `Patcher.addFiles` is now renamed to `Patcher.addIntegrations`

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-02-27 00:23:27 +01:00
oSumAtrIX
e4c3e9ffc5 refactor: remove unnecessary annotations
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-02-26 23:18:35 +01:00
Javier Flores
4c1778a62f chore: update gradle wrapper to 8.0.1 (#160) 2023-02-26 03:46:33 +01:00
oSumAtrIX
d99261cdbb ci: fix backmerge direction
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-02-22 16:39:50 +01:00
oSumAtrIX
ac1c0f2773 ci: add backmerge target branch
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-02-22 06:45:16 +01:00
oSumAtrIX
eddd4ec7ac ci: use new semantic-release-backmerge option
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-02-18 21:55:40 +01:00
Palm
07a2829c65 ci: update actions (#158) 2023-02-13 22:29:20 +01:00
semantic-release-bot
3d77e299d9 chore(release): 6.4.3 [skip ci]
## [6.4.3](https://github.com/revanced/revanced-patcher/compare/v6.4.2...v6.4.3) (2023-02-10)

### Bug Fixes

* check `CONST_STRING_JUMP` instructions for matching string ([058d292](058d292ad5))
2023-02-10 04:28:15 +00:00
oSumAtrIX
f1336f89e4 chore: merge branch dev to main (#156) 2023-02-10 05:26:43 +01:00
semantic-release-bot
0502f84c20 chore(release): 6.4.3-dev.1 [skip ci]
## [6.4.3-dev.1](https://github.com/revanced/revanced-patcher/compare/v6.4.2...v6.4.3-dev.1) (2023-02-10)

### Bug Fixes

* check `CONST_STRING_JUMP` instructions for matching string ([058d292](058d292ad5))
2023-02-10 04:20:46 +00:00
oSumAtrIX
058d292ad5 fix: check CONST_STRING_JUMP instructions for matching string
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-02-10 05:18:38 +01:00
oSumAtrIX
1029d56a52 refactor: remove dead code
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-02-10 05:17:36 +01:00
oSumAtrIX
709b5a0fec chore: fix typo
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-02-10 05:16:00 +01:00
semantic-release-bot
e1accc5041 chore(release): 6.4.2 [skip ci]
## [6.4.2](https://github.com/revanced/revanced-patcher/compare/v6.4.1...v6.4.2) (2023-01-17)

### Bug Fixes

* resolve failing builds ([a263fdf](a263fdfd41))
2023-01-17 23:29:34 +00:00
oSumAtrIX
6dbbf2e03e chore: merge branch dev to main (#153) 2023-01-18 00:14:38 +01:00
semantic-release-bot
16557eeab0 chore(release): 6.4.2-dev.1 [skip ci]
## [6.4.2-dev.1](https://github.com/revanced/revanced-patcher/compare/v6.4.1...v6.4.2-dev.1) (2023-01-17)

### Bug Fixes

* resolve failing builds ([a263fdf](a263fdfd41))
2023-01-17 23:09:26 +00:00
oSumAtrIX
6bca3e2bb5 build: update dependencies 2023-01-17 23:57:19 +01:00
oSumAtrIX
a263fdfd41 fix: resolve failing builds
This updates dependencies, because the previous ones were missing or outdated.
2023-01-17 01:32:11 +01:00
semantic-release-bot
e4b4bacae8 chore(release): 6.4.1 [skip ci]
## [6.4.1](https://github.com/revanced/revanced-patcher/compare/v6.4.0...v6.4.1) (2023-01-15)

### Bug Fixes

* update dependency `app.revanced:multidexlib2` ([#150](https://github.com/revanced/revanced-patcher/issues/150)) ([dd7dd38](dd7dd38357))
2023-01-15 05:13:48 +00:00
semantic-release-bot
cbc97af155 chore(release): 6.4.1 [skip ci]
## [6.4.1](https://github.com/revanced/revanced-patcher/compare/v6.4.0...v6.4.1) (2023-01-15)

### Bug Fixes

* update dependency `app.revanced:multidexlib2` ([#150](https://github.com/revanced/revanced-patcher/issues/150)) ([dd7dd38](dd7dd38357))
2023-01-15 04:32:33 +00:00
oSumAtrIX
d5533788e2 chore: merge branch dev to main (#152) 2023-01-15 05:31:12 +01:00
oSumAtrIX
5a4ea5cd7d ci: add missing PAT in step Release 2023-01-15 05:29:50 +01:00
oSumAtrIX
70f3c8b38c chore: merge branch dev to main (#151) 2023-01-15 05:24:25 +01:00
semantic-release-bot
6b410a0eea chore(release): 6.4.1-dev.1 [skip ci]
## [6.4.1-dev.1](https://github.com/revanced/revanced-patcher/compare/v6.4.0...v6.4.1-dev.1) (2023-01-15)

### Bug Fixes

* update dependency `app.revanced:multidexlib2` ([#150](https://github.com/revanced/revanced-patcher/issues/150)) ([dd7dd38](dd7dd38357))
2023-01-15 03:07:43 +00:00
oSumAtrIX
73a013d75b ci: use PAT in step Release 2023-01-15 04:06:45 +01:00
oSumAtrIX
7159f3db4c ci: downgrade semantic release and plugins to v19 2023-01-15 04:06:45 +01:00
oSumAtrIX
7d5ecf095c ci: give jobs names 2023-01-15 04:06:44 +01:00
oSumAtrIX
fa015a424d refactor: fix formatting 2023-01-15 04:06:44 +01:00
oSumAtrIX
dd7dd38357 fix: update dependency app.revanced:multidexlib2 (#150)
This commit addresses https://github.com/revanced/multidexlib2/issues/2.
2023-01-15 04:06:43 +01:00
semantic-release-bot
22356f2d26 chore(release): 6.4.0 [skip ci]
# [6.4.0](https://github.com/revanced/revanced-patcher/compare/v6.3.2...v6.4.0) (2023-01-02)

### Features

* add missing setter to `MutableMethod` ([8f3ecc3](8f3ecc318c))
* do not fix methods or methods in class merger ([4102f43](4102f43b8a))
* fix method and field access when merging classes ([5c09ef7](5c09ef7837))
* make `aaptPath` nullable ([#146](https://github.com/revanced/revanced-patcher/issues/146)) ([9f0a09a](9f0a09a756))
2023-01-02 08:07:08 +00:00
oSumAtrIX
66701f6076 chore: merge branch dev to main (#147) 2023-01-02 09:05:19 +01:00
semantic-release-bot
6a6ded084e chore(release): 6.4.0-dev.2 [skip ci]
# [6.4.0-dev.2](https://github.com/revanced/revanced-patcher/compare/v6.4.0-dev.1...v6.4.0-dev.2) (2023-01-02)

### Features

* add missing setter to `MutableMethod` ([8f3ecc3](8f3ecc318c))
* do not fix methods or methods in class merger ([4102f43](4102f43b8a))
* fix method and field access when merging classes ([5c09ef7](5c09ef7837))
2023-01-02 07:58:55 +00:00
oSumAtrIX
5887c69bde refactor: move merging classes code to own class (#149) 2023-01-02 08:58:05 +01:00
oSumAtrIX
4102f43b8a feat: do not fix methods or methods in class merger 2023-01-02 08:50:08 +01:00
oSumAtrIX
5c09ef7837 feat: fix method and field access when merging classes 2023-01-02 07:57:50 +01:00
oSumAtrIX
3e0bf8c863 refactor: move merging classes code to own class 2023-01-02 07:57:48 +01:00
oSumAtrIX
8f3ecc318c feat: add missing setter to MutableMethod 2023-01-02 07:09:58 +01:00
oSumAtrIX
365da96e2b build: do not comment on successful releases 2022-12-31 21:12:03 +01:00
oSumAtrIX
cd68ec4803 ci: do not escape in environment variable MESSAGE 2022-12-29 19:07:31 +01:00
semantic-release-bot
35265e029c chore(release): 6.4.0-dev.1 [skip ci]
# [6.4.0-dev.1](https://github.com/revanced/revanced-patcher/compare/v6.3.2...v6.4.0-dev.1) (2022-12-20)

### Features

* make `aaptPath` nullable ([#146](https://github.com/revanced/revanced-patcher/issues/146)) ([9f0a09a](9f0a09a756))
2022-12-20 19:05:47 +00:00
Canny
9f0a09a756 feat: make aaptPath nullable (#146) 2022-12-20 20:04:15 +01:00
semantic-release-bot
e802141df5 chore(release): 6.3.2 [skip ci]
## [6.3.2](https://github.com/revanced/revanced-patcher/compare/v6.3.1...v6.3.2) (2022-12-18)

### Bug Fixes

* check if fingerprint string is substring of any string references ([c5de9e2](c5de9e2988))
* print full exception when patch fails ([7cf79e6](7cf79e68e0))
2022-12-18 21:11:48 +00:00
oSumAtrIX
abebc0862c chore: merge branch dev to main (#144) 2022-12-18 22:10:56 +01:00
semantic-release-bot
96ef150e89 chore(release): 6.3.2-dev.1 [skip ci]
## [6.3.2-dev.1](https://github.com/revanced/revanced-patcher/compare/v6.3.1...v6.3.2-dev.1) (2022-12-18)

### Bug Fixes

* check if fingerprint string is substring of any string references ([c5de9e2](c5de9e2988))
* print full exception when patch fails ([7cf79e6](7cf79e68e0))
2022-12-18 21:08:40 +00:00
oSumAtrIX
c5de9e2988 fix: check if fingerprint string is substring of any string references 2022-12-18 22:05:05 +01:00
semantic-release-bot
c391ca648b chore(release): 6.3.2-dev.1 [skip ci]
## [6.3.2-dev.1](https://github.com/revanced/revanced-patcher/compare/v6.3.1...v6.3.2-dev.1) (2022-12-17)

### Bug Fixes

* print full exception when patch fails ([27a8401](27a8401d81))
2022-12-18 09:02:48 +01:00
oSumAtrIX
7cf79e68e0 fix: print full exception when patch fails 2022-12-18 09:02:48 +01:00
oSumAtrIX
f07db3c214 chore: merge branch dev to main (#143) 2022-12-15 21:44:59 +01:00
oSumAtrIX
88bb3a8845 ci: do not release on build commit type 2022-12-15 19:47:31 +01:00
oSumAtrIX
b9e6bd6775 chore: merge branch dev to main (#141) 2022-12-15 19:36:43 +01:00
oSumAtrIX
cd1b72e078 ci: remove unnecessary step 2022-12-15 01:08:00 +01:00
oSumAtrIX
6b889557ab ci: stash before rebasing 2022-12-15 01:07:48 +01:00
oSumAtrIX
4b1be8c647 ci: only back-merge from main branch to dev 2022-12-15 01:04:16 +01:00
oSumAtrIX
73c893c6e7 chore: merge branch dev to main (#140)
chore: merge branch `dev` to `main`
2022-12-14 00:13:25 +01:00
oSumAtrIX
75b36823b8 ci: back-merge releases back into dev branch 2022-12-14 00:02:52 +01:00
semantic-release-bot
d2d93cd075 chore(release): 6.3.1 [skip ci]
## [6.3.1](https://github.com/revanced/revanced-patcher/compare/v6.3.0...v6.3.1) (2022-12-13)

### Bug Fixes

* publicize types when merging files if necessary ([#137](https://github.com/revanced/revanced-patcher/issues/137)) ([9ec720e](9ec720e983))
2022-12-13 22:52:11 +00:00
oSumAtrIX
26b8621ac8 chore: merge branch dev to main (#139) 2022-12-13 23:50:28 +01:00
semantic-release-bot
f365a41741 chore(release): 6.3.1-dev.1 [skip ci]
## [6.3.1-dev.1](https://github.com/revanced/revanced-patcher/compare/v6.3.0...v6.3.1-dev.1) (2022-12-13)

### Bug Fixes

* publicize types when merging files if necessary ([#137](https://github.com/revanced/revanced-patcher/issues/137)) ([9ec720e](9ec720e983))
2022-12-13 22:39:34 +00:00
oSumAtrIX
9ec720e983 fix: publicize types when merging files if necessary (#137) 2022-12-13 23:36:47 +01:00
oSumAtrIX
0f432b3fdd ci: escape backticks in message environment variable 2022-12-13 23:36:47 +01:00
oSumAtrIX
96cd5618dd ci: open pull requests to merge dev to main (#131) 2022-12-13 23:36:47 +01:00
oSumAtrIX
c2a5a55e67 refactor: remove unnecessary test 2022-12-11 03:01:41 +01:00
oSumAtrIX
6c5de8b414 ci: refactor release workflow 2022-12-11 03:01:40 +01:00
semantic-release-bot
ea773cfa56 chore(release): 6.3.0 [skip ci]
# [6.3.0](https://github.com/revanced/revanced-patcher/compare/v6.2.0...v6.3.0) (2022-12-02)

### Features

* sort patches in lexicographical order ([a306561](a306561b55)), closes [#125](https://github.com/revanced/revanced-patcher/issues/125)
2022-12-02 02:32:49 +00:00
oSumAtrIX
a306561b55 feat: sort patches in lexicographical order
Closes #125
2022-12-02 03:31:25 +01:00
semantic-release-bot
b6dcd88495 chore(release): 6.2.0 [skip ci]
# [6.2.0](https://github.com/revanced/revanced-patcher/compare/v6.1.1...v6.2.0) (2022-12-02)

### Features

* merge classes on addition ([#127](https://github.com/revanced/revanced-patcher/issues/127)) ([a925650](a925650044))
2022-12-02 01:33:08 +00:00
oSumAtrIX
a925650044 feat: merge classes on addition (#127) 2022-12-02 02:31:47 +01:00
semantic-release-bot
77bbf6be1f chore(release): 6.1.1 [skip ci]
## [6.1.1](https://github.com/revanced/revanced-patcher/compare/v6.1.0...v6.1.1) (2022-11-25)

### Bug Fixes

* use `MethodUtil.methodSignaturesMatch` instead of `Method.softCompareTo` ([bd053b7](bd053b7e99))
2022-11-25 09:25:48 +00:00
oSumAtrIX
bd053b7e99 fix: use MethodUtil.methodSignaturesMatch instead of Method.softCompareTo 2022-11-25 10:24:13 +01:00
semantic-release-bot
fd742eba63 chore(release): 6.1.0 [skip ci]
# [6.1.0](https://github.com/revanced/revanced-patcher/compare/v6.0.2...v6.1.0) (2022-11-22)

### Features

* apply changes from ReVanced Patcher ([ba9d998](ba9d998681))
2022-11-22 23:30:33 +00:00
oSumAtrIX
ba9d998681 feat: apply changes from ReVanced Patcher
BREAKING-CHANGE: Some annotations have been removed regarding fingerprints and patches.
2022-11-23 00:29:12 +01:00
semantic-release-bot
75df245ec3 chore(release): 6.0.2 [skip ci]
## [6.0.2](https://github.com/revanced/revanced-patcher/compare/v6.0.1...v6.0.2) (2022-11-18)

### Bug Fixes

* fallback to patch class name instead of `java.lang.Class` class name ([4164cb0](4164cb0dea))
2022-11-18 01:20:19 +00:00
oSumAtrIX
4164cb0dea fix: fallback to patch class name instead of java.lang.Class class name 2022-11-18 02:14:20 +01:00
semantic-release-bot
18fe35ae73 chore(release): 6.0.1 [skip ci]
## [6.0.1](https://github.com/revanced/revanced-patcher/compare/v6.0.0...v6.0.1) (2022-11-14)

### Bug Fixes

* remove unnecessary dummy nop instructions ([#111](https://github.com/revanced/revanced-patcher/issues/111)) ([f9bc95f](f9bc95f220))
2022-11-14 15:59:22 +00:00
MewtR
f9bc95f220 fix: remove unnecessary dummy nop instructions (#111) 2022-11-14 16:57:13 +01:00
Nico Mexis
d2f91a8545 build: update workflow actions (#121) [skip ci] 2022-11-05 15:27:56 +01:00
semantic-release-bot
4016bdc37f chore(release): 6.0.0 [skip ci]
# [6.0.0](https://github.com/revanced/revanced-patcher/compare/v5.1.2...v6.0.0) (2022-10-05)

### Code Refactoring

* improve structuring of classes and their implementations ([4aa14bb](4aa14bbb85))

### Features

* remove unused annotation `DirectPatternScanMethod` ([538b2a8](538b2a8599))
* remove unused annotation `SincePatcher` ([4ae9ad0](4ae9ad09d6))
* remove unused extension `dependsOn` ([797286b](797286b758))
* remove unused patch extensions ([5583904](5583904994))

### BREAKING CHANGES

* various changes in which packages classes previously where and their implementation
* These extensions do not exist anymore and any use should be removed
* The extension does not exist anymore and any use should be removed
* The annotation does not exist anymore and any use should be removed
2022-10-05 02:11:19 +00:00
oSumAtrIX
538b2a8599 feat: remove unused annotation DirectPatternScanMethod 2022-10-05 03:57:40 +02:00
oSumAtrIX
4aa14bbb85 refactor: improve structuring of classes and their implementations
BREAKING CHANGE: various changes in which packages classes previously where and their implementation
2022-10-05 03:57:40 +02:00
oSumAtrIX
d37452997b refactor: move OptionsContainer to own class file
BREAKING-CHANGE: this changes the package
2022-10-04 08:32:50 +02:00
oSumAtrIX
db21d5e953 refactor: remove unused import 2022-10-04 08:30:17 +02:00
oSumAtrIX
4d581811db feat!: seal abstract class Patch as an interface 2022-10-04 08:30:17 +02:00
oSumAtrIX
8c502448be feat!: remove unused annotation MatchingMethod 2022-10-04 08:30:16 +02:00
oSumAtrIX
fec16d9442 refactor: remove line break 2022-10-04 08:18:52 +02:00
oSumAtrIX
5583904994 feat: remove unused patch extensions
BREAKING CHANGE: These extensions do not exist anymore and any use should be removed
2022-10-04 08:18:43 +02:00
oSumAtrIX
797286b758 feat: remove unused extension dependsOn
BREAKING CHANGE: The extension does not exist anymore and any use should be removed
2022-10-04 08:18:09 +02:00
oSumAtrIX
4ae9ad09d6 feat: remove unused annotation SincePatcher
BREAKING CHANGE: The annotation does not exist anymore and any use should be removed
2022-10-04 08:16:58 +02:00
semantic-release-bot
447e1ad30e chore(release): 5.1.2 [skip ci]
## [5.1.2](https://github.com/revanced/revanced-patcher/compare/v5.1.1...v5.1.2) (2022-09-29)

### Bug Fixes

* check dependencies for resource patches ([9c07ffc](9c07ffcc7a))
* use instruction index instead of strings list index for `StringMatch` ([843e62a](843e62ad29))
2022-09-29 19:29:55 +00:00
oSumAtrIX
843e62ad29 fix: use instruction index instead of strings list index for StringMatch 2022-09-29 21:27:56 +02:00
oSumAtrIX
9c07ffcc7a fix: check dependencies for resource patches 2022-09-29 21:27:12 +02:00
semantic-release-bot
438321330e chore(release): 5.1.1 [skip ci]
## [5.1.1](https://github.com/revanced/revanced-patcher/compare/v5.1.0...v5.1.1) (2022-09-26)

### Performance Improvements

* decode resources only when necessary ([3ba4be2](3ba4be240b))
2022-09-26 06:59:37 +00:00
oSumAtrIX
3ba4be240b perf: decode resources only when necessary 2022-09-26 08:57:39 +02:00
semantic-release-bot
98ce0abfa9 chore(release): 5.1.0 [skip ci]
# [5.1.0](https://github.com/revanced/revanced-patcher/compare/v5.0.1...v5.1.0) (2022-09-26)

### Features

* RwLock for opening files in `DomFileEditor` ([db4348c](db4348c4fa))
2022-09-26 01:22:58 +00:00
oSumAtrIX
db4348c4fa feat: RwLock for opening files in DomFileEditor 2022-09-26 03:21:13 +02:00
semantic-release-bot
4839f87519 chore(release): 5.0.1 [skip ci]
## [5.0.1](https://github.com/revanced/revanced-patcher/compare/v5.0.0...v5.0.1) (2022-09-23)

### Reverts

* revert breaking changes ([#106](https://github.com/revanced/revanced-patcher/issues/106)) ([124332f](124332f0e9))
2022-09-23 04:21:53 +00:00
oSumAtrIX
809862c997 build: update apktool-lib dependency 2022-09-23 06:20:00 +02:00
oSumAtrIX
fd5c878cee fix!: revert reverting changes
BREAKING-CHANGE: Imports will have to be updated from `MethodFingerprintUtils` to `MethodFingerprint.Companion`.
2022-09-21 16:45:16 +02:00
bogadana
124332f0e9 revert: revert breaking changes (#106) 2022-09-21 15:22:55 +02:00
semantic-release-bot
d4cf0cea52 chore(release): 5.0.0 [skip ci]
# [5.0.0](https://github.com/revanced/revanced-patcher/compare/v4.5.0...v5.0.0) (2022-09-21)

### Bug Fixes

* **tests:** access `patternScanResult` through `scanResult` ([76676fb](76676fb567))

* refactor!: move utility methods from `MethodFingerprintUtils` `MethodFingerprint` ([d802ef8](d802ef844e))
* feat(fingerprint)!: `StringsScanResult` for `MethodFingerprint` ([3813e28](3813e28ac2))

### BREAKING CHANGES

* Imports will have to be updated from `MethodFingerprintUtils` to `MethodFingerprint.Companion`.

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
* `MethodFingerprint` now has a field for `MethodFingerprintScanResult`. `MethodFingerprintScanResult` now holds the previous field `MethodFingerprint.patternScanResult`.

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-09-21 01:43:54 +00:00
oSumAtrIX
76676fb567 fix(tests): access patternScanResult through scanResult 2022-09-21 03:42:29 +02:00
oSumAtrIX
d802ef844e refactor!: move utility methods from MethodFingerprintUtils MethodFingerprint
BREAKING CHANGE: Imports will have to be updated from `MethodFingerprintUtils` to `MethodFingerprint.Companion`.

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-09-21 01:38:49 +02:00
oSumAtrIX
90fc547673 refactor: suppress member visibility and unnecessary null assertion warnings
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-09-21 01:38:49 +02:00
oSumAtrIX
3813e28ac2 feat(fingerprint)!: StringsScanResult for MethodFingerprint
BREAKING CHANGE: `MethodFingerprint` now has a field for `MethodFingerprintScanResult`. `MethodFingerprintScanResult` now holds the previous field `MethodFingerprint.patternScanResult`.

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-09-21 01:38:49 +02:00
semantic-release-bot
a2bb4004c7 chore(release): 4.5.0 [skip ci]
# [4.5.0](https://github.com/revanced/revanced-patcher/compare/v4.4.2...v4.5.0) (2022-09-20)

### Features

* section `acknowledgements` for issue templates ([a0cb449](a0cb449c60))
2022-09-20 22:37:38 +00:00
oSumAtrIX
a0cb449c60 feat: section acknowledgements for issue templates
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-09-21 00:36:25 +02:00
semantic-release-bot
e0271790b8 chore(release): 4.4.2 [skip ci]
## [4.4.2](https://github.com/revanced/revanced-patcher/compare/v4.4.1...v4.4.2) (2022-09-18)

### Bug Fixes

* **fingerprint:** do not throw on `MethodFingerprint.result` getter ([2f7e62e](2f7e62ef65))

### Performance Improvements

* **fingerprint:** do not resolve already resolved fingerprints ([4bfd7eb](4bfd7ebff8))
2022-09-18 06:12:38 +00:00
oSumAtrIX
4bfd7ebff8 perf(fingerprint): do not resolve already resolved fingerprints
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-09-18 07:35:08 +02:00
oSumAtrIX
2f7e62ef65 fix(fingerprint): do not throw on MethodFingerprint.result getter
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-09-18 07:34:32 +02:00
semantic-release-bot
4485af8036 chore(release): 4.4.1 [skip ci]
## [4.4.1](https://github.com/revanced/revanced-patcher/compare/v4.4.0...v4.4.1) (2022-09-14)

### Bug Fixes

* compare any methods parameters ([#101](https://github.com/revanced/revanced-patcher/issues/101)) ([085a3a4](085a3a479d))
2022-09-14 16:36:34 +00:00
d4rkk3y
085a3a479d fix: compare any methods parameters (#101) 2022-09-14 18:34:58 +02:00
semantic-release-bot
f75c9a78b8 chore(release): 4.4.0 [skip ci]
# [4.4.0](https://github.com/revanced/revanced-patcher/compare/v4.3.0...v4.4.0) (2022-09-09)

### Features

* add PathOption back ([172655b](172655bde0))
2022-09-09 14:24:48 +00:00
Sculas
172655bde0 feat: add PathOption back
Now backed by a String.
2022-09-09 16:23:21 +02:00
semantic-release-bot
456db7289a chore(release): 4.3.0 [skip ci]
# [4.3.0](https://github.com/revanced/revanced-patcher/compare/v4.2.3...v4.3.0) (2022-09-09)

### Features

* improved Patch Options ([e722e3f](e722e3f4f9))
2022-09-09 14:11:58 +00:00
Sculas
e722e3f4f9 feat: improved Patch Options
Removed a lot of the type mess. There's still some duplicated code PatchOption.kt, but I'm afraid there's nothing I can do about that. It's not a big deal anyway.
2022-09-09 16:10:30 +02:00
Sculas
c348c1f0a0 refactor: remove PathOption and FileOption 2022-09-09 15:04:17 +02:00
semantic-release-bot
ed1851013e chore(release): 4.2.3 [skip ci]
## [4.2.3](https://github.com/revanced/revanced-patcher/compare/v4.2.2...v4.2.3) (2022-09-08)

### Bug Fixes

* wrong value for iterator in PatchOptions ([e31ac1f](e31ac1f132))
2022-09-08 15:39:04 +00:00
Sculas
e31ac1f132 fix: wrong value for iterator in PatchOptions 2022-09-08 17:37:31 +02:00
semantic-release-bot
8f78f85e4a chore(release): 4.2.2 [skip ci]
## [4.2.2](https://github.com/revanced/revanced-patcher/compare/v4.2.1...v4.2.2) (2022-09-08)

### Bug Fixes

* invalid type propagation in options ([b873228](b873228ef0)), closes [#98](https://github.com/revanced/revanced-patcher/issues/98)
2022-09-08 14:50:38 +00:00
Sculas
0be2677519 Merge remote-tracking branch 'origin/main' into main 2022-09-08 16:49:26 +02:00
Sculas
b873228ef0 fix: invalid type propagation in options
Fixes #98
2022-09-08 16:49:06 +02:00
semantic-release-bot
639ff1c0ba chore(release): 4.2.1 [skip ci]
## [4.2.1](https://github.com/revanced/revanced-patcher/compare/v4.2.0...v4.2.1) (2022-09-08)

### Bug Fixes

* make patcher version public ([76c45dd](76c45dd7c1))
2022-09-08 12:51:09 +00:00
Sculas
f30671ddd1 Merge remote-tracking branch 'origin/main' into main 2022-09-08 14:49:35 +02:00
Sculas
76c45dd7c1 fix: make patcher version public 2022-09-08 14:49:26 +02:00
semantic-release-bot
1bafb77355 chore(release): 4.2.0 [skip ci]
# [4.2.0](https://github.com/revanced/revanced-patcher/compare/v4.1.5...v4.2.0) (2022-09-08)

### Bug Fixes

* remove repeatable from PatchDeprecated ([6e73631](6e73631d4d))

### Features

* SincePatcher annotation ([25f74dc](25f74dc5e9))
2022-09-08 12:43:11 +00:00
Sculas
25f74dc5e9 feat: SincePatcher annotation 2022-09-08 14:41:42 +02:00
Sculas
6e73631d4d fix: remove repeatable from PatchDeprecated 2022-09-08 14:00:15 +02:00
semantic-release-bot
7761d5b85e chore(release): 4.1.5 [skip ci]
## [4.1.5](https://github.com/revanced/revanced-patcher/compare/v4.1.4...v4.1.5) (2022-09-08)

### Bug Fixes

* broken deprecation message ([62aa295](62aa295e73))
2022-09-08 11:43:39 +00:00
Sculas
62aa295e73 fix: broken deprecation message 2022-09-08 13:42:26 +02:00
Sculas
596ede1b12 refactor: make patchName work on any class 2022-09-08 13:42:15 +02:00
semantic-release-bot
7debe62738 chore(release): 4.1.4 [skip ci]
## [4.1.4](https://github.com/revanced/revanced-patcher/compare/v4.1.3...v4.1.4) (2022-09-08)

### Bug Fixes

* handle option types and nulls properly ([aff4968](aff4968e6f))
2022-09-08 09:30:49 +00:00
Sculas
002f84da1a Merge remote-tracking branch 'origin/main' into main 2022-09-08 11:29:14 +02:00
Sculas
aff4968e6f fix: handle option types and nulls properly 2022-09-08 11:29:06 +02:00
Sculas
1d989abd55 chore: ignore kotlinc 2022-09-08 11:07:34 +02:00
semantic-release-bot
f1775f83d0 chore(release): 4.1.3 [skip ci]
## [4.1.3](https://github.com/revanced/revanced-patcher/compare/v4.1.2...v4.1.3) (2022-09-07)

### Bug Fixes

* only run list option check if not null ([4055939](4055939c08))
2022-09-07 21:48:24 +00:00
Sculas
4055939c08 fix: only run list option check if not null 2022-09-07 23:46:46 +02:00
semantic-release-bot
85120374d6 chore(release): 4.1.2 [skip ci]
## [4.1.2](https://github.com/revanced/revanced-patcher/compare/v4.1.1...v4.1.2) (2022-09-07)

### Bug Fixes

* invalid types for example options ([79f91e0](79f91e0e5a))
2022-09-07 21:24:50 +00:00
Sculas
8b4819faa1 Merge remote-tracking branch 'origin/main' into main 2022-09-07 23:23:29 +02:00
semantic-release-bot
d219276298 chore(release): 4.1.1 [skip ci]
## [4.1.1](https://github.com/revanced/revanced-patcher/compare/v4.1.0...v4.1.1) (2022-09-07)

### Bug Fixes

* handle private companion objects ([ad3d332](ad3d332e27))
2022-09-07 21:23:12 +00:00
Sculas
79f91e0e5a fix: invalid types for example options 2022-09-07 23:22:34 +02:00
Sculas
fadf62f594 Merge remote-tracking branch 'origin/main' into main 2022-09-07 23:21:41 +02:00
Sculas
ad3d332e27 fix: handle private companion objects 2022-09-07 23:21:32 +02:00
semantic-release-bot
8f66df7666 chore(release): 4.1.0 [skip ci]
# [4.1.0](https://github.com/revanced/revanced-patcher/compare/v4.0.0...v4.1.0) (2022-09-07)

### Features

* deprecation for patches ([80c2e80](80c2e80925))
2022-09-07 20:32:51 +00:00
Sculas
80c2e80925 feat: deprecation for patches 2022-09-07 22:31:15 +02:00
semantic-release-bot
c3db23d3c7 chore(release): 4.0.0 [skip ci]
# [4.0.0](https://github.com/revanced/revanced-patcher/compare/v3.5.1...v4.0.0) (2022-09-07)

### Code Refactoring

* Improve Patch Options ([6b909c1](6b909c1ee6))

### BREAKING CHANGES

* Options has been moved from Patch to a new interface called OptionsContainer and are now handled entirely different. Make sure to check the examples to understand how it works.
2022-09-07 18:57:04 +00:00
Sculas
c28584736e Merge remote-tracking branch 'origin/main' into main 2022-09-07 20:55:45 +02:00
Sculas
6b909c1ee6 refactor: Improve Patch Options
It's so much better now. Really happy with the current system.

BREAKING CHANGE: Options has been moved from Patch to a new interface called OptionsContainer and are now handled entirely different. Make sure to check the examples to understand how it works.
2022-09-07 20:55:35 +02:00
Sculas
0e8446516e build: add Kotlin Reflect 2022-09-07 20:52:05 +02:00
semantic-release-bot
aa46b953db chore(release): 3.5.1 [skip ci]
## [3.5.1](https://github.com/revanced/revanced-patcher/compare/v3.5.0...v3.5.1) (2022-09-06)

### Bug Fixes

* add tests for PathOption ([d6308e1](d6308e126c))
* PathOption should be open, not sealed ([a562e47](a562e476c0))
* typo in ListOption ([3921648](392164862c))

### Performance Improvements

* make exception an object ([75d2be8](75d2be8803))
2022-09-06 20:38:24 +00:00
Sculas
a562e476c0 fix: PathOption should be open, not sealed 2022-09-06 22:36:20 +02:00
Sculas
75d2be8803 perf: make exception an object 2022-09-06 22:35:33 +02:00
Sculas
d6308e126c fix: add tests for PathOption 2022-09-06 22:35:00 +02:00
Sculas
bb97af4d86 refactor: add FileOption alias for PathOption 2022-09-06 22:34:46 +02:00
Sculas
392164862c fix: typo in ListOption 2022-09-06 21:44:05 +02:00
Sculas
53e807dec1 refactor: add PatchOption.PathOption 2022-09-06 21:43:45 +02:00
semantic-release-bot
288d50a8b4 chore(release): 3.5.0 [skip ci]
# [3.5.0](https://github.com/revanced/revanced-patcher/compare/v3.4.1...v3.5.0) (2022-09-05)

### Features

* default value for `Package.versions` annotation parameter ([131dedd](131dedd4b0))
2022-09-05 14:45:56 +00:00
oSumAtrIX
131dedd4b0 feat: default value for Package.versions annotation parameter
Reverts 4b81318710
2022-09-05 16:44:35 +02:00
semantic-release-bot
5a92d5c29d chore(release): 3.4.1 [skip ci]
## [3.4.1](https://github.com/revanced/revanced-patcher/compare/v3.4.0...v3.4.1) (2022-09-03)

### Bug Fixes

* remove default param from Package.versions ([4b81318](4b81318710))
2022-09-03 20:54:06 +00:00
Sculas
4b81318710 fix: remove default param from Package.versions
Kotlin compiler bug produces invalid bytecode, resulting in an IncompleteAnnotationException at runtime.
2022-09-03 22:52:49 +02:00
semantic-release-bot
44f6a3ebc5 chore(release): 3.4.0 [skip ci]
# [3.4.0](https://github.com/revanced/revanced-patcher/compare/v3.3.3...v3.4.0) (2022-08-31)

### Features

* nullable parameters ([7882a8d](7882a8d928))
2022-08-31 18:32:43 +00:00
oSumAtrIX
7882a8d928 feat: nullable parameters
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-08-31 20:30:31 +02:00
semantic-release-bot
cc3d32748b chore(release): 3.3.3 [skip ci]
## [3.3.3](https://github.com/revanced/revanced-patcher/compare/v3.3.2...v3.3.3) (2022-08-14)

### Bug Fixes

* show error message if cause is null ([f9da2ad](f9da2ad531))
2022-08-14 15:25:16 +00:00
oSumAtrIX
f9da2ad531 fix: show error message if cause is null 2022-08-14 17:22:43 +02:00
semantic-release-bot
b19e1131e8 chore(release): 3.3.2 [skip ci]
## [3.3.2](https://github.com/revanced/revanced-patcher/compare/v3.3.1...v3.3.2) (2022-08-06)

### Bug Fixes

* close open files ([#75](https://github.com/revanced/revanced-patcher/issues/75)) ([123ad54](123ad54c15))
2022-08-06 22:17:39 +00:00
dan1st
123ad54c15 fix: close open files (#75) 2022-08-07 00:16:23 +02:00
Sculas
09f6ab4155 Merge remote-tracking branch 'origin/main' into main 2022-08-03 18:32:34 +02:00
Sculas
01cf3fb50f refactor: util package structure 2022-08-03 18:31:31 +02:00
semantic-release-bot
6c5f9d4198 chore(release): 3.3.1 [skip ci]
## [3.3.1](https://github.com/revanced/revanced-patcher/compare/v3.3.0...v3.3.1) (2022-08-03)

### Bug Fixes

* revert soft dependencies ([7b2d058](7b2d058144))
2022-08-03 01:48:56 +00:00
oSumAtrIX
7b2d058144 fix: revert soft dependencies 2022-08-03 03:45:34 +02:00
semantic-release-bot
db2804270e chore(release): 3.3.0 [skip ci]
# [3.3.0](https://github.com/revanced/revanced-patcher/compare/v3.2.1...v3.3.0) (2022-08-02)

### Features

* add getValue & setValue for PatchOption ([2572cd0](2572cd04b5))
2022-08-02 21:31:59 +00:00
Sculas
2572cd04b5 feat: add getValue & setValue for PatchOption 2022-08-02 23:30:38 +02:00
semantic-release-bot
5eb8b428b9 chore(release): 3.2.1 [skip ci]
## [3.2.1](https://github.com/revanced/revanced-patcher/compare/v3.2.0...v3.2.1) (2022-08-02)

### Bug Fixes

* check if patch option requirement is met ([14a73bf](14a73bfcaf))
2022-08-02 20:43:26 +00:00
Sculas
3a118d9b9d Merge remote-tracking branch 'origin/main' into main 2022-08-02 22:41:41 +02:00
Sculas
14a73bfcaf fix: check if patch option requirement is met 2022-08-02 22:41:34 +02:00
semantic-release-bot
567bf52e16 chore(release): 3.2.0 [skip ci]
# [3.2.0](https://github.com/revanced/revanced-patcher/compare/v3.1.0...v3.2.0) (2022-08-02)

### Features

* PatchOptions#nullify to nullify an option ([371f0c4](371f0c4d0b))
2022-08-02 20:36:21 +00:00
Sculas
35c6489dba Merge remote-tracking branch 'origin/main' into main 2022-08-02 22:34:44 +02:00
Sculas
371f0c4d0b feat: PatchOptions#nullify to nullify an option 2022-08-02 22:32:55 +02:00
Sculas
1b42f65d95 refactor: migrate to custom exceptions for patch options 2022-08-02 22:16:37 +02:00
semantic-release-bot
2aee0cbd0f chore(release): 3.1.0 [skip ci]
# [3.1.0](https://github.com/revanced/revanced-patcher/compare/v3.0.0...v3.1.0) (2022-08-02)

### Features

* validator for patch options ([4e2e772](4e2e772389))
2022-08-02 20:02:18 +00:00
Sculas
19256b5437 Merge remote-tracking branch 'origin/main' into main 2022-08-02 22:00:40 +02:00
Sculas
67a5237541 test: refactor & add more tests 2022-08-02 22:00:32 +02:00
Sculas
4e2e772389 feat: validator for patch options 2022-08-02 22:00:10 +02:00
semantic-release-bot
799bc9e163 chore(release): 3.0.0 [skip ci]
# [3.0.0](https://github.com/revanced/revanced-patcher/compare/v2.9.0...v3.0.0) (2022-08-02)

### Features

* registry for patch options ([2431785](2431785d0e))

### BREAKING CHANGES

* Patch options now use the PatchOptions registry class instead of an Iterable. This change requires modifications to existing patches using this API.
2022-08-02 19:11:43 +00:00
Sculas
2431785d0e feat: registry for patch options
BREAKING CHANGE: Patch options now use the PatchOptions registry class instead of an Iterable. This change requires modifications to existing patches using this API.
2022-08-02 21:10:14 +02:00
semantic-release-bot
fb3c0e87d4 chore(release): 2.9.0 [skip ci]
# [2.9.0](https://github.com/revanced/revanced-patcher/compare/v2.8.0...v2.9.0) (2022-08-02)

### Bug Fixes

* show error message instead of `null` ([8d95b14](8d95b14f35))

### Features

* exclusive mutable access to files ([814ce0b](814ce0b9ae))
2022-08-02 01:11:01 +00:00
oSumAtrIX
5f7ef2dbff Merge remote-tracking branch 'origin/main' 2022-08-02 03:09:02 +02:00
Sculas
ec1d8a8fba refactor: remove DependencyType.SOFT (#82)
BREAKING-CHANGE: DependencyType.SOFT has now been removed after it was deprecated. There is no direct replacement for this. Please look into Patch Options instead, which supersedes this.
2022-08-02 00:47:32 +02:00
oSumAtrIX
814ce0b9ae feat: exclusive mutable access to files 2022-08-02 00:42:38 +02:00
oSumAtrIX
8d95b14f35 fix: show error message instead of null 2022-08-02 00:42:38 +02:00
semantic-release-bot
711b8a25a7 chore(release): 2.8.0 [skip ci]
# [2.8.0](https://github.com/revanced/revanced-patcher/compare/v2.7.0...v2.8.0) (2022-08-01)

### Bug Fixes

* remove requirement for solution [skip ci] ([#80](https://github.com/revanced/revanced-patcher/issues/80)) ([9a4d30e](9a4d30e152))

### Features

* patch options ([#81](https://github.com/revanced/revanced-patcher/issues/81)) ([fbb09f3](fbb09f38dc))
2022-08-01 22:32:32 +00:00
Sculas
fbb09f38dc feat: patch options (#81)
* feat: Patch Options

* refactor: remove delegate property

* feat: List patch options

* refactor: add setter example to PatchOptionsUsage.kt

* docs: add docs for PatchOptions

* docs: tidy docs
2022-08-02 00:31:00 +02:00
Robert
9a4d30e152 fix: remove requirement for solution [skip ci] (#80) 2022-08-01 13:07:12 +02:00
semantic-release-bot
368c61c1bf chore(release): 2.7.0 [skip ci]
# [2.7.0](https://github.com/revanced/revanced-patcher/compare/v2.6.0...v2.7.0) (2022-08-01)

### Features

* `Closeable` patches ([bbd40bf](bbd40bf2f6))
2022-08-01 02:15:18 +00:00
oSumAtrIX
bbd40bf2f6 feat: Closeable patches 2022-08-01 04:12:33 +02:00
Sculas
3de999a2d3 refactor: remove ReplaceWith from DependencyType.SOFT 2022-07-31 18:35:02 +02:00
Sculas
83cbb2f110 Merge remote-tracking branch 'origin/main' into main 2022-07-31 18:31:50 +02:00
Sculas
fcc7fa75d0 refactor: deprecate DependencyType.SOFT
Soft dependencies will be removed when Patch Options is implemented.
2022-07-31 18:31:40 +02:00
semantic-release-bot
495ebface8 chore(release): 2.6.0 [skip ci]
# [2.6.0](https://github.com/revanced/revanced-patcher/compare/v2.5.2...v2.6.0) (2022-07-31)

### Features

* add Patch#dependsOn extension ([523f67b](523f67b238))
* Soft Dependencies for Patches ([8c12f8d](8c12f8d488))
2022-07-31 14:52:23 +00:00
Sculas
8c12f8d488 feat: Soft Dependencies for Patches 2022-07-31 16:50:59 +02:00
Sculas
523f67b238 feat: add Patch#dependsOn extension 2022-07-31 15:07:23 +02:00
Sculas
4813a8b48e chore: remove import 2022-07-31 15:01:38 +02:00
Sculas
d5c66022c9 refactor: get rid of package names in example 2022-07-31 15:01:13 +02:00
Lucaskyy
1d4034b36c chore: add description to readme 2022-07-31 14:41:41 +02:00
oSumAtrIX
dd2d696d00 docs: add missing . to feature-issue.yml description 2022-07-26 19:38:00 +02:00
oSumAtrIX
6326321b65 docs: add missing . to issue description 2022-07-26 19:34:39 +02:00
oSumAtrIX
f291a4ae3e docs: GitHub issue forms 2022-07-26 19:28:32 +02:00
semantic-release-bot
817b8db019 chore(release): 2.5.2 [skip ci]
## [2.5.2](https://github.com/revanced/revanced-patcher/compare/v2.5.1...v2.5.2) (2022-07-24)
2022-07-24 16:30:57 +00:00
Sculas
a321b8971b build: update Apktool to 2.7.0 2022-07-24 18:29:25 +02:00
semantic-release-bot
783b2de9db chore(release): 2.5.1 [skip ci]
## [2.5.1](https://github.com/revanced/revanced-patcher/compare/v2.5.0...v2.5.1) (2022-07-17)

### Bug Fixes

* close stream when closing `DomFileEditor` ([77604d4](77604d4078))
2022-07-17 23:30:04 +00:00
oSumAtrIX
77604d4078 fix: close stream when closing DomFileEditor 2022-07-18 01:28:16 +02:00
oSumAtrIX
21b5404180 docs: change size of headings [skip ci] 2022-07-12 01:12:45 +02:00
semantic-release-bot
9ac6d5c7da chore(release): 2.5.0 [skip ci]
# [2.5.0](https://github.com/revanced/revanced-patcher/compare/v2.4.0...v2.5.0) (2022-07-11)

### Bug Fixes

* missing additional items [skip ci] ([0ebab8b](0ebab8bf59))

### Features

* feature request issue template ([1b39278](1b39278b24))
* issue templates [skip ci] ([112bc99](112bc998f4))
2022-07-11 18:21:14 +00:00
oSumAtrIX
1b39278b24 feat: feature request issue template 2022-07-11 20:19:53 +02:00
oSumAtrIX
0ebab8bf59 fix: missing additional items [skip ci] 2022-07-10 00:34:55 +02:00
oSumAtrIX
112bc998f4 feat: issue templates [skip ci] 2022-07-10 00:32:05 +02:00
semantic-release-bot
12c96bf818 chore(release): 2.4.0 [skip ci]
# [2.4.0](https://github.com/revanced/revanced-patcher/compare/v2.3.1...v2.4.0) (2022-07-09)

### Features

* Improve Smali Compiler ([6bfe571](6bfe5716c3))
2022-07-09 13:04:21 +00:00
oSumAtrIX
91298a8790 Merge pull request #52 from revanced/feat/smali-branching
feat: improve Smali compiler
2022-07-09 15:03:01 +02:00
oSumAtrIX
f2a7cff41c style: fix casing of the first letter in comments 2022-07-09 06:27:49 +02:00
oSumAtrIX
dd941233ca refactor: improve the addInstructions extension method further more 2022-07-09 06:26:05 +02:00
semantic-release-bot
fc06dd1c29 chore(release): 2.3.1 [skip ci]
## [2.3.1](https://github.com/revanced/revanced-patcher/compare/v2.3.0...v2.3.1) (2022-07-07)

### Bug Fixes

* handle null properly ([#64](https://github.com/revanced/revanced-patcher/issues/64)) ([482af78](482af78f2b))
2022-07-07 06:35:28 +00:00
bogadana
482af78f2b fix: handle null properly (#64) 2022-07-07 08:33:40 +02:00
semantic-release-bot
89a27dfbe6 chore(release): 2.3.0 [skip ci]
# [2.3.0](https://github.com/revanced/revanced-patcher/compare/v2.2.2...v2.3.0) (2022-07-05)

### Features

* nullability for `BytecodePatch` constructor ([#59](https://github.com/revanced/revanced-patcher/issues/59)) ([4ea030d](4ea030d0a0))
2022-07-05 14:48:22 +00:00
bogadana
4ea030d0a0 feat: nullability for BytecodePatch constructor (#59) 2022-07-05 16:46:54 +02:00
semantic-release-bot
4cc2fa17f5 chore(release): 2.2.2 [skip ci]
## [2.2.2](https://github.com/revanced/revanced-patcher/compare/v2.2.1...v2.2.2) (2022-07-04)

### Bug Fixes

* `MethodWalker` not accounting for all reference instructions ([48068cb](48068cb3d7))
2022-07-04 19:36:34 +00:00
oSumAtrIX
48068cb3d7 fix: MethodWalker not accounting for all reference instructions 2022-07-03 22:51:04 +02:00
semantic-release-bot
d107c7245c chore(release): 2.2.1 [skip ci]
## [2.2.1](https://github.com/revanced/revanced-patcher/compare/v2.2.0...v2.2.1) (2022-07-03)

### Bug Fixes

* more useful error message ([4b2e323](4b2e3230ec))
2022-07-03 14:46:19 +00:00
oSumAtrIX
4b2e3230ec fix: more useful error message 2022-07-03 15:37:48 +02:00
semantic-release-bot
fb5b82da4e chore(release): 2.2.0 [skip ci]
# [2.2.0](https://github.com/revanced/revanced-patcher/compare/v2.1.2...v2.2.0) (2022-07-02)

### Bug Fixes

* DomFileEditor opening in- and output streams on the same file ([83187c9](83187c9edd))

### Features

* remove deprecated functions ([ada5a03](ada5a033de))
* streams overload for `XmlFileHolder` ([6f72c4c](6f72c4c4c0))
2022-07-02 22:59:27 +00:00
oSumAtrIX
5970e32aa5 Merge pull request #57 from revanced/dev
Merge `dev` to `main`
2022-07-03 00:30:37 +02:00
semantic-release-bot
0f00d33f4e chore(release): 2.2.0-dev.3 [skip ci]
# [2.2.0-dev.3](https://github.com/revanced/revanced-patcher/compare/v2.2.0-dev.2...v2.2.0-dev.3) (2022-07-02)

### Bug Fixes

* DomFileEditor opening in- and output streams on the same file ([83187c9](83187c9edd))
2022-07-02 22:21:19 +00:00
oSumAtrIX
83187c9edd fix: DomFileEditor opening in- and output streams on the same file 2022-07-03 00:19:39 +02:00
semantic-release-bot
79d70cff4b chore(release): 2.2.0-dev.2 [skip ci]
# [2.2.0-dev.2](https://github.com/revanced/revanced-patcher/compare/v2.2.0-dev.1...v2.2.0-dev.2) (2022-07-02)

### Features

* streams overload for `XmlFileHolder` ([6f72c4c](6f72c4c4c0))
2022-07-02 15:46:16 +00:00
oSumAtrIX
6f72c4c4c0 feat: streams overload for XmlFileHolder 2022-07-02 17:44:08 +02:00
oSumAtrIX
c8eedac4d9 refactor: members of ResourceData 2022-07-02 16:22:19 +02:00
semantic-release-bot
60a8278ae8 chore(release): 2.2.0-dev.1 [skip ci]
# [2.2.0-dev.1](https://github.com/revanced/revanced-patcher/compare/v2.1.2...v2.2.0-dev.1) (2022-07-02)

### Features

* remove deprecated functions ([ada5a03](ada5a033de))
2022-07-02 02:23:32 +00:00
oSumAtrIX
ada5a033de feat: remove deprecated functions 2022-07-02 04:21:20 +02:00
semantic-release-bot
109b8a296d chore(release): 2.1.2 [skip ci]
## [2.1.2](https://github.com/revanced/revanced-patcher/compare/v2.1.1...v2.1.2) (2022-06-29)

### Bug Fixes

* invert fingerprint resolution condition of `customFingerprint` ([e2faf4c](e2faf4ca9b))
2022-06-29 23:37:37 +00:00
oSumAtrIX
e2faf4ca9b fix: invert fingerprint resolution condition of customFingerprint 2022-06-30 01:36:25 +02:00
oSumAtrIX
2134182a0e refactor: declare data parameter internal 2022-06-29 19:55:23 +02:00
semantic-release-bot
d8b5b8bb7c chore(release): 2.1.1 [skip ci]
## [2.1.1](https://github.com/revanced/revanced-patcher/compare/v2.1.0...v2.1.1) (2022-06-28)
2022-06-28 17:47:39 +00:00
Sculas
49970b5926 build: update Apktool to re-enable 9patch decoder 2022-06-28 19:45:45 +02:00
semantic-release-bot
c1fbd8cf8c chore(release): 2.1.0 [skip ci]
# [2.1.0](https://github.com/revanced/revanced-patcher/compare/v2.0.4...v2.1.0) (2022-06-28)

### Features

* log failed patches due to failed dependencies ([a467fbb](a467fbb704))
2022-06-28 01:27:05 +00:00
oSumAtrIX
a467fbb704 feat: log failed patches due to failed dependencies 2022-06-28 03:25:49 +02:00
semantic-release-bot
5a4bd7a76e chore(release): 2.0.4 [skip ci]
## [2.0.4](https://github.com/revanced/revanced-patcher/compare/v2.0.3...v2.0.4) (2022-06-27)
2022-06-27 22:38:36 +00:00
Sculas
e5ca86fac6 build: update Apktool to disable 9patch decoder
for real for real, this time
2022-06-28 00:36:50 +02:00
semantic-release-bot
68d9e9f02c chore(release): 2.0.3 [skip ci]
## [2.0.3](https://github.com/revanced/revanced-patcher/compare/v2.0.2...v2.0.3) (2022-06-27)
2022-06-27 22:22:19 +00:00
Sculas
494a9a09ac build: update Apktool to disable 9patch decoder
for real, this time
2022-06-28 00:20:54 +02:00
semantic-release-bot
06a88839de chore(release): 2.0.2 [skip ci]
## [2.0.2](https://github.com/revanced/revanced-patcher/compare/v2.0.1...v2.0.2) (2022-06-27)
2022-06-27 22:05:56 +00:00
Sculas
4c41b955df ci: trigger release on build commits 2022-06-28 00:04:39 +02:00
Sculas
614e555f4c build: update Apktool to disable 9patch decoder 2022-06-28 00:01:38 +02:00
Lucaskyy
6bfe5716c3 feat: Improve Smali Compiler
- Branching support has been added. See InlineSmaliCompilerTest.kt for an example.
- Some other improvements have been made too.
2022-06-27 21:11:59 +02:00
semantic-release-bot
d6ed06a327 chore(release): 2.0.1 [skip ci]
## [2.0.1](https://github.com/revanced/revanced-patcher/compare/v2.0.0...v2.0.1) (2022-06-26)

### Bug Fixes

* use `Exception` instead of `MethodNotFoundException` ([2fc4ec4](2fc4ec4021))
2022-06-26 16:03:10 +00:00
oSumAtrIX
2fc4ec4021 fix: use Exception instead of MethodNotFoundException 2022-06-26 18:01:54 +02:00
Lucaskyy
f565c4f6a7 refactor: improve ResourceData.kt
Old methods have been marked as deprecated, and will be removed in the future.

- ResourceData.kt was made an Iterable<File>, and the forEach method was removed in favor of Kotlin's forEach function. (no modifications required)
- The resolve method was deprecated in favor of a new operator getter function, which can be either called using get(path) or data[path]. This keeps backwards compatibility with the old get method.
- The getXmlEditor method was deprecated in favor of the new xmlEditor variable, which is a XmlFileHolder which has an operator getter which acts like an array. This is syntactically better.
2022-06-26 17:14:38 +02:00
Lucaskyy
35749454ab refactor: remove deprecated methods in ResourceData.kt 2022-06-26 16:53:25 +02:00
Lucaskyy
2b492e7a5e refactor: cleanup code 2022-06-26 16:32:22 +02:00
Lucaskyy
081a5a6849 refactor: fmt ExampleBytecodePatch.kt 2022-06-26 16:21:55 +02:00
Lucaskyy
852ae7d8d1 refactor: move BytecodeData#proxy into class 2022-06-26 16:20:45 +02:00
semantic-release-bot
52f8a6a2eb chore(release): 2.0.0 [skip ci]
# [2.0.0](https://github.com/revanced/revanced-patcher/compare/v1.11.0...v2.0.0) (2022-06-26)

### Code Refactoring

* migrate from `Signature` to `Fingerprint` ([efa8ea1](efa8ea1445))

### BREAKING CHANGES

* Not backwards compatible, since a lot of classes where renamed.
2022-06-26 13:12:24 +00:00
oSumAtrIX
efa8ea1445 refactor: migrate from Signature to Fingerprint
BREAKING CHANGE: Not backwards compatible, since a lot of classes where renamed.
2022-06-26 15:10:54 +02:00
semantic-release-bot
c828fa2a27 chore(release): 1.11.0 [skip ci]
# [1.11.0](https://github.com/revanced/revanced-patcher/compare/v1.10.2...v1.11.0) (2022-06-24)

### Features

* add replace and remove extensions ([#50](https://github.com/revanced/revanced-patcher/issues/50)) ([92ac5e4](92ac5e4dc2))
2022-06-24 16:49:12 +00:00
bogadana
92ac5e4dc2 feat: add replace and remove extensions (#50) 2022-06-24 18:47:37 +02:00
semantic-release-bot
070c09cf71 chore(release): 1.10.2 [skip ci]
## [1.10.2](https://github.com/revanced/revanced-patcher/compare/v1.10.1...v1.10.2) (2022-06-23)

### Bug Fixes

* dexlib must be propagated ([b738dcd](b738dcd7ea))
2022-06-23 10:21:25 +00:00
Sculas
b738dcd7ea fix: dexlib must be propagated 2022-06-23 12:20:04 +02:00
semantic-release-bot
8efcf329bb chore(release): 1.10.1 [skip ci]
## [1.10.1](https://github.com/revanced/revanced-patcher/compare/v1.10.0...v1.10.1) (2022-06-23)

### Bug Fixes

* callback only when inteded ([e3bf367](e3bf367ad6))
* mutability of local variable `modified` ([0e87ef5](0e87ef56c4))
2022-06-23 06:59:43 +00:00
oSumAtrIX
0e87ef56c4 fix: mutability of local variable modified 2022-06-23 08:57:41 +02:00
oSumAtrIX
e3bf367ad6 fix: callback only when inteded 2022-06-23 08:54:47 +02:00
semantic-release-bot
3d61dacbda chore(release): 1.10.0 [skip ci]
# [1.10.0](https://github.com/revanced/revanced-patcher/compare/v1.9.0...v1.10.0) (2022-06-23)

### Features

* improve logging ([c20dfe1](c20dfe12d5))
2022-06-23 00:12:04 +00:00
oSumAtrIX
c20dfe12d5 feat: improve logging 2022-06-23 02:10:43 +02:00
semantic-release-bot
78663cde88 chore(release): 1.9.0 [skip ci]
# [1.9.0](https://github.com/revanced/revanced-patcher/compare/v1.8.0...v1.9.0) (2022-06-22)

### Bug Fixes

* callback for each file instead of class ([930768d](930768dfb3))

### Features

* yield the patch result ([dde5385](dde5385232))
2022-06-22 23:43:17 +00:00
oSumAtrIX
dde5385232 feat: yield the patch result 2022-06-23 01:41:52 +02:00
oSumAtrIX
930768dfb3 fix: callback for each file instead of class 2022-06-23 01:41:52 +02:00
semantic-release-bot
1f4bc5079f chore(release): 1.8.0 [skip ci]
# [1.8.0](https://github.com/revanced/revanced-patcher/compare/v1.7.2...v1.8.0) (2022-06-22)

### Features

* logging class ([caf2745](caf2745805))
2022-06-22 23:25:29 +00:00
oSumAtrIX
caf2745805 feat: logging class 2022-06-23 01:23:35 +02:00
oSumAtrIX
a4529c3fee refactor: logging and exception strings 2022-06-22 16:47:58 +02:00
semantic-release-bot
835c0f9f7a chore(release): 1.7.2 [skip ci]
## [1.7.2](https://github.com/revanced/revanced-patcher/compare/v1.7.1...v1.7.2) (2022-06-22)

### Bug Fixes

* add execute permission to `./gradlew` file ([#46](https://github.com/revanced/revanced-patcher/issues/46)) ([34f607a](34f607aa24))
2022-06-22 14:17:16 +00:00
Oskar
34f607aa24 fix: add execute permission to ./gradlew file (#46) 2022-06-22 16:16:00 +02:00
Lucaskyy
0f38b94701 Merge remote-tracking branch 'origin/main' into main 2022-06-22 16:13:34 +02:00
Lucaskyy
39bb1b25dc refactor: add logging 2022-06-22 16:13:23 +02:00
Lucaskyy
4fc63a4d8a refactor: add callbacks for applyPatches & addFiles 2022-06-22 15:37:33 +02:00
semantic-release-bot
6037397bc2 chore(release): 1.7.1 [skip ci]
## [1.7.1](https://github.com/revanced/revanced-patcher/compare/v1.7.0...v1.7.1) (2022-06-22)

### Reverts

* revert "feat: use of `java.util.logging.Logger`" ([e8488b3](e8488b3e86))
2022-06-22 13:07:22 +00:00
Lucaskyy
273dd86b65 chore: remove ExtFile import 2022-06-22 15:04:05 +02:00
Lucaskyy
e8488b3e86 revert "feat: use of java.util.logging.Logger"
This reverts commit 9c39c9efdb.
This reverts commit 8f66f9f606.
2022-06-22 15:03:30 +02:00
semantic-release-bot
c13361823d chore(release): 1.7.0 [skip ci]
# [1.7.0](https://github.com/revanced/revanced-patcher/compare/v1.6.0...v1.7.0) (2022-06-22)

### Features

* migrate logger to `slf4j` ([8f66f9f](8f66f9f606))
2022-06-22 12:18:57 +00:00
oSumAtrIX
8f66f9f606 feat: migrate logger to slf4j 2022-06-22 14:17:09 +02:00
semantic-release-bot
a123026f46 chore(release): 1.6.0 [skip ci]
# [1.6.0](https://github.com/revanced/revanced-patcher/compare/v1.5.0...v1.6.0) (2022-06-22)

### Features

* use of `java.util.logging.Logger` ([9c39c9e](9c39c9efdb))
2022-06-22 11:48:43 +00:00
oSumAtrIX
9c39c9efdb feat: use of java.util.logging.Logger 2022-06-22 13:45:13 +02:00
semantic-release-bot
3ee1c01430 chore(release): 1.5.0 [skip ci]
# [1.5.0](https://github.com/revanced/revanced-patcher/compare/v1.4.0...v1.5.0) (2022-06-22)

### Features

* use streams to write the dex files ([64bae88](64bae884dc))
2022-06-22 01:21:33 +00:00
oSumAtrIX
64bae884dc feat: use streams to write the dex files 2022-06-22 03:19:39 +02:00
semantic-release-bot
e94a706949 chore(release): 1.4.0 [skip ci]
# [1.4.0](https://github.com/revanced/revanced-patcher/compare/v1.3.4...v1.4.0) (2022-06-22)

### Features

* return a `File` instance instead of `ExtFile` ([68174bb](68174bbd6b))
2022-06-22 00:55:56 +00:00
oSumAtrIX
89bb43066b build: use dependencies as implementations instead of apis 2022-06-22 02:54:23 +02:00
oSumAtrIX
68174bbd6b feat: return a File instance instead of ExtFile 2022-06-22 02:53:37 +02:00
semantic-release-bot
d05c9416d6 chore(release): 1.3.4 [skip ci]
## [1.3.4](https://github.com/revanced/revanced-patcher/compare/v1.3.3...v1.3.4) (2022-06-21)

### Bug Fixes

* `String.toInstructions` defaulting `forStaticMethod` to `false` ([5a2f02b](5a2f02b97d)), closes [revanced/revanced-patches#46](https://github.com/revanced/revanced-patches/issues/46)
2022-06-21 21:53:33 +00:00
oSumAtrIX
5a2f02b97d fix: String.toInstructions defaulting forStaticMethod to false
Fixes revanced/revanced-patches#46
2022-06-21 23:52:09 +02:00
semantic-release-bot
a3005fa08e chore(release): 1.3.3 [skip ci]
## [1.3.3](https://github.com/revanced/revanced-patcher/compare/v1.3.2...v1.3.3) (2022-06-21)

### Bug Fixes

* add docs (trigger release) ([6628b78](6628b7870f))

### Reverts

* propagate dependencies ([365e1d7](365e1d7a45))
2022-06-21 19:04:06 +00:00
Lucaskyy
6628b7870f fix: add docs (trigger release) 2022-06-21 21:02:50 +02:00
Lucaskyy
a6411245aa Merge remote-tracking branch 'origin/main' into main 2022-06-21 20:50:11 +02:00
Lucaskyy
365e1d7a45 revert: propagate dependencies
guess it doesn't work when not propagating them
2022-06-21 20:50:00 +02:00
semantic-release-bot
4507cd2353 chore(release): 1.3.2 [skip ci]
## [1.3.2](https://github.com/revanced/revanced-patcher/compare/v1.3.1...v1.3.2) (2022-06-21)

### Bug Fixes

* return resourceFile to caller ([1f75777](1f75777cf9))
2022-06-21 18:45:16 +00:00
Lucaskyy
1f75777cf9 fix: return resourceFile to caller 2022-06-21 20:43:47 +02:00
Lucaskyy
28d5468b07 build: do not propagate all dependencies 2022-06-21 20:29:37 +02:00
semantic-release-bot
746496125d chore(release): 1.3.1 [skip ci]
## [1.3.1](https://github.com/revanced/revanced-patcher/compare/v1.3.0...v1.3.1) (2022-06-21)

### Bug Fixes

* `InlineSmaliCompiler.compile` using 0 registers instead of 1 by default ([835a421](835a421cc0))
2022-06-21 15:48:43 +00:00
oSumAtrIX
835a421cc0 fix: InlineSmaliCompiler.compile using 0 registers instead of 1 by default 2022-06-21 17:46:43 +02:00
semantic-release-bot
99342fe033 chore(release): 1.3.0 [skip ci]
# [1.3.0](https://github.com/revanced/revanced-patcher/compare/v1.2.9...v1.3.0) (2022-06-20)

### Features

* `parametersCount` for `InlineSmaliCompiler` instead of `parameters` ([ad6c5c8](ad6c5c8273))
* simplify adding instructions ([e47b67d](e47b67d7ec))
2022-06-20 19:22:22 +00:00
oSumAtrIX
e47b67d7ec feat: simplify adding instructions 2022-06-20 21:20:51 +02:00
oSumAtrIX
ad6c5c8273 feat: parametersCount for InlineSmaliCompiler instead of parameters 2022-06-20 20:10:11 +02:00
oSumAtrIX
fd690acd61 refactor: add internal attribute to signatures field 2022-06-20 20:10:06 +02:00
semantic-release-bot
e698b02bf6 chore(release): 1.2.9 [skip ci]
## [1.2.9](https://github.com/revanced/revanced-patcher/compare/v1.2.8...v1.2.9) (2022-06-20)

### Bug Fixes

* update apktool ([ab866bb](ab866bb8ef))
2022-06-20 15:08:57 +00:00
Lucaskyy
ab866bb8ef fix: update apktool 2022-06-20 17:07:04 +02:00
semantic-release-bot
714a98422d chore(release): 1.2.8 [skip ci]
## [1.2.8](https://github.com/revanced/revanced-patcher/compare/v1.2.7...v1.2.8) (2022-06-18)

### Bug Fixes

* update apktool ([051afd9](051afd98d0))
2022-06-18 21:51:07 +00:00
Sculas
051afd98d0 fix: update apktool 2022-06-18 23:49:41 +02:00
semantic-release-bot
d38cf6a229 chore(release): 1.2.7 [skip ci]
## [1.2.7](https://github.com/revanced/revanced-patcher/compare/v1.2.6...v1.2.7) (2022-06-18)

### Bug Fixes

* version not working with apktool due to cache ([03f5ee0](03f5ee088b))
2022-06-18 21:17:22 +00:00
Sculas
03f5ee088b fix: version not working with apktool due to cache 2022-06-18 23:15:33 +02:00
semantic-release-bot
5d0fd48b15 chore(release): 1.2.6 [skip ci]
## [1.2.6](https://github.com/revanced/revanced-patcher/compare/v1.2.5...v1.2.6) (2022-06-18)

### Bug Fixes

* remove javadoc jar (also trigger release) ([56f6ca3](56f6ca3891))
2022-06-18 20:54:29 +00:00
Sculas
56f6ca3891 fix: remove javadoc jar (also trigger release) 2022-06-18 22:52:49 +02:00
semantic-release-bot
9e0a74fcfb chore(release): 1.2.5 [skip ci]
## [1.2.5](https://github.com/revanced/revanced-patcher/compare/v1.2.4...v1.2.5) (2022-06-17)

### Bug Fixes

* goodbye security ([8f3ac77](8f3ac7702a))
2022-06-17 16:13:47 +00:00
Sculas
8f3ac7702a fix: goodbye security 2022-06-17 18:12:18 +02:00
semantic-release-bot
7b65f2d02c chore(release): 1.2.4 [skip ci]
## [1.2.4](https://github.com/revanced/revanced-patcher/compare/v1.2.3...v1.2.4) (2022-06-15)

### Reverts

* "fix: enforce aapt v1" ([dfd8a24](dfd8a24512))
2022-06-15 19:41:28 +00:00
Lucaskyy
2a1b2df56b Merge remote-tracking branch 'origin/main' into main 2022-06-15 21:39:42 +02:00
Lucaskyy
dfd8a24512 revert: "fix: enforce aapt v1"
This reverts commit cff87ff077.
2022-06-15 21:39:27 +02:00
semantic-release-bot
a3efd212fc chore(release): 1.2.3 [skip ci]
## [1.2.3](https://github.com/revanced/revanced-patcher/compare/v1.2.2...v1.2.3) (2022-06-14)

### Bug Fixes

* enforce aapt v1 ([cff87ff](cff87ff077))
2022-06-14 22:26:32 +00:00
Lucaskyy
3e610f7ba9 Merge remote-tracking branch 'origin/main' into main 2022-06-15 00:25:21 +02:00
Lucaskyy
cff87ff077 fix: enforce aapt v1 2022-06-15 00:25:06 +02:00
semantic-release-bot
54aa04ca34 chore(release): 1.2.2 [skip ci]
## [1.2.2](https://github.com/revanced/revanced-patcher/compare/v1.2.1...v1.2.2) (2022-06-14)

### Bug Fixes

* enforce aapt v2 ([b68b0bf](b68b0bf3d7))
2022-06-14 20:35:38 +00:00
Lucaskyy
0eda84eaef Merge remote-tracking branch 'origin/main' into main 2022-06-14 22:34:21 +02:00
Lucaskyy
b68b0bf3d7 fix: enforce aapt v2 2022-06-14 22:34:10 +02:00
semantic-release-bot
c692202f67 chore(release): 1.2.1 [skip ci]
## [1.2.1](https://github.com/revanced/revanced-patcher/compare/v1.2.0...v1.2.1) (2022-06-14)

### Bug Fixes

* Patcher setting BuildOptions too late ([6a5c873](6a5c8735fb))
2022-06-14 16:25:08 +00:00
Lucaskyy
8ce3535427 Merge remote-tracking branch 'origin/main' into main 2022-06-14 18:23:49 +02:00
Lucaskyy
6a5c8735fb fix: Patcher setting BuildOptions too late
This causes the Manager to crash, due to a stupid bug in Apktool which is prevented by setting a valid frameworkFolderLocation.
2022-06-14 18:23:40 +02:00
semantic-release-bot
8f32bc9c08 chore(release): 1.2.0 [skip ci]
# [1.2.0](https://github.com/revanced/revanced-patcher/compare/v1.1.0...v1.2.0) (2022-06-14)

### Features

* allow custom framework path to be specified ([d3a580e](d3a580ea19))
2022-06-14 15:50:24 +00:00
Lucaskyy
d3a580ea19 feat: allow custom framework path to be specified 2022-06-14 17:49:07 +02:00
oSumAtrIX
4c8eb0e5c7 refactor: gradle build script 2022-06-14 01:34:48 +02:00
semantic-release-bot
bc92eb7fd8 chore(release): 1.1.0 [skip ci]
# [1.1.0](https://github.com/revanced/revanced-patcher/compare/v1.0.0...v1.1.0) (2022-06-11)

### Bug Fixes

* resource patcher ([31815ca](31815ca9ea))
* update apktool to fork ([566ecef](566ecefa2b))

### Features

* allow custom aapt path to be specified ([8eb4a8f](8eb4a8f87a))
2022-06-11 23:25:19 +00:00
oSumAtrIX
cf89bd4171 Merge pull request #39 from revanced/non-root
fix: resource patcher
2022-06-12 01:24:04 +02:00
Lucaskyy
566ecefa2b fix: update apktool to fork 2022-06-11 20:39:29 +02:00
Lucaskyy
8eb4a8f87a feat: allow custom aapt path to be specified 2022-06-11 20:08:00 +02:00
oSumAtrIX
afcba5c212 refactor: simplify code by removing the with block 2022-06-11 19:45:11 +02:00
oSumAtrIX
2dcbd8d079 refactor: use include annotation parameter instead of excludeByDefault 2022-06-11 19:14:19 +02:00
oSumAtrIX
81895c7d5c Merge remote-tracking branch 'origin/non-root' into non-root
# Conflicts:
#	src/main/kotlin/app/revanced/patcher/Patcher.kt
2022-06-11 18:56:38 +02:00
Lucaskyy
22267883b1 refactor: get rid of all useless let blocks 2022-06-11 16:56:05 +02:00
oSumAtrIX
26fca60b53 refactor: use also instead of let where possible 2022-06-11 16:24:49 +02:00
oSumAtrIX
31815ca9ea fix: resource patcher 2022-06-11 06:36:13 +02:00
semantic-release-bot
1ce6098cad chore(release): 1.0.0 [skip ci]
# 1.0.0 (2022-06-05)

### Bug Fixes

* `compareSignatureToMethod` not matching correctly in case opcodes are null ([cca12aa](cca12aa34a))
* `ConcurrentModificationException` while iterating through `proxies` and modifying it ([6cb7cdb](6cb7cdb0b2))
* `JarPatchBundle` loading non-class files to class loader ([849616d](849616dc2b))
* `PackageMetadata` ([7399450](7399450139))
* `replaceWith` not replacing classes with used class proxies ([4178a1e](4178a1eedc))
* adding existing classes to the patchers cache ([9659a61](9659a61c5c))
* always return PatchResultSuccess on patch success ([996c4ac](996c4acb20))
* applying no patches throwing error ([5ca5a1c](5ca5a1c29e))
* applyPatches not returning successful patches ([f806cb3](f806cb38c5))
* avoid ignoring test resources (fixes [#1](https://github.com/revanced/revanced-patcher/issues/1)) ([d5a3c76](d5a3c76389))
* Classes not being written properly because of array shifting ([6e4db11](6e4db110c8))
* current must be calculated after increment ([5f12bab](5f12bab5df))
* failing tests temporarily ([fc05fe7](fc05fe79de))
* fix classes having multiple instances of fields ([7cc8a7d](7cc8a7dec3))
* fix classes having multiple method instances ([398239d](398239dc10))
* Fixed writer & signature resolver, improved tests & speed, minor refactoring ([e6c2501](e6c2501539))
* fuzzy resolver warning params were turned around ([e5bea06](e5bea06353))
* give ClassWriter a ClassReader for symtable ([41749ba](41749ba829))
* **gradle:** publish source and javadocs ([c236ebe](c236ebe078))
* incorrect pattern offset ([f3b5f67](f3b5f67b39))
* **Io:** fix finding classes by name ([b957501](b957501e70))
* **Io:** JAR loading and saving ([#8](https://github.com/revanced/revanced-patcher/issues/8)) ([310a7c4](310a7c446b))
* make `methodMetadata` nullable in `MethodSignatureMetadata` ([4e56652](4e56652429))
* make warnings nullable instead of lateinit ([8f1a629](8f1a629191))
* match to correct signature method parameters ([1ee2e4b](1ee2e4ba56))
* **MethodResolver:** fix cd57a8c9a0 ([cbd8df2](cbd8df2df0))
* **MethodResolver:** strip labels and line numbers so opcode patterns match ([699c730](699c730a7c))
* **MethodResolver:** strip labels nodes so opcode patterns match ([82c5306](82c530650f))
* MethodSignature#resolved throwing an exception ([c612676](c612676543))
* Move proxy package out of cache package ([ce21bd6](ce21bd60f3))
* null check causing an exception ([338bd9f](338bd9f739))
* nullable signature members ([#10](https://github.com/revanced/revanced-patcher/issues/10)) ([674461f](674461f08d))
* Patch should have access to the Cache ([4dd820f](4dd820ffdf))
* Patcher not writing resolved methods ([fac44a5](fac44a50c3))
* qualifying `Element` with wrong package ([024fa86](024fa867e1))
* reaching all constructors not possible ([c459beb](c459beb5f8))
* reformat (trigger release) ([bf48945](bf4894592b))
* remove broken code ([0e72a6e](0e72a6e85f))
* remove dependency to fork of Apktool ([11abc67](11abc67d9a))
* remove leftover debug code ([0f30eac](0f30eac32c))
* return mutable set of classes ([66a9b76](66a9b76845))
* returning failure on success ([48c4ea2](48c4ea2f6d))
* Search method map for existing class proxy ([a1e909b](a1e909b163))
* set index for insertAt to 0 by default ([d5b4c99](d5b4c99c00))
* set marklimit to Integer.MAX_VALUE ([e6e468f](e6e468fbb5))
* string signature in `SignatureResolver` ([e5ae970](e5ae970009))
* Suppress unused for addFiles ([3d6a1d3](3d6a1d38f3))
* throwing in case the opcode patterns do not match ([3144ec8](3144ec872a))
* use Array instead of Iterable for methodParameters ([dfac8f0](dfac8f03a3))
* using old instance of `Androlib` when saving ([a4d8be2](a4d8be20fc))
* workflow on dev branch ([428f7f4](428f7f4dec))
* write all classes ([f068fc8](f068fc87ff))

### Code Refactoring

* bump multidexlib2 to 2.5.2.r2 ([a6c6b49](a6c6b4979a))
* Change all references from Array to Iterable ([72f3cad](72f3cad3f9))
* convert Patch to abstract class ([cb9b1b9](cb9b1b9416))
* Optimize Signature class ([#11](https://github.com/revanced/revanced-patcher/issues/11)) ([7faa001](7faa001406))
* Rename `net.revanced` to `app.revanced` ([7087230](70872307e3))

### Features

* `Dependencies` annotation ([893d4c6](893d4c699b))
* `PatchLoader` ([ec9fd15](ec9fd15f9b))
* Add `findParentMethod` utility method ([#4](https://github.com/revanced/revanced-patcher/issues/4)) ([bbb2c54](bbb2c547aa))
* add `MethodWalker` ([7755bbc](7755bbc645))
* add `p` naming scheme to smali compiler ([79909cf](79909cf260))
* add extensions for cloning methods ([01bfbd6](01bfbd656e))
* add findClass method with className ([4087f49](4087f49863))
* Add first tests ([544bcf7](544bcf76bd))
* add fuzzy resolver ([7a56dca](7a56dca004))
* add immutableMethod ([c63b20f](c63b20fa65))
* add inline smali compiler ([bfe4e3e](bfe4e3e298))
* add missing test for fields ([6b8b057](6b8b0573d4))
* add or extension for AccessFlags ([00c85b5](00c85b5d75))
* Add patch metadata ([642e903](642e9031eb)), closes [ReVancedTeam/revanced-patches#1](https://github.com/ReVancedTeam/revanced-patches/issues/1)
* add SafeClassWriter ([6626014](6626014ef3))
* Add warnings for Fuzzy resolver ([715a2ad](715a2ad025))
* allow classes to be overwritten in addFiles and resolve signatures when applyPatches is called ([1db735b](1db735b1e2))
* Allow unknown opcodes using `null` ([0e5f4ba](0e5f4ba2d5))
* Finish first patcher test ([0d8d19e](0d8d19e708))
* Improve `SignatureResolver` ([139a23b](139a23b750))
* migrate to `DexPatchBundle` and `JarPatchBundle` ([8615798](8615798711))
* migrate to dexlib ([3651981](3651981161))
* Minor refactor and return proxy, if class has been proxied already ([4b26305](4b26305bd5))
* optional `forStaticMethod` parameter for `InlineSmaliCompiler.compileMethodInstructions` ([41e8860](41e88605c3))
* patch dependencies annotation and `PatcherOptions` ([6c65952](6c65952d80))
* properly manage `ClassProxy` & add `ProxyBackedClassList` ([6cb1fdf](6cb1fdf617))
* remaining mutable `EncodedValue` classes ([3f97cc8](3f97cc8e1f))
* string signature ([#22](https://github.com/revanced/revanced-patcher/issues/22)) ([612515a](612515acf8))
* use annotations instead of metadata objects ([d20f7fd](d20f7fd6e1))
* utility functions to get metadata of patch & sigs ([54511a4](54511a4fc6))

### Performance Improvements

* check type instead of class ([c7ef264](c7ef2644d8))
* decode manifest only when not using resource patcher ([4f60bea](4f60bea81e))
* depend on `androlib` instead of `ApkDecoder` ([cc9416d](cc9416dd11))
* do not resolve empty signatures list ([b1eebc9](b1eebc99a7))
* lazy-ify all mutable clones ([d18a3b6](d18a3b6a28))
* optimize indexOf call away ([9991f39](9991f39c9a))
* use Set instead of List since there are no dupes ([e65ebd2](e65ebd27c2))
* use String List and compare instead of any lambda ([5bd416b](5bd416b409))

### Reverts

* AccessFlag extensions not working with IDE ([0bfb92a](0bfb92a0cb))
* previous commits check for dupes in dexFile, not cache ([e810197](e810197e2a))

### BREAKING CHANGES

* arrayOf has to be changed to listOf.
* Method signature of Patcher#save() was changed to comply with the changes of multidexlib2.
* Removed usage of ASM library
* Array<Int> was changed to IntArray. This breaks existing patches.
* Package name was changed from "net.revanced" to "app.revanced"
* Method signature of execute() was changed to include the cache, this will break existing implementations of the Patch class.
* Patch class is now an abstract class. You must implement it. You can use anonymous implements, like done in the tests.
2022-06-05 06:10:56 +00:00
semantic-release-bot
46a6396114 chore(release): 1.0.0-dev.18 [skip ci]
# [1.0.0-dev.18](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.17...v1.0.0-dev.18) (2022-06-04)

### Features

* `Dependencies` annotation ([83d608a](83d608ac06))
* optional `forStaticMethod` parameter for `InlineSmaliCompiler.compileMethodInstructions` ([28b9847](28b98478e4))
2022-06-05 08:03:41 +02:00
oSumAtrIX
41e88605c3 feat: optional forStaticMethod parameter for InlineSmaliCompiler.compileMethodInstructions 2022-06-05 08:03:40 +02:00
oSumAtrIX
893d4c699b feat: Dependencies annotation 2022-06-05 08:03:40 +02:00
semantic-release-bot
bf8655ead8 chore(release): 1.0.0-dev.17 [skip ci]
# [1.0.0-dev.17](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.16...v1.0.0-dev.17) (2022-05-31)

### Features

* patch dependencies annotation and `PatcherOptions` ([8442991](8442991290))
2022-06-05 08:03:40 +02:00
oSumAtrIX
6c65952d80 feat: patch dependencies annotation and PatcherOptions 2022-06-05 08:03:39 +02:00
semantic-release-bot
26f3e7336b chore(release): 1.0.0-dev.16 [skip ci]
# [1.0.0-dev.16](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.15...v1.0.0-dev.16) (2022-05-27)

### Bug Fixes

* `JarPatchBundle` loading non-class files to class loader ([3f0c740](3f0c740200))
* remove dependency to fork of Apktool ([0fa529f](0fa529fcdf))

### Features

* migrate to `DexPatchBundle` and `JarPatchBundle` ([7573db2](7573db2575))
2022-06-05 08:03:39 +02:00
oSumAtrIX
849616dc2b fix: JarPatchBundle loading non-class files to class loader 2022-06-05 08:03:38 +02:00
oSumAtrIX
e8a131fb08 chore: update gradlew wrapper 2022-06-05 08:03:38 +02:00
oSumAtrIX
11abc67d9a fix: remove dependency to fork of Apktool 2022-06-05 08:03:38 +02:00
oSumAtrIX
8615798711 feat: migrate to DexPatchBundle and JarPatchBundle
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:37 +02:00
semantic-release-bot
070e02ea28 chore(release): 1.0.0-dev.15 [skip ci]
# [1.0.0-dev.15](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.14...v1.0.0-dev.15) (2022-05-25)

### Features

* utility functions to get metadata of patch & sigs ([72f16b7](72f16b7785))
2022-06-05 08:03:37 +02:00
Lucaskyy
54511a4fc6 feat: utility functions to get metadata of patch & sigs 2022-06-05 08:03:37 +02:00
Lucaskyy
94f3c9116e chore: fix typo 2022-06-05 08:03:36 +02:00
semantic-release-bot
fe56c0cadb chore(release): 1.0.0-dev.14 [skip ci]
# [1.0.0-dev.14](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.13...v1.0.0-dev.14) (2022-05-24)

### Bug Fixes

* reformat (trigger release) ([45a167e](45a167e785))
2022-06-05 08:03:36 +02:00
Lucaskyy
bf4894592b fix: reformat (trigger release) 2022-06-05 08:03:36 +02:00
Lucaskyy
5a96f2d99f refactor: use apktool fork
also fixed some compilation issues
2022-06-05 08:03:35 +02:00
semantic-release-bot
839a5ef22a chore(release): 1.0.0-dev.13 [skip ci]
# [1.0.0-dev.13](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.12...v1.0.0-dev.13) (2022-05-24)

### Performance Improvements

* decode manifest only when not using resource patcher ([40b1fa4](40b1fa43e1))
2022-06-05 08:03:35 +02:00
oSumAtrIX
0ebdb100fd refactor: use resourceData.get(path) instead of a reader/writer
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:35 +02:00
oSumAtrIX
4f60bea81e perf: decode manifest only when not using resource patcher
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:34 +02:00
oSumAtrIX
1a49d9439f chore: update kotlin jvm
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:34 +02:00
oSumAtrIX
5535eb4f01 refactor: improve ExampleResourcePatch
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:33 +02:00
oSumAtrIX
5dc6aa9bfd chore: update dependencies
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:33 +02:00
semantic-release-bot
6c0d28191b chore(release): 1.0.0-dev.12 [skip ci]
# [1.0.0-dev.12](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.11...v1.0.0-dev.12) (2022-05-22)

### Bug Fixes

* using old instance of `Androlib` when saving ([5630e49](5630e49663))
2022-06-05 08:03:33 +02:00
semantic-release-bot
9d067b9b0d chore(release): 1.0.0-dev.11 [skip ci]
# [1.0.0-dev.11](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.10...v1.0.0-dev.11) (2022-05-22)

### Features

* `PatchLoader` ([1a99eca](1a99ecaffe))
* use annotations instead of metadata objects ([6726884](6726884be5))
2022-06-05 08:03:32 +02:00
oSumAtrIX
a4d8be20fc fix: using old instance of Androlib when saving
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:32 +02:00
oSumAtrIX
ec9fd15f9b feat: PatchLoader
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:32 +02:00
oSumAtrIX
d20f7fd6e1 feat: use annotations instead of metadata objects
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:31 +02:00
semantic-release-bot
ebbcf78e56 chore(release): 1.0.0-dev.10 [skip ci]
# [1.0.0-dev.10](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.9...v1.0.0-dev.10) (2022-05-07)

### Bug Fixes

* qualifying `Element` with wrong package ([4d74de4](4d74de4061))
2022-06-05 08:03:31 +02:00
oSumAtrIX
024fa867e1 fix: qualifying Element with wrong package
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:31 +02:00
semantic-release-bot
e506d8fd8c chore(release): 1.0.0-dev.9 [skip ci]
# [1.0.0-dev.9](https://github.com/revanced/revanced-patcher/compare/v1.0.0-dev.8...v1.0.0-dev.9) (2022-05-07)

### Bug Fixes

* `compareSignatureToMethod` not matching correctly in case opcodes are null ([5ae5e98](5ae5e98f1f))
* `ConcurrentModificationException` while iterating through `proxies` and modifying it ([bfeeaf4](bfeeaf4435))
* `PackageMetadata` ([305a817](305a81793a))
* `replaceWith` not replacing classes with used class proxies ([f0f3403](f0f34031dd))
* adding existing classes to the patchers cache ([4281546](4281546f69))
* always return PatchResultSuccess on patch success ([866b03a](866b03af21))
* applying no patches throwing error ([f88c118](f88c11820d))
* applyPatches not returning successful patches ([8b70bb4](8b70bb4290))
* Classes not being written properly because of array shifting ([1471956](147195647c))
* failing tests temporarily ([66b08f8](66b08f8b3a))
* fix classes having multiple instances of fields ([b711b80](b711b8001e))
* fix classes having multiple method instances ([12c10d8](12c10d8c64))
* Fixed writer & signature resolver, improved tests & speed, minor refactoring ([bb42fa3](bb42fa3c6f))
* fuzzy resolver warning params were turned around ([d49df10](d49df10a3c))
* incorrect pattern offset ([03700ff](03700ffa51))
* make `methodMetadata` nullable in `MethodSignatureMetadata` ([864e38c](864e38c069))
* make warnings nullable instead of lateinit ([04b49b8](04b49b8b66))
* match to correct signature method parameters ([c49071a](c49071aff7))
* MethodSignature#resolved throwing an exception ([82b1e66](82b1e66d54))
* Move proxy package out of cache package ([6bc4e7e](6bc4e7eab7))
* null check causing an exception ([560c485](560c485ab0))
* Patcher not writing resolved methods ([d15240d](d15240d033))
* reaching all constructors not possible ([37fa994](37fa9949ec))
* remove leftover debug code ([4458141](4458141d6d))
* return mutable set of classes ([84bc7e0](84bc7e0dc7))
* returning failure on success ([3b68d5c](3b68d5c65e))
* Search method map for existing class proxy ([d5e694c](d5e694c306))
* string signature in `SignatureResolver` ([ac36d19](ac36d19693))
* Suppress unused for addFiles ([a0d6d46](a0d6d46217))
* throwing in case the opcode patterns do not match ([f72dd68](f72dd68ec5))
* use Array instead of Iterable for methodParameters ([312235b](312235b194))
* write all classes ([6ad51aa](6ad51aad9a))

### Code Refactoring

* bump multidexlib2 to 2.5.2.r2 ([32e6458](32e645850d))
* Change all references from Array to Iterable ([264989f](264989f488))

### Features

* add `MethodWalker` ([659e108](659e1087c9))
* add `p` naming scheme to smali compiler ([38556d6](38556d61ab))
* add extensions for cloning methods ([df7503b](df7503b47b))
* add findClass method with className ([78235d1](78235d1abe))
* Add first tests ([6767c8f](6767c8fbc1))
* add fuzzy resolver ([a492808](a492808021))
* add immutableMethod ([eed1cfd](eed1cfda7b))
* add inline smali compiler ([dbafe2a](dbafe2ab37))
* add missing test for fields ([4022b8b](4022b8b847))
* add or extension for AccessFlags ([aec5eeb](aec5eeb597))
* Add patch metadata ([8544fc4](8544fc4cbc)), closes [ReVancedTeam/revanced-patches#1](https://github.com/ReVancedTeam/revanced-patches/issues/1)
* Add warnings for Fuzzy resolver ([643a14e](643a14e664))
* allow classes to be overwritten in addFiles and resolve signatures when applyPatches is called ([5f71a34](5f71a342ac))
* Allow unknown opcodes using `null` ([f4a47d4](f4a47d4dc8))
* Finish first patcher test ([a9e4e8a](a9e4e8ac32))
* Improve `SignatureResolver` ([88a6a27](88a6a27302))
* migrate to dexlib ([be51f42](be51f42710))
* Minor refactor and return proxy, if class has been proxied already ([2d3c611](2d3c61113d))
* properly manage `ClassProxy` & add `ProxyBackedClassList` ([2319787](23197879b2))
* remaining mutable `EncodedValue` classes ([7d38bb0](7d38bb0baa))
* string signature ([#22](https://github.com/revanced/revanced-patcher/issues/22)) ([c245edb](c245edb0c5))

### Performance Improvements

* depend on `androlib` instead of `ApkDecoder` ([e5c054a](e5c054ac2f))
* do not resolve empty signatures list ([1f7bf3a](1f7bf3ac6c))
* lazy-ify all mutable clones ([05e4400](05e44007d8))
* optimize indexOf call away ([f8e978a](f8e978af88))
* use Set instead of List since there are no dupes ([6221387](622138736d))
* use String List and compare instead of any lambda ([aed4fd9](aed4fd9a3c))

### Reverts

* AccessFlag extensions not working with IDE ([e161f7f](e161f7fea4))
* previous commits check for dupes in dexFile, not cache ([433914f](433914feda))

### BREAKING CHANGES

* arrayOf has to be changed to listOf.
* Method signature of Patcher#save() was changed to comply with the changes of multidexlib2.
* Removed usage of ASM library
2022-06-05 08:03:30 +02:00
oSumAtrIX
f5b5c52e55 chore: bump java-version for action setup-java
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:30 +02:00
oSumAtrIX
fc05fe79de fix: failing tests temporarily
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:29 +02:00
j4k0xb
79909cf260 feat: add p naming scheme to smali compiler 2022-06-05 08:03:29 +02:00
autergame
8f12873200 Replace ReVancedTeam with revanced in build.gradle.kts 2022-06-05 08:03:29 +02:00
oSumAtrIX
cc9416dd11 perf: depend on androlib instead of ApkDecoder
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:28 +02:00
oSumAtrIX
99319e63da add: resource patcher
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:28 +02:00
oSumAtrIX
c459beb5f8 fix: reaching all constructors not possible
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:28 +02:00
oSumAtrIX
e5ae970009 fix: string signature in SignatureResolver
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:27 +02:00
oSumAtrIX
612515acf8 feat: string signature (#22)
* feat: string signature

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>

* fix: signature in test

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>

* fix: make string signature optional

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>

* fix: use of `compareOpcodes` when comparing string signatures

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>

* add: `PackageMetadata` for signatures

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:27 +02:00
oSumAtrIX
b1eebc99a7 perf: do not resolve empty signatures list
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:27 +02:00
oSumAtrIX
6cb7cdb0b2 fix: ConcurrentModificationException while iterating through proxies and modifying it
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:26 +02:00
oSumAtrIX
beff1df9b0 refactor: resolve signatures automatically
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:26 +02:00
oSumAtrIX
f58a498849 add: applyProxies method
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:26 +02:00
oSumAtrIX
6cb1fdf617 feat: properly manage ClassProxy & add ProxyBackedClassList
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:25 +02:00
oSumAtrIX
7399450139 fix: PackageMetadata
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:25 +02:00
oSumAtrIX
193eae298a add: PackageMetadata for signatures
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:25 +02:00
oSumAtrIX
4e56652429 fix: make methodMetadata nullable in MethodSignatureMetadata
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:24 +02:00
oSumAtrIX
7755bbc645 feat: add MethodWalker
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:24 +02:00
Lucaskyy
f3b5f67b39 fix: incorrect pattern offset 2022-06-05 08:03:24 +02:00
Lucaskyy
7f18bbf66e docs: fix improper docs for fuzzy resolver Warning 2022-06-05 08:03:23 +02:00
oSumAtrIX
c8b68e36e0 refactor: better naming for resolver warning parameters
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:23 +02:00
oSumAtrIX
5ca5a1c29e fix: applying no patches throwing error
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:23 +02:00
oSumAtrIX
d677d9e800 refact: better parameter names for Warning
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:22 +02:00
Lucaskyy
e5bea06353 fix: fuzzy resolver warning params were turned around 2022-06-05 08:03:22 +02:00
Lucaskyy
8f1a629191 fix: make warnings nullable instead of lateinit 2022-06-05 08:03:22 +02:00
Lucaskyy
e6086511e5 refactor: remove all parameter names 2022-06-05 08:03:21 +02:00
Lucaskyy
c612676543 fix: MethodSignature#resolved throwing an exception 2022-06-05 08:03:21 +02:00
Lucaskyy
bca948658e test: Add tests for unknown opcodes 2022-06-05 08:03:20 +02:00
Lucaskyy
0e5f4ba2d5 feat: Allow unknown opcodes using null
This is the same as `??` in IDA signatures.
2022-06-05 08:03:20 +02:00
Lucaskyy
6ca05769ef chore: remove todo 2022-06-05 08:03:20 +02:00
Lucaskyy
c21e5affba refactor: remove all @Suppression's 2022-06-05 08:03:19 +02:00
Lucaskyy
1c5a04caf9 refactor: format code 2022-06-05 08:03:19 +02:00
Lucaskyy
3d6a1d38f3 fix: Suppress unused for addFiles 2022-06-05 08:03:19 +02:00
Lucaskyy
715a2ad025 feat: Add warnings for Fuzzy resolver 2022-06-05 08:03:18 +02:00
Lucaskyy
9889ec9d03 docs: fix wrong wording 2022-06-05 08:03:18 +02:00
Lucaskyy
01bfbd656e feat: add extensions for cloning methods 2022-06-05 08:03:17 +02:00
Lucaskyy
6c9797583d test: fix outdated test 2022-06-05 08:03:17 +02:00
Lucaskyy
3cf07f5ce2 refactor: replace asInstructions with toInstruction to follow proper naming scheme 2022-06-05 08:03:17 +02:00
Lucaskyy
0bfb92a0cb revert: AccessFlag extensions not working with IDE 2022-06-05 08:03:16 +02:00
Lucaskyy
042638a399 refactor: replace Array with Iterable 2022-06-05 08:03:16 +02:00
oSumAtrIX
4178a1eedc fix: replaceWith not replacing classes with used class proxies
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:15 +02:00
oSumAtrIX
338bd9f739 fix: null check causing an exception
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:15 +02:00
oSumAtrIX
c55c62a57e add: throw on getting result of MethodSignature if null
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:15 +02:00
oSumAtrIX
1f08da8b2a refact: include each signature in its corresponding patch
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:14 +02:00
Lucaskyy
b2dab3fabf refactor: rename method to resolverMethod 2022-06-05 08:03:14 +02:00
Lucaskyy
0f30eac32c fix: remove leftover debug code 2022-06-05 08:03:14 +02:00
Lucaskyy
642e9031eb feat: Add patch metadata
Fixes ReVancedTeam/revanced-patches#1
2022-06-05 08:03:13 +02:00
Lucaskyy
7a56dca004 feat: add fuzzy resolver
fixed docs for MethodSignature & added tests for fuzzy resolver
2022-06-05 08:03:13 +02:00
Lucaskyy
18853f70a4 refactor: migrate signature schema changes to Patcher
also updated Extensions, for good measure.
2022-06-05 08:03:13 +02:00
oSumAtrIX
6b8b0573d4 feat: add missing test for fields
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:12 +02:00
oSumAtrIX
3889d72927 style: reformat code
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-06-05 08:03:12 +02:00
oSumAtrIX
3f97cc8e1f feat: remaining mutable EncodedValue classes 2022-06-05 08:03:11 +02:00
Lucaskyy
1db735b1e2 feat: allow classes to be overwritten in addFiles and resolve signatures when applyPatches is called 2022-06-05 08:03:11 +02:00
Lucaskyy
996c4acb20 fix: always return PatchResultSuccess on patch success 2022-06-05 08:03:11 +02:00
Lucaskyy
5b28523eea add: optional callback for CLI 2022-06-05 08:03:10 +02:00
Lucaskyy
72f3cad3f9 refactor: Change all references from Array to Iterable
BREAKING CHANGE: arrayOf has to be changed to listOf.
2022-06-05 08:03:10 +02:00
oSumAtrIX
9659a61c5c fix: adding existing classes to the patchers cache 2022-06-05 08:03:10 +02:00
Lucaskyy
b892729332 chore: update kotlin, don't shade deps, publish to maven local, make deps api instead of implementation 2022-06-05 08:03:09 +02:00
Lucaskyy
6e4db110c8 fix: Classes not being written properly because of array shifting
We now use a MutableList to replace it at the proper index, and use a ListBackedSet, so we don't copy List's to Set's for no reason.
This was a very bad issue. The array was shifted every time we removed the original class, the fact we even got a "working" dex file surprises me. Thankfully, this issue is now solved, and we lived happily after.
2022-06-05 08:03:09 +02:00
Lucaskyy
e810197e2a revert: previous commits check for dupes in dexFile, not cache
This reverts commit aed4fd9a3c.
This reverts commit 622138736d.
2022-06-05 08:03:08 +02:00
Lucaskyy
e65ebd27c2 perf: use Set instead of List since there are no dupes 2022-06-05 08:03:08 +02:00
Lucaskyy
5bd416b409 perf: use String List and compare instead of any lambda 2022-06-05 08:03:08 +02:00
Lucaskyy
a6c6b4979a refactor: bump multidexlib2 to 2.5.2.r2
BREAKING CHANGE: Method signature of Patcher#save() was changed to comply with the changes of multidexlib2.
2022-06-05 08:03:07 +02:00
Lucaskyy
db10ab03be ci: Fix Unauthorized error 2022-06-05 08:03:07 +02:00
Lucaskyy
94dbb573cf refactor: bump multidexlib2, dexlib2 and smali 2022-06-05 08:03:07 +02:00
oSumAtrIX
08253ee010 add: addFiles method to merge additional dex containers 2022-06-05 08:03:06 +02:00
oSumAtrIX
3144ec872a fix: throwing in case the opcode patterns do not match 2022-06-05 08:03:06 +02:00
Lucaskyy
48c4ea2f6d fix: returning failure on success
oh wow, that's an oopsie
2022-06-05 08:03:06 +02:00
Lucaskyy
c63b20fa65 feat: add immutableMethod
added docs
2022-06-05 08:03:05 +02:00
Lucaskyy
f806cb38c5 fix: applyPatches not returning successful patches 2022-06-05 08:03:05 +02:00
Lucaskyy
6c3e2d79ea chore: format code 2022-06-05 08:03:05 +02:00
oSumAtrIX
cca12aa34a fix: compareSignatureToMethod not matching correctly in case opcodes are null 2022-06-05 08:03:04 +02:00
Lucaskyy
c267b12a7d refactor: make method a property 2022-06-05 08:03:04 +02:00
Lucaskyy
eef448cc39 refactor: cleanup SignatureResolver.kt 2022-06-05 08:03:04 +02:00
Lucaskyy
45303f66ec test: fix test with previous changes 2022-06-05 08:03:03 +02:00
Lucaskyy
783fbf43f2 refactor: rename resolveAndGetMethod to method 2022-06-05 08:03:03 +02:00
Lucaskyy
59189058ac refactor: cleanup Patcher.kt 2022-06-05 08:03:03 +02:00
Lucaskyy
dfac8f03a3 fix: use Array instead of Iterable for methodParameters 2022-06-05 08:03:02 +02:00
Lucaskyy
b44bf4c267 chore: move replace extension method to Extensions.kt 2022-06-05 08:03:02 +02:00
Lucaskyy
066ad274ed docs: fixup 2022-06-05 08:03:02 +02:00
Lucaskyy
a8653fe6a0 chore: publish jar with dependencies 2022-06-05 08:03:01 +02:00
oSumAtrIX
139a23b750 feat: Improve SignatureResolver 2022-06-05 08:03:01 +02:00
oSumAtrIX
0d8d19e708 feat: Finish first patcher test 2022-06-05 08:03:00 +02:00
oSumAtrIX
a1e909b163 fix: Search method map for existing class proxy 2022-06-05 08:03:00 +02:00
oSumAtrIX
e4157332d3 add: MutableMethodImplementation.addInstructions extension 2022-06-05 08:03:00 +02:00
oSumAtrIX
923efc4caf add: TODO for mutable encoded value clones 2022-06-05 08:02:59 +02:00
oSumAtrIX
bea0cbc550 refactor: lazy initialize implementation field for mutable methods 2022-06-05 08:02:59 +02:00
oSumAtrIX
1ee2e4ba56 fix: match to correct signature method parameters 2022-06-05 08:02:59 +02:00
oSumAtrIX
fac44a50c3 fix: Patcher not writing resolved methods 2022-06-05 08:02:58 +02:00
oSumAtrIX
544bcf76bd feat: Add first tests 2022-06-05 08:02:58 +02:00
oSumAtrIX
a16c8cabf2 refactor: Improve SignatureResolver 2022-06-05 08:02:58 +02:00
oSumAtrIX
2777117da2 refactor: Use String instead of CharSequence for method parameter signature 2022-06-05 08:02:57 +02:00
oSumAtrIX
66a9b76845 fix: return mutable set of classes 2022-06-05 08:02:57 +02:00
oSumAtrIX
f068fc87ff fix: write all classes 2022-06-05 08:02:57 +02:00
oSumAtrIX
7cc8a7dec3 fix: fix classes having multiple instances of fields 2022-06-05 08:02:56 +02:00
oSumAtrIX
398239dc10 fix: fix classes having multiple method instances 2022-06-05 08:02:56 +02:00
Lucaskyy
d18a3b6a28 perf: lazy-ify all mutable clones 2022-06-05 08:02:56 +02:00
Lucaskyy
bfe4e3e298 feat: add inline smali compiler 2022-06-05 08:02:55 +02:00
Lucaskyy
a1b6b06bd3 test: use findClass with className & cleanup 2022-06-05 08:02:55 +02:00
Lucaskyy
4087f49863 feat: add findClass method with className 2022-06-05 08:02:54 +02:00
Lucaskyy
00c85b5d75 feat: add or extension for AccessFlags 2022-06-05 08:02:54 +02:00
Lucaskyy
cb78c5a86f style: reformat code 2022-06-05 08:02:54 +02:00
Lucaskyy
9991f39c9a perf: optimize indexOf call away 2022-06-05 08:02:53 +02:00
oSumAtrIX
650bf71124 docs: Document important parts of the code 2022-06-05 08:02:53 +02:00
oSumAtrIX
1dd3394ea3 refactor: Replacing original classes with mutated ones 2022-06-05 08:02:53 +02:00
oSumAtrIX
e6c2501539 fix: Fixed writer & signature resolver, improved tests & speed, minor refactoring 2022-06-05 08:02:52 +02:00
oSumAtrIX
4b26305bd5 feat: Minor refactor and return proxy, if class has been proxied already 2022-06-05 08:02:52 +02:00
oSumAtrIX
ce21bd60f3 fix: Move proxy package out of cache package 2022-06-05 08:02:51 +02:00
oSumAtrIX
3651981161 feat: migrate to dexlib
BREAKING CHANGE: Removed usage of ASM library
2022-06-05 08:02:51 +02:00
semantic-release-bot
6299b9e951 chore(release): 1.0.0-dev.8 [skip ci]
# [1.0.0-dev.8](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.7...v1.0.0-dev.8) (2022-03-24)

### Performance Improvements

* check type instead of class ([47eb493](47eb493f54))
2022-06-05 08:02:51 +02:00
semantic-release-bot
24b544708f chore(release): 1.0.0-dev.7 [skip ci]
# [1.0.0-dev.7](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.6...v1.0.0-dev.7) (2022-03-24)

### Bug Fixes

* **MethodResolver:** fix cd57a8c9a0 ([1af31b2](1af31b2aa3))
2022-06-05 08:02:50 +02:00
Lucaskyy
c7ef2644d8 perf: check type instead of class
this is way better, thank you oSumAtrIX!
2022-06-05 08:02:50 +02:00
Lucaskyy
fa6e454ae9 test: fix assert message 2022-06-05 08:02:50 +02:00
Lucaskyy
cbd8df2df0 fix(MethodResolver): fix cd57a8c9a0 2022-06-05 08:02:49 +02:00
semantic-release-bot
f3d8b917de chore(release): 1.0.0-dev.6 [skip ci]
# [1.0.0-dev.6](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.5...v1.0.0-dev.6) (2022-03-24)

### Bug Fixes

* **MethodResolver:** strip labels nodes so opcode patterns match ([cd57a8c](cd57a8c9a0))
2022-06-05 08:02:49 +02:00
Lucaskyy
82c530650f fix(MethodResolver): strip labels nodes so opcode patterns match
this commit is also a fix for 8d1bb5f3d9 because it corrupted the stack by completely removing the nodes
2022-06-05 08:02:49 +02:00
semantic-release-bot
81d0cf20f3 chore(release): 1.0.0-dev.5 [skip ci]
# [1.0.0-dev.5](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.4...v1.0.0-dev.5) (2022-03-24)

### Bug Fixes

* **MethodResolver:** strip labels and line numbers so opcode patterns match ([8d1bb5f](8d1bb5f3d9))
2022-06-05 08:02:48 +02:00
Lucaskyy
36d4f71325 refactor: log as trace instead of debug
so there's less spam in console
2022-06-05 08:02:48 +02:00
Lucaskyy
699c730a7c fix(MethodResolver): strip labels and line numbers so opcode patterns match 2022-06-05 08:02:48 +02:00
Lucaskyy
b197956e39 refactor: only compute maxs and use existing stack frames 2022-06-05 08:02:47 +02:00
semantic-release-bot
be992a3e6f chore(release): 1.0.0-dev.4 [skip ci]
# [1.0.0-dev.4](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.3...v1.0.0-dev.4) (2022-03-23)

### Bug Fixes

* give ClassWriter a ClassReader for symtable ([e8f6973](e8f6973938))
2022-06-05 08:02:47 +02:00
semantic-release-bot
e0437397df chore(release): 1.0.0-dev.3 [skip ci]
# [1.0.0-dev.3](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.2...v1.0.0-dev.3) (2022-03-23)

### Features

* add SafeClassWriter ([ca6b94d](ca6b94d943))
2022-06-05 08:02:47 +02:00
Lucaskyy
41749ba829 fix: give ClassWriter a ClassReader for symtable
removed SafeClassWriter as it was unused
2022-06-05 08:02:46 +02:00
semantic-release-bot
8161ce4fa6 chore(release): 1.0.0-dev.2 [skip ci]
# [1.0.0-dev.2](https://github.com/ReVancedTeam/revanced-patcher/compare/v1.0.0-dev.1...v1.0.0-dev.2) (2022-03-23)

### Bug Fixes

* set marklimit to Integer.MAX_VALUE ([ab6453c](ab6453ca8a))
2022-06-05 08:02:46 +02:00
Lucaskyy
6626014ef3 feat: add SafeClassWriter
the standard ClassWriter implementation uses the ClassLoader to find a common superclass. this won't work for us since we are not loading the JAR into the classpath. using this SafeClassWriter should fix that issue.
2022-06-05 08:02:46 +02:00
Lucaskyy
e6e468fbb5 fix: set marklimit to Integer.MAX_VALUE 2022-06-05 08:02:45 +02:00
semantic-release-bot
2fabbdf71b chore(release): 1.0.0-dev.1 [skip ci]
# 1.0.0-dev.1 (2022-03-23)

### Bug Fixes

* avoid ignoring test resources (fixes [#1](https://github.com/ReVancedTeam/revanced-patcher/issues/1)) ([d5a3c76](d5a3c76389))
* current must be calculated after increment ([5f12bab](5f12bab5df))
* **gradle:** publish source and javadocs ([87bbde5](87bbde5e06))
* **Io:** fix finding classes by name ([460d62a](460d62a24c))
* **Io:** JAR loading and saving ([#8](https://github.com/ReVancedTeam/revanced-patcher/issues/8)) ([4d98cbc](4d98cbc9e8))
* nullable signature members ([#10](https://github.com/ReVancedTeam/revanced-patcher/issues/10)) ([8db8893](8db8893ab1))
* Patch should have access to the Cache ([6c0f082](6c0f0823c9))
* remove broken code ([0e72a6e](0e72a6e85f))
* set index for insertAt to 0 by default ([1769132](1769132a9e))
* workflow on dev branch ([7e67daf](7e67daf878))

### Code Refactoring

* convert Patch to abstract class ([23e897a](23e897a7a9))
* Optimize Signature class ([#11](https://github.com/ReVancedTeam/revanced-patcher/issues/11)) ([49beec9](49beec9fc6))
* Rename `net.revanced` to `app.revanced` ([3ab42a9](3ab42a932c))

### Features

* Add `findParentMethod` utility method ([#4](https://github.com/ReVancedTeam/revanced-patcher/issues/4)) ([00c6ab7](00c6ab7faf))

### BREAKING CHANGES

* Array<Int> was changed to IntArray. This breaks existing patches.
* Package name was changed from "net.revanced" to "app.revanced"
* Method signature of execute() was changed to include the cache, this will break existing implementations of the Patch class.
* Patch class is now an abstract class. You must implement it. You can use anonymous implements, like done in the tests.
2022-06-05 08:02:45 +02:00
Lucaskyy
7faa001406 refactor: Optimize Signature class (#11)
BREAKING CHANGE: Array<Int> was changed to IntArray. This breaks existing patches.
2022-06-05 08:02:44 +02:00
Lucaskyy
70872307e3 refactor: Rename net.revanced to app.revanced
BREAKING CHANGE: Package name was changed from "net.revanced" to "app.revanced"
2022-06-05 08:02:44 +02:00
oSumAtrIX
310a7c446b fix(Io): JAR loading and saving (#8)
* refactor: Complete rewrite of `Io`

* style: format code

* style: rewrite todos

* fix: use lateinit instead of nonnull assert for zipEntry

* fix: use lateinit instead of nonnull assert for jarEntry & reuse zipEntry

* docs: add docs to `Patcher`

* test: match output of patcher

* chore: add todo to `Io` for removing non-class files

Co-authored-by: Sculas <contact@sculas.xyz>
2022-06-05 08:02:43 +02:00
Lucaskyy
c236ebe078 fix(gradle): publish source and javadocs 2022-06-05 08:02:43 +02:00
oSumAtrIX
674461f08d fix: nullable signature members (#10)
This commit will allow "partial" signatures, basically we will be allowed to exclude members to match for the signature
2022-06-05 08:02:43 +02:00
oSumAtrIX
bbb2c547aa feat: Add findParentMethod utility method (#4)
* feat: Add `findParentMethod` utitly method

* refactor: add `resolveMethod` to `MethodResolver`

added some assertions and some tests

Co-authored-by: Lucaskyy <contact@sculas.xyz>
2022-06-05 08:02:42 +02:00
Bleuzen
b957501e70 fix(Io): fix finding classes by name 2022-06-05 08:02:42 +02:00
Lucaskyy
b6ca31a970 chore: push IntelliJ project files 2022-06-05 08:02:42 +02:00
Lucaskyy
cbcf93f7d6 refactor: target java 8 instead of java 17 2022-06-05 08:02:41 +02:00
Lucaskyy
d5b4c99c00 fix: set index for insertAt to 0 by default 2022-06-05 08:02:41 +02:00
Lucaskyy
4dd820ffdf fix: Patch should have access to the Cache
BREAKING CHANGE: Method signature of execute() was changed to include the cache, this will break existing implementations of the Patch class.
2022-06-05 08:02:41 +02:00
Lucaskyy
cb9b1b9416 refactor: convert Patch to abstract class
BREAKING CHANGE: Patch class is now an abstract class. You must implement it. You can use anonymous implements, like done in the tests.
2022-06-05 08:02:40 +02:00
Lucaskyy
428f7f4dec fix: workflow on dev branch 2022-06-05 08:02:40 +02:00
Lucaskyy
77536cce8f style: remove tab 2022-06-05 08:02:39 +02:00
she11sh0cked
7b6a61b674 ci: add gradle-semantic-release-plugin and remove the github release assets 2022-06-05 08:02:39 +02:00
she11sh0cked
7f5f3b217d ci: add semantic-release 2022-06-05 08:02:39 +02:00
113 changed files with 12968 additions and 887 deletions

9
.gitattributes vendored Normal file
View File

@@ -0,0 +1,9 @@
#
# 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

72
.github/ISSUE_TEMPLATE/bug-issue.yml vendored Normal file
View File

@@ -0,0 +1,72 @@
name: 🐞 Bug report
description: Report a very clearly broken issue.
title: 'bug: <title>'
labels: [bug]
body:
- type: markdown
attributes:
value: |
# ReVanced bug report
Important to note that your issue may have already been reported before. Please check for existing issues [here](https://github.com/revanced/revanced-patcher/labels/bug).
- type: dropdown
attributes:
label: Type
options:
- Crash
- Cosmetic
- Other
validations:
required: true
- type: textarea
attributes:
label: Bug description
description: How did you find the bug? Any additional details that might help?
validations:
required: true
- type: textarea
attributes:
label: Steps to reproduce
description: Add the steps to reproduce this bug including your environment.
placeholder: Step 1. Download some files. Step 2. ...
validations:
required: true
- type: textarea
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell
validations:
required: true
- type: textarea
attributes:
label: Screenshots or videos
description: Add screenshots or videos that show the bug here.
placeholder: Drag and drop the screenshots/videos into this box.
validations:
required: false
- type: textarea
attributes:
label: Solution
description: If applicable, add a possible solution.
validations:
required: false
- type: textarea
attributes:
label: Additional context
description: Add additional context here.
validations:
required: false
- type: checkboxes
id: acknowledgements
attributes:
label: Acknowledgements
description: Your issue will be closed if you haven't done these steps.
options:
- label: I have searched the existing issues and this is a new and no duplicate or related to another open issue.
required: true
- label: I have written a short but informative title.
required: true
- label: I filled out all of the requested information in this issue properly.
required: true

8
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,8 @@
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!

View File

@@ -0,0 +1,58 @@
name: ⭐ Feature request
description: Create a detailed feature request.
title: 'feat: <title>'
labels: [feature-request]
body:
- type: markdown
attributes:
value: |
# ReVanced feature request
Do not submit requests for patches here. Please submit them [here](https://github.com/orgs/revanced/discussions/categories/patches) instead.
Important to note that your feature request may have already been made before. Please check for existing feature requests [here](https://github.com/revanced/revanced-patcher/labels/feature-request).
- type: dropdown
attributes:
label: Type
options:
- Functionality
- Cosmetic
- Other
validations:
required: true
- type: textarea
attributes:
label: Issue
description: What is the current problem. Why does it require a feature request?
validations:
required: true
- type: textarea
attributes:
label: Feature
description: Describe your feature in detail. How does it solve the issue?
validations:
required: true
- type: textarea
attributes:
label: Motivation
description: Why should your feature should be considered?
validations:
required: true
- type: textarea
attributes:
label: Additional context
description: Add additional context here.
validations:
required: false
- type: checkboxes
id: acknowledgements
attributes:
label: Acknowledgements
description: Your issue will be closed if you haven't done these steps.
options:
- label: I have searched the existing issues and this is a new and no duplicate or related to another open issue.
required: true
- label: I have written a short but informative title.
required: true
- label: I filled out all of the requested information in this issue properly.
required: true

2
.github/config.yml vendored Normal file
View File

@@ -0,0 +1,2 @@
firstPRMergeComment: >
Thank you for contributing to ReVanced. Join us on [Discord](https://revanced.app/discord) if you want to receive a contributor role.

25
.github/workflows/pull_request.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
name: 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@v3
- 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

View File

@@ -1,5 +1,7 @@
name: Release
on:
workflow_dispatch:
push:
branches:
- main
@@ -8,32 +10,36 @@ on:
branches:
- main
- dev
jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
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: Setup JDK
uses: actions/setup-java@v2
- name: Cache
uses: actions/cache@v3
with:
java-version: '8'
distribution: 'adopt'
cache: gradle
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: "lts/*"
- name: Make gradlew executable
run: chmod +x gradlew
path: |
${{ runner.home }}/.gradle/caches
${{ runner.home }}/.gradle/wrapper
.gradle
build
node_modules
key: ${{ runner.os }}-gradle-npm-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', 'package-lock.json') }}
- 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.GITHUB_TOKEN }}
run: npx semantic-release
run: ./gradlew clean --no-daemon
- name: Setup semantic-release
run: npm install
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
run: npm exec semantic-release

7
.gitignore vendored
View File

@@ -74,6 +74,7 @@ cmake-build-*/
# IntelliJ
out/
.idea/
# mpeltonen/sbt-idea plugin
.idea_modules/
@@ -115,3 +116,9 @@ 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
View File

@@ -1,8 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@@ -1,10 +0,0 @@
<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>

View File

@@ -1,5 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

7
.idea/discord.xml generated
View File

@@ -1,7 +0,0 @@
<?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>

View File

@@ -1,15 +0,0 @@
<?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
View File

@@ -1,10 +0,0 @@
<?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
View File

@@ -1,12 +0,0 @@
<?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>

View File

@@ -7,7 +7,13 @@
}
],
"plugins": [
"@semantic-release/commit-analyzer",
[
"@semantic-release/commit-analyzer", {
"releaseRules": [
{ "type": "build", "scope": "Needs bump", "release": "patch" }
]
}
],
"@semantic-release/release-notes-generator",
"@semantic-release/changelog",
"gradle-semantic-release-plugin",
@@ -20,6 +26,18 @@
]
}
],
"@semantic-release/github"
[
"@saithodev/semantic-release-backmerge",
{
backmergeBranches: [{"from": "main", "to": "dev"}],
clearWorkspace: true
}
],
[
"@semantic-release/github",
{
successComment: false
}
]
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -1 +1,3 @@
# Patcher
# 💉 ReVanced Patcher
ReVanced Patcher used to patch Android applications.

View File

@@ -1,43 +1,48 @@
plugins {
kotlin("jvm") version "1.6.10"
java
kotlin("jvm") version "1.8.20"
`maven-publish`
}
group = "app.revanced"
repositories {
mavenCentral()
}
dependencies {
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"))
implementation(libs.kotlinx.coroutines.core)
implementation(libs.xpp3)
implementation(libs.smali)
implementation(libs.multidexlib2)
implementation(libs.apktool.lib)
implementation(libs.kotlin.reflect)
compileOnly(libs.android)
testImplementation(libs.kotlin.test)
}
tasks.test {
useJUnitPlatform()
testLogging {
events("PASSED", "SKIPPED", "FAILED")
tasks {
test {
useJUnitPlatform()
testLogging {
events("PASSED", "SKIPPED", "FAILED")
}
}
processResources {
expand("projectVersion" to project.version)
}
}
kotlin { jvmToolchain(11) }
java {
withSourcesJar()
withJavadocJar()
}
publishing {
repositories {
mavenLocal()
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/ReVancedTeam/revanced-patcher")
url = uri("https://maven.pkg.github.com/revanced/revanced-patcher")
credentials {
username = System.getenv("GITHUB_ACTOR")
password = System.getenv("GITHUB_TOKEN")
@@ -45,7 +50,7 @@ publishing {
}
}
publications {
register<MavenPublication>("gpr") {
create<MavenPublication>("gpr") {
from(components["java"])
}
}

View File

@@ -1,2 +1,4 @@
org.gradle.parallel = true
org.gradle.caching = true
kotlin.code.style = official
version = 1.0.0-dev.2
version = 14.2.0-dev.2

21
gradle/libs.versions.toml Normal file
View File

@@ -0,0 +1,21 @@
[versions]
android = "4.1.1.4"
kotlin-reflect = "1.9.0"
apktool-lib = "2.8.2-5"
kotlin-test = "1.8.20-RC"
kotlinx-coroutines-core = "1.7.1"
multidexlib2 = "3.0.3.r2"
shadow = "8.1.1"
smali = "3.0.3"
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-reflect" }
apktool-lib = { module = "app.revanced:apktool-lib", version.ref = "apktool-lib" }
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin-test" }
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" }

Binary file not shown.

View File

@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

293
gradlew vendored Normal file → Executable file
View File

@@ -1,7 +1,7 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,67 +17,98 @@
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# 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/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
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
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
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
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"'
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# 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
@@ -87,9 +118,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
@@ -98,88 +129,120 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
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.
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.
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" = "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
# 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" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# 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" ;;
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
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# 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.
# 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"
# 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" )
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
done
fi
# 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' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

15
gradlew.bat vendored
View File

@@ -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,7 +25,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 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!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
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%
:mainEnd
if "%OS%"=="Windows_NT" endlocal

6580
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

9
package.json Normal file
View File

@@ -0,0 +1,9 @@
{
"devDependencies": {
"@saithodev/semantic-release-backmerge": "^3.1.0",
"@semantic-release/changelog": "^6.0.2",
"@semantic-release/git": "^10.0.1",
"gradle-semantic-release-plugin": "^1.7.6",
"semantic-release": "^20.1.0"
}
}

View File

@@ -1 +1,22 @@
val githubUsername: String = providers.gradleProperty("gpr.user").orNull ?: System.getenv("GITHUB_ACTOR")
val githubPassword: String = providers.gradleProperty("gpr.key").orNull ?: System.getenv("GITHUB_TOKEN")
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
mavenCentral()
google()
mavenLocal()
listOf("multidexlib2", "apktool").forEach { repo ->
maven {
url = uri("https://maven.pkg.github.com/revanced/$repo")
credentials {
username = githubUsername
password = githubPassword
}
}
}
}
}
rootProject.name = "revanced-patcher"

View File

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

View File

@@ -0,0 +1,14 @@
package app.revanced.patcher
import brut.androlib.apk.ApkInfo
/**
* Metadata about a package.
*/
class PackageMetadata internal constructor(internal val apkInfo: ApkInfo) {
lateinit var packageName: String
internal set
lateinit var packageVersion: String
internal set
}

View File

@@ -0,0 +1,74 @@
@file:Suppress("unused")
package app.revanced.patcher
import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively
import app.revanced.patcher.extensions.PatchExtensions.patchName
import app.revanced.patcher.patch.Patch
import app.revanced.patcher.patch.PatchClass
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
/**
* A patch bundle.
*
* @param fromClasses The classes to get [Patch]es from.
*/
sealed class PatchBundleLoader private constructor(
fromClasses: Iterable<Class<*>>
) : MutableList<PatchClass> by mutableListOf() {
init {
fromClasses.filter {
if (it.isAnnotation) return@filter false
it.findAnnotationRecursively(app.revanced.patcher.patch.annotations.Patch::class) != null
}.map {
@Suppress("UNCHECKED_CAST")
it as PatchClass
}.sortedBy {
it.patchName
}.let { addAll(it) }
}
/**
* A [PatchBundleLoader] for JAR files.
*
* @param patchBundles The path to patch bundles of JAR format.
*/
class Jar(vararg patchBundles: File) :
PatchBundleLoader(with(URLClassLoader(patchBundles.map { it.toURI().toURL() }.toTypedArray())) {
patchBundles.flatMap { patchBundle ->
// Get the names of all classes in the DEX file.
JarFile(patchBundle).entries().asSequence()
.filter { it.name.endsWith(".class") }
.map { it.name.replace('/', '.').replace(".class", "") }
.map { loadClass(it) }
}
})
/**
* A [PatchBundleLoader] for [Dex] files.
*
* @param patchBundles The path to patch bundles of DEX format.
*/
class Dex(vararg patchBundles: File) : PatchBundleLoader(with(
DexClassLoader(
patchBundles.joinToString(File.pathSeparator) { it.absolutePath },
null,
null,
PatchBundleLoader::class.java.classLoader
)
) {
patchBundles
.flatMap {
MultiDexIO.readDexFile(true, it, BasicDexFileNamer(), null, null).classes
}
.map { classDef -> classDef.type.substring(1, classDef.length - 1) }
.map { loadClass(it) }
})
}

View File

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

View File

@@ -1,70 +1,236 @@
package app.revanced.patcher
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
import app.revanced.patcher.data.Context
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively
import app.revanced.patcher.extensions.PatchExtensions.dependencies
import app.revanced.patcher.extensions.PatchExtensions.patchName
import app.revanced.patcher.extensions.PatchExtensions.requiresIntegrations
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patcher.fingerprint.method.impl.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.Level
import java.util.logging.LogManager
import java.util.logging.Logger
/**
* The Patcher class.
* ***It is of utmost importance that the input and output streams are NEVER closed.***
* ReVanced 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
* @param options The options for the patcher.
*/
class Patcher(
private val input: InputStream,
private val output: OutputStream,
signatures: Array<Signature>,
) {
var cache: Cache
private val options: PatcherOptions
) : PatchExecutorFunction, PatchesConsumer, IntegrationsConsumer, Supplier<PatcherResult>, Closeable {
private val logger = Logger.getLogger(Patcher::class.java.name)
private var io: Io
private val patches = mutableListOf<Patch>()
/**
* The context of ReVanced [Patcher].
* This holds the current state of the patcher.
*/
val context = PatcherContext(options)
init {
val classes = mutableListOf<ClassNode>()
io = Io(input, output, classes)
io.readFromJar()
cache = Cache(classes, MethodResolver(classes, signatures).resolve())
LogManager.getLogManager().let { manager ->
// Disable root logger.
manager.getLogger("").level = Level.OFF
// Enable ReVanced logging only.
manager.loggerNames
.toList()
.filter { it.startsWith("app.revanced") }
.map { manager.getLogger(it) }
.forEach { it.level = Level.INFO }
}
context.resourceContext.decodeResources(ResourceContext.ResourceDecodingMode.MANIFEST_ONLY)
}
override fun acceptPatches(patches: List<PatchClass>) {
/**
* Returns true if at least one patches or its dependencies matches the given predicate.
*/
fun PatchClass.anyRecursively(predicate: (PatchClass) -> Boolean): Boolean =
predicate(this) || dependencies?.any { dependency ->
dependency.java.anyRecursively(predicate)
} ?: false
// Determine if resource patching is required.
for (patch in patches) {
if (patch.anyRecursively { ResourcePatch::class.java.isAssignableFrom(it) }) {
options.resourceDecodingMode = ResourceContext.ResourceDecodingMode.FULL
break
}
}
// Determine if merging integrations is required.
for (patch in patches) {
if (patch.anyRecursively { it.requiresIntegrations }) {
context.bytecodeContext.integrations.merge = true
break
}
}
context.patches.addAll(patches)
}
/**
* 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.
* Add integrations to the [Patcher].
*
* @throws IOException if one of the streams are closed
* @param integrations The integrations to add. Must be a DEX file or container of DEX files.
*/
fun save() {
io.saveAsJar()
override fun acceptIntegrations(integrations: List<File>) {
context.bytecodeContext.integrations.addAll(integrations)
}
fun addPatches(vararg patches: Patch) {
this.patches.addAll(patches)
}
/**
* 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 {
class ExecutedPatch(val patchInstance: Patch<Context<*>>, val patchResult: PatchResult)
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)
/**
* Execute a [Patch] and its dependencies recursively.
*
* @param patchClass 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(
patchClass: PatchClass,
executedPatches: LinkedHashMap<String, ExecutedPatch>
): PatchResult {
val patchName = patchClass.patchName
executedPatches[patchName]?.let { executedPatch ->
executedPatch.patchResult.exception ?: return executedPatch.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(patchName, PatchException("'$patchName' did not succeed previously"))
}
// Recursively execute all dependency patches.
patchClass.dependencies?.forEach { dependencyClass ->
val dependency = dependencyClass.java
val result = executePatch(dependency, executedPatches)
result.exception?.let {
return PatchResult(
patchName,
PatchException(
"'$patchName' depends on '${dependency.patchName}' that raised an exception: $it"
)
)
}
this[patch.patchName] = result
if (stopOnError && result.isFailure) break
}
// TODO: Implement this in a more polymorphic way.
val patchInstance = patchClass.getDeclaredConstructor().newInstance()
val patchContext = if (patchInstance is BytecodePatch) {
patchInstance.fingerprints?.resolveUsingLookupMap(context.bytecodeContext)
context.bytecodeContext
} else {
context.resourceContext
}
return try {
patchInstance.execute(patchContext)
PatchResult(patchName)
} catch (exception: PatchException) {
PatchResult(patchName, exception)
} catch (exception: Exception) {
PatchResult(patchName, PatchException(exception))
}.also { executedPatches[patchName] = ExecutedPatch(patchInstance, it) }
}
if (context.bytecodeContext.integrations.merge) context.bytecodeContext.integrations.flush()
MethodFingerprint.initializeFingerprintResolutionLookupMaps(context.bytecodeContext)
// Prevent from decoding the app manifest twice if it is not needed.
if (options.resourceDecodingMode == ResourceContext.ResourceDecodingMode.FULL)
context.resourceContext.decodeResources(ResourceContext.ResourceDecodingMode.FULL)
logger.info("Executing patches")
val executedPatches = LinkedHashMap<String, ExecutedPatch>() // Key is name.
context.patches.forEach { patch ->
val result = executePatch(patch, executedPatches)
// If the patch failed, or if the patch is not closeable, emit the result.
// Results of patches that are closeable will be emitted later.
result.exception?.let {
emit(result)
if (returnOnError) return@flow
} ?: run {
if (executedPatches[result.patchName]!!.patchInstance is Closeable) return@run
emit(result)
}
}
executedPatches.values
.filter { it.patchResult.exception == null }
.filter { it.patchInstance is Closeable }.asReversed().forEach { executedPatch ->
val patchName = executedPatch.patchResult.patchName
val result = try {
(executedPatch.patchInstance as Closeable).close()
executedPatch.patchResult
} catch (exception: PatchException) {
PatchResult(patchName, exception)
} catch (exception: Exception) {
PatchResult(patchName, PatchException(exception))
}
result.exception?.let {
emit(
PatchResult(
patchName,
PatchException("'$patchName' raised an exception while being closed: $it")
)
)
if (returnOnError) return@flow
} ?: run {
executedPatch
.patchInstance::class
.java
.findAnnotationRecursively(app.revanced.patcher.patch.annotations.Patch::class)
?: return@run
emit(result)
}
}
}
}
override fun close() {
MethodFingerprint.clearFingerprintResolutionLookupMaps()
}
/**
* Compile and save the patched APK file.
*
* @return The [PatcherResult] containing the patched input files.
*/
override fun get() = PatcherResult(
context.bytecodeContext.get(),
context.resourceContext.get(),
context.packageMetadata.apkInfo.doNotCompress?.toList()
)
}

View File

@@ -0,0 +1,37 @@
package app.revanced.patcher
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.Patch
import app.revanced.patcher.patch.PatchClass
import brut.androlib.apk.ApkInfo
import brut.directory.ExtFile
/**
* A context for ReVanced [Patcher].
*
* @param options The [PatcherOptions] used to create this context.
*/
class PatcherContext internal constructor(options: PatcherOptions) {
/**
* [PackageMetadata] of the supplied [PatcherOptions.inputFile].
*/
val packageMetadata = PackageMetadata(ApkInfo(ExtFile(options.inputFile)))
/**
* The list of [Patch]es to execute.
*/
internal val patches = mutableListOf<PatchClass>()
/**
* The [ResourceContext] of this [PatcherContext].
* This holds the current state of the resources.
*/
internal val resourceContext = ResourceContext(this, options)
/**
* The [BytecodeContext] of this [PatcherContext].
* This holds the current state of the bytecode.
*/
internal val bytecodeContext = BytecodeContext(options)
}

View File

@@ -0,0 +1,73 @@
package app.revanced.patcher
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.logging.impl.NopLogger
import brut.androlib.Config
import java.io.File
import java.util.logging.Logger
/**
* Options for ReVanced [Patcher].
* @param inputFile The input file to patch.
* @param resourceCachePath The path to the directory to use for caching resources.
* @param aaptBinaryPath The path to a custom aapt binary.
* @param frameworkFileDirectory The path to the directory to cache the framework file in.
* @param unusedLogger The logger to use for logging.
*/
data class PatcherOptions
@Deprecated("Use the constructor without the logger parameter instead")
constructor(
internal val inputFile: File,
internal val resourceCachePath: File = File("revanced-resource-cache"),
internal val aaptBinaryPath: String? = null,
internal val frameworkFileDirectory: String? = null,
internal val unusedLogger: app.revanced.patcher.logging.Logger = NopLogger
) {
private val logger = Logger.getLogger(PatcherOptions::class.java.name)
/**
* The mode to use for resource decoding.
* @see ResourceContext.ResourceDecodingMode
*/
internal var resourceDecodingMode = ResourceContext.ResourceDecodingMode.MANIFEST_ONLY
/**
* The configuration to use for resource decoding and compiling.
*/
internal val resourceConfig = Config.getDefaultConfig().apply {
useAapt2 = true
aaptPath = aaptBinaryPath ?: ""
frameworkDirectory = frameworkFileDirectory
}
/**
* Options for ReVanced [Patcher].
* @param inputFile The input file to patch.
* @param resourceCachePath The path to the directory to use for caching resources.
* @param aaptBinaryPath The path to a custom aapt binary.
* @param frameworkFileDirectory The path to the directory to cache the framework file in.
*/
constructor(
inputFile: File,
resourceCachePath: File = File("revanced-resource-cache"),
aaptBinaryPath: String? = null,
frameworkFileDirectory: String? = null,
) : this(
inputFile,
resourceCachePath,
aaptBinaryPath,
frameworkFileDirectory,
NopLogger
)
fun recreateResourceCacheDirectory() = resourceCachePath.also {
if (it.exists()) {
logger.info("Deleting existing resource cache directory")
if (!it.deleteRecursively())
logger.severe("Failed to delete existing resource cache directory")
}
it.mkdirs()
}
}

View File

@@ -0,0 +1,23 @@
package app.revanced.patcher
import java.io.File
import java.io.InputStream
/**
* The result of a patcher.
* @param dexFiles The patched dex files.
* @param resourceFile File containing resources that need to be extracted into the APK.
* @param doNotCompress List of relative paths of files to exclude from compressing.
*/
data class PatcherResult(
val dexFiles: List<PatchedDexFile>,
val resourceFile: File?,
val doNotCompress: List<String>? = null
) {
/**
* Wrapper for dex files.
* @param name The original name of the dex file.
* @param stream The dex file as [InputStream].
*/
class PatchedDexFile(val name: String, val stream: InputStream)
}

View File

@@ -0,0 +1,8 @@
package app.revanced.patcher
import app.revanced.patcher.patch.PatchClass
@FunctionalInterface
interface PatchesConsumer {
fun acceptPatches(patches: List<PatchClass>)
}

View File

@@ -0,0 +1,23 @@
package app.revanced.patcher.annotation
import app.revanced.patcher.patch.Patch
/**
* Annotation to constrain a [Patch] to compatible packages.
* @param compatiblePackages A list of packages a [Patch] is compatible with.
*/
@Target(AnnotationTarget.CLASS)
annotation class Compatibility(
val compatiblePackages: Array<Package>,
)
/**
* Annotation to represent packages a patch can be compatible with.
* @param name The package identifier name.
* @param versions The versions of the package the [Patch] is compatible with.
*/
@Target()
annotation class Package(
val name: String,
val versions: Array<String> = [],
)

View File

@@ -0,0 +1,21 @@
package app.revanced.patcher.annotation
import app.revanced.patcher.patch.Patch
/**
* Annotation to name a [Patch].
* @param name A suggestive name for the [Patch].
*/
@Target(AnnotationTarget.CLASS)
annotation class Name(
val name: String,
)
/**
* Annotation to describe a [Patch].
* @param description A description for the [Patch].
*/
@Target(AnnotationTarget.CLASS)
annotation class Description(
val description: String,
)

View File

@@ -1,16 +0,0 @@
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)

View File

@@ -1,22 +0,0 @@
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
)

View File

@@ -0,0 +1,157 @@
package app.revanced.patcher.data
import app.revanced.patcher.PatcherContext
import app.revanced.patcher.PatcherOptions
import app.revanced.patcher.PatcherResult
import app.revanced.patcher.patch.Patch
import app.revanced.patcher.patch.annotations.RequiresIntegrations
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 com.android.tools.smali.dexlib2.writer.io.MemoryDataStore
import lanchon.multidexlib2.BasicDexFileNamer
import lanchon.multidexlib2.DexIO
import lanchon.multidexlib2.MultiDexIO
import java.io.File
import java.io.Flushable
import java.util.logging.Logger
/**
* A context for bytecode.
* This holds the current state of the bytecode.
*
* @param options The [PatcherOptions] used to create this context.
*/
class BytecodeContext internal constructor(private val options: PatcherOptions) :
Context<List<PatcherResult.PatchedDexFile>> {
private val logger = Logger.getLogger(BytecodeContext::class.java.name)
/**
* [Opcodes] of the supplied [PatcherOptions.inputFile].
*/
internal lateinit var opcodes: Opcodes
/**
* The list of classes.
*/
val classes by lazy {
ProxyClassList(
MultiDexIO.readDexFile(
true, options.inputFile, 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)
/**
* The integrations of a [PatcherContext].
*/
internal inner class Integrations : MutableList<File> by mutableListOf(), Flushable {
/**
* Whether to merge integrations.
* True when any supplied [Patch] is annotated with [RequiresIntegrations].
*/
var merge = false
/**
* Merge integrations into the [BytecodeContext] and flush all [Integrations].
*/
override fun flush() {
if (!merge) return
logger.info("Merging integrations")
this@Integrations.forEach { integrations ->
MultiDexIO.readDexFile(
true,
integrations, BasicDexFileNamer(),
null,
null
).classes.forEach classDef@{ classDef ->
val existingClass = classes.find { it == classDef } ?: run {
logger.fine("Merging $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()
}
}
/**
* Compile bytecode from the [BytecodeContext].
*
* @return The compiled bytecode.
*/
override fun get(): List<PatcherResult.PatchedDexFile> {
logger.info("Compiling modified dex files")
return mutableMapOf<String, MemoryDataStore>().apply {
MultiDexIO.writeDexFile(
true, -1, // Defaults to amount of available cores.
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, null
)
}.map { PatcherResult.PatchedDexFile(it.key, it.value.readAt(0)) }
}
}

View File

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

View File

@@ -0,0 +1,160 @@
package app.revanced.patcher.data
import app.revanced.patcher.PatcherContext
import app.revanced.patcher.PatcherOptions
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 resources.
* This holds the current state of the resources.
*
* @param context The [PatcherContext] to create the context for.
*/
class ResourceContext internal constructor(
private val context: PatcherContext,
private val options: PatcherOptions
) : Context<File?>, Iterable<File> {
private val logger = Logger.getLogger(ResourceContext::class.java.name)
val xmlEditor = XmlFileHolder()
/**
* Decode resources for the patcher.
*
* @param mode The [ResourceDecodingMode] to use when decoding.
*/
internal fun decodeResources(mode: ResourceDecodingMode) = with(context.packageMetadata.apkInfo) {
// Needed to decode resources.
val resourcesDecoder = ResourcesDecoder(options.resourceConfig, this)
when (mode) {
ResourceDecodingMode.FULL -> {
val outDir = options.recreateResourceCacheDirectory()
logger.info("Decoding resources")
resourcesDecoder.decodeResources(outDir)
resourcesDecoder.decodeManifest(outDir)
// Needed to record uncompressed files.
val apkDecoder = ApkDecoder(options.resourceConfig, this)
apkDecoder.recordUncompressedFiles(resourcesDecoder.resFileMapping)
usesFramework = UsesFramework().apply {
ids = resourcesDecoder.resTable.listFramePackages().map { it.id }
}
}
ResourceDecodingMode.MANIFEST_ONLY -> {
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.
context.packageMetadata.let { metadata ->
metadata.packageName = resourcesDecoder.resTable.packageRenamed
versionInfo.let {
metadata.packageVersion = it.versionName ?: it.versionCode
}
}
}
}
}
operator fun get(path: String) = options.resourceCachePath.resolve(path)
override fun iterator() = options.resourceCachePath.walkTopDown().iterator()
/**
* Compile resources from the [ResourceContext].
*
* @return The compiled resources.
*/
override fun get(): File? {
var resourceFile: File? = null
if (options.resourceDecodingMode == ResourceDecodingMode.FULL) {
logger.info("Compiling modified resources")
val cacheDirectory = ExtFile(options.resourceCachePath)
val aaptFile = cacheDirectory.resolve("aapt_temp_file").also {
Files.deleteIfExists(it.toPath())
}.also { resourceFile = it }
try {
AaptInvoker(
options.resourceConfig, context.packageMetadata.apkInfo
).invokeAapt(aaptFile,
cacheDirectory.resolve("AndroidManifest.xml").also {
ResXmlPatcher.fixingPublicAttrsInProviderAttributes(it)
},
cacheDirectory.resolve("res"),
null,
null,
context.packageMetadata.apkInfo.usesFramework.let { usesFramework ->
usesFramework.ids.map { id ->
Framework(options.resourceConfig).getFrameworkApk(id, usesFramework.tag)
}.toTypedArray()
})
} finally {
cacheDirectory.close()
}
}
return resourceFile
}
/**
* The type of decoding the resources.
*/
internal enum class ResourceDecodingMode {
/**
* Decode all resources.
*/
FULL,
/**
* Decode the manifest file only.
*/
MANIFEST_ONLY,
}
inner class XmlFileHolder {
operator fun get(inputStream: InputStream) =
DomFileEditor(inputStream)
operator fun get(path: String): DomFileEditor {
return DomFileEditor(this@ResourceContext[path])
}
}
}

View File

@@ -0,0 +1,33 @@
package app.revanced.patcher.extensions
import kotlin.reflect.KClass
internal object AnnotationExtensions {
/**
* Recursively find a given annotation on a class.
*
* @param targetAnnotation The annotation to find.
* @return The annotation.
*/
fun <T : Annotation> Class<*>.findAnnotationRecursively(targetAnnotation: KClass<T>): T? {
fun <T : Annotation> Class<*>.findAnnotationRecursively(
targetAnnotation: Class<T>, traversed: MutableSet<Annotation>
): T? {
val found = this.annotations.firstOrNull { it.annotationClass.java.name == targetAnnotation.name }
@Suppress("UNCHECKED_CAST") if (found != null) return found as T
for (annotation in this.annotations) {
if (traversed.contains(annotation)) continue
traversed.add(annotation)
return (annotation.annotationClass.java.findAnnotationRecursively(targetAnnotation, traversed))
?: continue
}
return null
}
return this.findAnnotationRecursively(targetAnnotation.java, mutableSetOf())
}
}

View File

@@ -0,0 +1,33 @@
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 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 [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 an [Int] and an [AccessFlags].
*
* @param other The [AccessFlags] to perform the operation with.
*/
infix fun AccessFlags.or(other: Int) = value or other

View File

@@ -0,0 +1,330 @@
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
}

View File

@@ -0,0 +1,20 @@
package app.revanced.patcher.extensions
import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object MethodFingerprintExtensions {
/**
* The name of a [MethodFingerprint].
*/
val MethodFingerprint.name: String
get() = this.javaClass.simpleName
/**
* The [FuzzyPatternScanMethod] annotation of a [MethodFingerprint].
*/
val MethodFingerprint.fuzzyPatternScanMethod
get() = javaClass.findAnnotationRecursively(FuzzyPatternScanMethod::class)
}

View File

@@ -0,0 +1,64 @@
package app.revanced.patcher.extensions
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.extensions.AnnotationExtensions.findAnnotationRecursively
import app.revanced.patcher.patch.OptionsContainer
import app.revanced.patcher.patch.Patch
import app.revanced.patcher.patch.PatchClass
import app.revanced.patcher.patch.PatchOptions
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.RequiresIntegrations
import kotlin.reflect.KVisibility
import kotlin.reflect.full.companionObject
import kotlin.reflect.full.companionObjectInstance
object PatchExtensions {
/**
* The name of a [Patch].
*/
val PatchClass.patchName: String
get() = findAnnotationRecursively(Name::class)?.name ?: this.simpleName
/**
* Weather or not a [Patch] should be included.
*/
val PatchClass.include
get() = findAnnotationRecursively(app.revanced.patcher.patch.annotations.Patch::class)!!.include
/**
* The description of a [Patch].
*/
val PatchClass.description
get() = findAnnotationRecursively(Description::class)?.description
/**
* The dependencies of a [Patch].
*/
val PatchClass.dependencies
get() = findAnnotationRecursively(DependsOn::class)?.dependencies
/**
* The packages a [Patch] is compatible with.
*/
val PatchClass.compatiblePackages
get() = findAnnotationRecursively(Compatibility::class)?.compatiblePackages
/**
* Weather or not a [Patch] requires integrations.
*/
internal val PatchClass.requiresIntegrations
get() = findAnnotationRecursively(RequiresIntegrations::class) != null
/**
* The options of a [Patch].
*/
val PatchClass.options: PatchOptions?
get() = kotlin.companionObject?.let { cl ->
if (cl.visibility != KVisibility.PUBLIC) return null
kotlin.companionObjectInstance?.let {
(it as? OptionsContainer)?.options
}
}
}

View File

@@ -0,0 +1,9 @@
package app.revanced.patcher.fingerprint
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
/**
* A ReVanced fingerprint.
* Can be a [MethodFingerprint].
*/
interface Fingerprint

View File

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

View File

@@ -0,0 +1,513 @@
package app.revanced.patcher.fingerprint.method.impl
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.MethodFingerprintExtensions.fuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.Fingerprint
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.util.proxy.ClassProxy
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.ClassDef
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.StringReference
import com.android.tools.smali.dexlib2.util.MethodUtil
import java.util.*
private typealias StringMatch = MethodFingerprintResult.MethodFingerprintScanResult.StringsScanResult.StringMatch
private typealias StringsScanResult = MethodFingerprintResult.MethodFingerprintScanResult.StringsScanResult
private typealias MethodClassPair = Pair<Method, ClassDef>
/**
* 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.
*/
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
) : Fingerprint {
/**
* The result of the [MethodFingerprint].
*/
var result: MethodFingerprintResult? = null
companion object {
/**
* A list of methods and the class they were found in.
*/
private val methods = mutableListOf<MethodClassPair>()
/**
* Lookup map for methods keyed to the methods access flags, return type and parameter.
*/
private val methodSignatureLookupMap = mutableMapOf<String, MutableList<MethodClassPair>>()
/**
* Lookup map for methods keyed to the strings contained in the method.
*/
private val methodStringsLookupMap = mutableMapOf<String, MutableList<MethodClassPair>>()
/**
* Appends a string based on the parameter reference types of this method.
*/
private 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())
}
}
/**
* 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 initializeFingerprintResolutionLookupMaps(context: BytecodeContext) {
fun MutableMap<String, MutableList<MethodClassPair>>.add(
key: String,
methodClassPair: MethodClassPair
) {
var methodClassPairs = this[key]
methodClassPairs ?: run {
methodClassPairs = LinkedList<MethodClassPair>().also { this[key] = it }
}
methodClassPairs!!.add(methodClassPair)
}
if (methods.isNotEmpty()) clearFingerprintResolutionLookupMaps()
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 [initializeFingerprintResolutionLookupMaps]
*/
internal fun clearFingerprintResolutionLookupMaps() {
methods.clear()
methodSignatureLookupMap.clear()
methodStringsLookupMap.clear()
}
/**
* Resolve a list of [MethodFingerprint] using the lookup map built by [initializeFingerprintResolutionLookupMaps].
*
* [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 Iterable<MethodFingerprint>.resolveUsingLookupMap(context: BytecodeContext) {
if (methods.isEmpty()) throw PatchException("lookup map not initialized")
for (fingerprint in this) {
fingerprint.resolveUsingLookupMap(context)
}
}
/**
* Resolve a [MethodFingerprint] using the lookup map built by [initializeFingerprintResolutionLookupMaps].
*
* [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 MethodFingerprint.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(): List<MethodClassPair>? {
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(): List<MethodClassPair> {
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 emptyList()
}
/**
* Resolve a [MethodFingerprint] using a list of [MethodClassPair].
*
* @return True if the resolution was successful, false otherwise.
*/
fun MethodFingerprint.resolveUsingMethodClassPair(classMethods: Iterable<MethodClassPair>): Boolean {
classMethods.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 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>) {
for (fingerprint in this) // For each fingerprint...
classes@ for (classDef in classes) // ...search through all classes for the MethodFingerprint
if (fingerprint.resolve(context, classDef))
break@classes // ...if the resolution succeeded, continue with the next MethodFingerprint.
}
/**
* Resolve a [MethodFingerprint] against a [ClassDef].
*
* @param forClass The class on which to resolve the [MethodFingerprint] in.
* @param context The [BytecodeContext] to host proxies.
* @return True if the resolution was successful, false otherwise.
*/
fun MethodFingerprint.resolve(context: BytecodeContext, forClass: ClassDef): Boolean {
for (method in forClass.methods)
if (this.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 MethodFingerprint.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(
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 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.createWarnings(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
}
private fun MethodFingerprintResult.MethodFingerprintScanResult.PatternScanResult.createWarnings(
pattern: Iterable<Opcode?>, instructions: Iterable<Instruction>
) = buildList {
for ((patternIndex, instructionIndex) in (this@createWarnings.startIndex until this@createWarnings.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
)
)
}
}
}
}
/**
* 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.
*/
data 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.
*/
data 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.
*/
data 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.
*/
data 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].
*/
data 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.
*/
data class Warning(
val correctOpcode: Opcode,
val wrongOpcode: Opcode,
val instructionIndex: Int,
val patternIndex: Int,
)
}
}
}

View File

@@ -0,0 +1,9 @@
package app.revanced.patcher.logging
@Deprecated("This will be removed in a future release")
interface Logger {
fun error(msg: String) {}
fun warn(msg: String) {}
fun info(msg: String) {}
fun trace(msg: String) {}
}

View File

@@ -0,0 +1,6 @@
package app.revanced.patcher.logging.impl
import app.revanced.patcher.logging.Logger
@Deprecated("This will be removed in a future release")
object NopLogger : Logger

View File

@@ -0,0 +1,18 @@
package app.revanced.patcher.patch
/**
* A container for patch options.
*/
abstract class OptionsContainer {
/**
* A list of [PatchOption]s.
* @see PatchOptions
*/
@Suppress("MemberVisibilityCanBePrivate")
val options = PatchOptions()
protected fun <T> option(opt: PatchOption<T>): PatchOption<T> {
options.register(opt)
return opt
}
}

View File

@@ -1,7 +1,39 @@
package app.revanced.patcher.patch
import app.revanced.patcher.cache.Cache
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.data.Context
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import java.io.Closeable
abstract class Patch(val patchName: String) {
abstract fun execute(cache: Cache): PatchResult
typealias PatchClass = Class<out Patch<Context<*>>>
/**
* A ReVanced patch.
*
* If it implements [Closeable], it will be closed after all patches have been executed.
* Closing will be done in reverse execution order.
*/
sealed interface Patch<out T : Context<*>> {
/**
* The main function of the [Patch] which the patcher will call.
*
* @param context The [Context] the patch will work on.
* @return The result of executing the patch.
*/
fun execute(context: @UnsafeVariance T)
}
/**
* Resource patch for the Patcher.
*/
interface ResourcePatch : Patch<ResourceContext>
/**
* Bytecode patch for the Patcher.
*
* @param fingerprints A list of [MethodFingerprint] this patch relies on.
*/
abstract class BytecodePatch(
internal val fingerprints: Iterable<MethodFingerprint>? = null
) : Patch<BytecodeContext>

View File

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

View File

@@ -0,0 +1,232 @@
@file:Suppress("CanBeParameter", "MemberVisibilityCanBePrivate", "UNCHECKED_CAST")
package app.revanced.patcher.patch
import java.nio.file.Path
import kotlin.io.path.pathString
import kotlin.reflect.KProperty
class NoSuchOptionException(val option: String) : Exception("No such option: $option")
class IllegalValueException(val value: Any?) : Exception("Illegal value: $value")
class InvalidTypeException(val got: String, val expected: String) :
Exception("Invalid option value type: $got, expected $expected")
object RequirementNotMetException : Exception("null was passed into an option that requires a value")
/**
* A registry for an array of [PatchOption]s.
* @param options An array of [PatchOption]s.
*/
class PatchOptions(vararg options: PatchOption<*>) : Iterable<PatchOption<*>> {
private val register = mutableMapOf<String, PatchOption<*>>()
init {
options.forEach { register(it) }
}
internal fun register(option: PatchOption<*>) {
if (register.containsKey(option.key)) {
throw IllegalStateException("Multiple options found with the same key")
}
register[option.key] = option
}
/**
* Get a [PatchOption] by its key.
* @param key The key of the [PatchOption].
*/
@JvmName("getUntyped")
operator fun get(key: String) = register[key] ?: throw NoSuchOptionException(key)
/**
* Get a [PatchOption] by its key.
* @param key The key of the [PatchOption].
*/
inline operator fun <reified T> get(key: String): PatchOption<T> {
val opt = get(key)
if (opt.value !is T) throw InvalidTypeException(
opt.value?.let { it::class.java.canonicalName } ?: "null",
T::class.java.canonicalName
)
return opt as PatchOption<T>
}
/**
* Set the value of a [PatchOption].
* @param key The key of the [PatchOption].
* @param value The value you want it to be.
* Please note that using the wrong value type results in a runtime error.
*/
inline operator fun <reified T> set(key: String, value: T) {
val opt = get<T>(key)
if (opt.value !is T) throw InvalidTypeException(
T::class.java.canonicalName,
opt.value?.let { it::class.java.canonicalName } ?: "null"
)
opt.value = value
}
/**
* Sets the value of a [PatchOption] to `null`.
* @param key The key of the [PatchOption].
*/
fun nullify(key: String) {
get(key).value = null
}
override fun iterator() = register.values.iterator()
}
/**
* A [Patch] option.
* @param key Unique identifier of the option. Example: _`settings`_
* @param default The default value of the option.
* @param title A human-readable title of the option. Example: _Patch Settings_
* @param description A human-readable description of the option. Example: _Settings for the patches._
* @param required Whether the option is required.
*/
@Suppress("MemberVisibilityCanBePrivate")
sealed class PatchOption<T>(
val key: String,
default: T?,
val title: String,
val description: String,
val required: Boolean,
val validator: (T?) -> Boolean
) {
var value: T? = default
get() {
if (field == null && required) {
throw RequirementNotMetException
}
return field
}
set(value) {
if (value == null && required) {
throw RequirementNotMetException
}
if (!validator(value)) {
throw IllegalValueException(value)
}
field = value
}
/**
* Gets the value of the option.
* Please note that using the wrong value type results in a runtime error.
*/
@JvmName("getValueTyped")
inline operator fun <reified V> getValue(thisRef: Nothing?, property: KProperty<*>): V? {
if (value !is V?) throw InvalidTypeException(
V::class.java.canonicalName,
value?.let { it::class.java.canonicalName } ?: "null"
)
return value as? V?
}
operator fun getValue(thisRef: Any?, property: KProperty<*>) = value
/**
* Gets the value of the option.
* Please note that using the wrong value type results in a runtime error.
*/
@JvmName("setValueTyped")
inline operator fun <reified V> setValue(thisRef: Nothing?, property: KProperty<*>, new: V) {
if (value !is V) throw InvalidTypeException(
V::class.java.canonicalName,
value?.let { it::class.java.canonicalName } ?: "null"
)
value = new as T
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, new: T?) {
value = new
}
/**
* A [PatchOption] representing a [String].
* @see PatchOption
*/
class StringOption(
key: String,
default: String?,
title: String,
description: String,
required: Boolean = false,
validator: (String?) -> Boolean = { true }
) : PatchOption<String>(
key, default, title, description, required, validator
)
/**
* A [PatchOption] representing a [Boolean].
* @see PatchOption
*/
class BooleanOption(
key: String,
default: Boolean?,
title: String,
description: String,
required: Boolean = false,
validator: (Boolean?) -> Boolean = { true }
) : PatchOption<Boolean>(
key, default, title, description, required, validator
)
/**
* A [PatchOption] with a list of allowed options.
* @param options A list of allowed options for the [ListOption].
* @see PatchOption
*/
sealed class ListOption<E>(
key: String,
default: E?,
val options: Iterable<E>,
title: String,
description: String,
required: Boolean = false,
validator: (E?) -> Boolean = { true }
) : PatchOption<E>(
key, default, title, description, required, {
(it?.let { it in options } ?: true) && validator(it)
}
) {
init {
if (default != null && default !in options) {
throw IllegalStateException("Default option must be an allowed option")
}
}
}
/**
* A [ListOption] of type [String].
* @see ListOption
*/
class StringListOption(
key: String,
default: String?,
options: Iterable<String>,
title: String,
description: String,
required: Boolean = false,
validator: (String?) -> Boolean = { true }
) : ListOption<String>(
key, default, options, title, description, required, validator
)
/**
* A [ListOption] of type [Int].
* @see ListOption
*/
class IntListOption(
key: String,
default: Int?,
options: Iterable<Int>,
title: String,
description: String,
required: Boolean = false,
validator: (Int?) -> Boolean = { true }
) : ListOption<Int>(
key, default, options, title, description, required, validator
)
}

View File

@@ -1,33 +1,10 @@
package app.revanced.patcher.patch
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
/**
* A result of executing a [Patch].
*
* @param patchName The name of the [Patch].
* @param exception The [PatchException] thrown, if any.
*/
@Suppress("MemberVisibilityCanBePrivate")
class PatchResult internal constructor(val patchName: String, val exception: PatchException? = null)

View File

@@ -0,0 +1,27 @@
package app.revanced.patcher.patch.annotations
import app.revanced.patcher.data.Context
import app.revanced.patcher.patch.Patch
import kotlin.reflect.KClass
/**
* Annotation to mark a class as a patch.
* @param include If false, the patch should be treated as optional by default.
*/
@Target(AnnotationTarget.CLASS)
annotation class Patch(val include: Boolean = true)
/**
* Annotation for dependencies of [Patch]es.
*/
@Target(AnnotationTarget.CLASS)
annotation class DependsOn(
val dependencies: Array<KClass<out Patch<Context<*>>>> = []
)
// TODO: Remove this annotation, once integrations are coupled with patches.
/**
* Annotation to mark [Patch]es which depend on integrations.
*/
@Target(AnnotationTarget.CLASS)
annotation class RequiresIntegrations

View File

@@ -1,159 +0,0 @@
package app.revanced.patcher.resolver
import mu.KotlinLogging
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 org.objectweb.asm.Type
import org.objectweb.asm.tree.ClassNode
import org.objectweb.asm.tree.InsnList
import org.objectweb.asm.tree.MethodNode
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.debug { "Sig ${signature.name} already found, skipping." }
continue
}
logger.debug { "Resolving sig ${signature.name}: ${classNode.name} / ${method.name}" }
val (r, sr) = cmp(method, signature)
if (!r || sr == null) {
logger.debug { "Compare result for sig ${signature.name} has failed!" }
continue
}
logger.debug { "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.debug {
"""
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.debug {
"""
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.debug {
"""
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.debug { "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(): ClassNode {
return this
}
private operator fun ClassNode.component2(): List<MethodNode> {
return this.methods
}
private fun InsnList.scanFor(pattern: IntArray): ScanResult {
for (i in 0 until this.size()) {
var occurrence = 0
while (i + occurrence < this.size()) {
if (this[i + occurrence].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()
}

View File

@@ -1,7 +0,0 @@
package app.revanced.patcher.resolver
internal data class ScanResult(
val found: Boolean,
val startIndex: Int? = 0,
val endIndex: Int? = 0
)

View File

@@ -1,27 +0,0 @@
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?
)

View File

@@ -0,0 +1,222 @@
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)
}
}
}
}

View File

@@ -0,0 +1,87 @@
package app.revanced.patcher.util
import org.w3c.dom.Document
import java.io.Closeable
import java.io.File
import java.io.InputStream
import java.io.OutputStream
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.transform.TransformerFactory
import javax.xml.transform.dom.DOMSource
import javax.xml.transform.stream.StreamResult
/**
* Wrapper for a file that can be edited as a dom document.
*
* This constructor does not check for locks to the file when writing.
* Use the secondary constructor.
*
* @param inputStream the input stream to read the xml file from.
* @param outputStream the output stream to write the xml file to. If null, the file will be read only.
*
*/
class DomFileEditor internal constructor(
private val inputStream: InputStream,
private val outputStream: Lazy<OutputStream>? = null,
) : Closeable {
// path to the xml file to unlock the resource when closing the editor
private var filePath: String? = null
private var closed: Boolean = false
/**
* The document of the xml file
*/
val file: Document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(inputStream)
.also(Document::normalize)
// lazily open an output stream
// this is required because when constructing a DomFileEditor the output stream is created along with the input stream, which is not allowed
// the workaround is to lazily create the output stream. This way it would be used after the input stream is closed, which happens in the constructor
constructor(file: File) : this(file.inputStream(), lazy { file.outputStream() }) {
// increase the lock
locks.merge(file.path, 1, Integer::sum)
filePath = file.path
}
/**
* Closes the editor. Write backs and decreases the lock count.
*
* Will not write back to the file if the file is still locked.
*/
override fun close() {
if (closed) return
inputStream.close()
// if the output stream is not null, do not close it
outputStream?.let {
// prevent writing to same file, if it is being locked
// isLocked will be false if the editor was created through a stream
val isLocked = filePath?.let { path ->
val isLocked = locks[path]!! > 1
// decrease the lock count if the editor was opened for a file
locks.merge(path, -1, Integer::sum)
isLocked
} ?: false
// if unlocked, write back to the file
if (!isLocked) {
it.value.use { stream ->
val result = StreamResult(stream)
TransformerFactory.newInstance().newTransformer().transform(DOMSource(file), result)
}
it.value.close()
return
}
}
closed = true
}
private companion object {
// map of concurrent open files
val locks = mutableMapOf<String, Int>()
}
}

View File

@@ -1,12 +0,0 @@
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)
}

View File

@@ -1,93 +0,0 @@
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)
// 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) {
// skip all class files because we added them in the loop above
// TODO(oSumAtrIX): Check for zipEntry.isDirectory
if (zipEntry.name.endsWith(".class")) continue
// create a new zipEntry and write the contents of the zipEntry to the output stream
jos.putNextEntry(ZipEntry(zipEntry))
jos.write(jis.readBytes())
// close the newly created zipEntry
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
jos.putNextEntry(JarEntry(patchedClass.name + ".class"))
// parse the patched class to a byte array and write it to the output stream
val cw = ClassWriter(ClassWriter.COMPUTE_MAXS or ClassWriter.COMPUTE_FRAMES)
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()
}
}

View File

@@ -0,0 +1,33 @@
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
}
}

View File

@@ -0,0 +1,56 @@
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)
}

View File

@@ -0,0 +1,33 @@
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)
}
}

View File

@@ -0,0 +1,29 @@
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)
}
}
}

View File

@@ -0,0 +1,34 @@
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)
}
}
}

View File

@@ -0,0 +1,103 @@
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.google.common.collect.Iterables
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
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)
}
}
}

View File

@@ -0,0 +1,73 @@
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)
}
}
}

View File

@@ -0,0 +1,80 @@
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)
}
}
}

View File

@@ -0,0 +1,37 @@
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)
}
}
}

View File

@@ -0,0 +1,33 @@
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)
}
}
}

View File

@@ -0,0 +1,22 @@
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)
}
}
}

View File

@@ -0,0 +1,23 @@
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)
}
}
}

View File

@@ -0,0 +1,22 @@
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)
}
}
}

View File

@@ -0,0 +1,22 @@
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)
}
}
}

View File

@@ -0,0 +1,23 @@
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)
}
}
}

View File

@@ -0,0 +1,32 @@
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
}
}
}
}

View File

@@ -0,0 +1,23 @@
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)
}
}
}

View File

@@ -0,0 +1,28 @@
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)
}
}
}

View File

@@ -0,0 +1,22 @@
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)
}
}
}

View File

@@ -0,0 +1,22 @@
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)
}
}
}

View File

@@ -0,0 +1,22 @@
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)
}
}
}

View File

@@ -0,0 +1,24 @@
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)
}
}
}

View File

@@ -0,0 +1,27 @@
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)
}
}
}

View File

@@ -0,0 +1,26 @@
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
import com.android.tools.smali.dexlib2.base.value.BaseMethodTypeEncodedValue
import com.android.tools.smali.dexlib2.iface.reference.MethodProtoReference
import com.android.tools.smali.dexlib2.iface.value.MethodTypeEncodedValue
class MutableMethodTypeEncodedValue(methodTypeEncodedValue: MethodTypeEncodedValue) : BaseMethodTypeEncodedValue(),
MutableEncodedValue {
private var value = methodTypeEncodedValue.value
override fun getValue(): MethodProtoReference {
return this.value
}
fun setValue(value: MethodProtoReference) {
this.value = value
}
companion object {
fun MethodTypeEncodedValue.toMutable(): MutableMethodTypeEncodedValue {
return MutableMethodTypeEncodedValue(this)
}
}
}

View File

@@ -0,0 +1,12 @@
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
import com.android.tools.smali.dexlib2.base.value.BaseNullEncodedValue
import com.android.tools.smali.dexlib2.iface.value.ByteEncodedValue
class MutableNullEncodedValue : BaseNullEncodedValue(), MutableEncodedValue {
companion object {
fun ByteEncodedValue.toMutable(): MutableByteEncodedValue {
return MutableByteEncodedValue(this)
}
}
}

View File

@@ -0,0 +1,22 @@
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
import com.android.tools.smali.dexlib2.base.value.BaseShortEncodedValue
import com.android.tools.smali.dexlib2.iface.value.ShortEncodedValue
class MutableShortEncodedValue(shortEncodedValue: ShortEncodedValue) : BaseShortEncodedValue(), MutableEncodedValue {
private var value = shortEncodedValue.value
override fun getValue(): Short {
return this.value
}
fun setValue(value: Short) {
this.value = value
}
companion object {
fun ShortEncodedValue.toMutable(): MutableShortEncodedValue {
return MutableShortEncodedValue(this)
}
}
}

View File

@@ -0,0 +1,24 @@
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
import com.android.tools.smali.dexlib2.base.value.BaseStringEncodedValue
import com.android.tools.smali.dexlib2.iface.value.ByteEncodedValue
import com.android.tools.smali.dexlib2.iface.value.StringEncodedValue
class MutableStringEncodedValue(stringEncodedValue: StringEncodedValue) : BaseStringEncodedValue(),
MutableEncodedValue {
private var value = stringEncodedValue.value
override fun getValue(): String {
return this.value
}
fun setValue(value: String) {
this.value = value
}
companion object {
fun ByteEncodedValue.toMutable(): MutableByteEncodedValue {
return MutableByteEncodedValue(this)
}
}
}

View File

@@ -0,0 +1,22 @@
package app.revanced.patcher.util.proxy.mutableTypes.encodedValue
import com.android.tools.smali.dexlib2.base.value.BaseTypeEncodedValue
import com.android.tools.smali.dexlib2.iface.value.TypeEncodedValue
class MutableTypeEncodedValue(typeEncodedValue: TypeEncodedValue) : BaseTypeEncodedValue(), MutableEncodedValue {
private var value = typeEncodedValue.value
override fun getValue(): String {
return this.value
}
fun setValue(value: String) {
this.value = value
}
companion object {
fun TypeEncodedValue.toMutable(): MutableTypeEncodedValue {
return MutableTypeEncodedValue(this)
}
}
}

View File

@@ -0,0 +1,10 @@
package app.revanced.patcher.util.smali
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
/**
* A class that represents a label for an instruction.
* @param name The label name.
* @param instruction The instruction that this label is for.
*/
data class ExternalLabel(internal val name: String, internal val instruction: Instruction)

View File

@@ -0,0 +1,84 @@
package app.revanced.patcher.util.smali
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import org.antlr.runtime.CommonTokenStream
import org.antlr.runtime.TokenSource
import org.antlr.runtime.tree.CommonTreeNodeStream
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcodes
import com.android.tools.smali.dexlib2.builder.BuilderInstruction
import com.android.tools.smali.dexlib2.writer.builder.DexBuilder
import com.android.tools.smali.smali.LexerErrorInterface
import com.android.tools.smali.smali.smaliFlexLexer
import com.android.tools.smali.smali.smaliParser
import com.android.tools.smali.smali.smaliTreeWalker
import java.io.InputStreamReader
private const val METHOD_TEMPLATE = """
.class LInlineCompiler;
.super Ljava/lang/Object;
.method %s dummyMethod(%s)V
.registers %d
%s
.end method
"""
class InlineSmaliCompiler {
companion object {
/**
* Compiles a string of Smali code to a list of instructions.
* Special registers (such as p0, p1) will only work correctly
* if the parameters and registers of the method are passed.
*/
fun compile(
instructions: String, parameters: String, registers: Int, forStaticMethod: Boolean
): List<BuilderInstruction> {
val input = METHOD_TEMPLATE.format(
if (forStaticMethod) {
"static"
} else {
""
}, parameters, registers, instructions
)
val reader = InputStreamReader(input.byteInputStream())
val lexer: LexerErrorInterface = smaliFlexLexer(reader, 15)
val tokens = CommonTokenStream(lexer as TokenSource)
val parser = smaliParser(tokens)
val result = parser.smali_file()
if (parser.numberOfSyntaxErrors > 0 || lexer.numberOfSyntaxErrors > 0) {
throw IllegalStateException(
"Encountered ${parser.numberOfSyntaxErrors} parser syntax errors and ${lexer.numberOfSyntaxErrors} lexer syntax errors!"
)
}
val treeStream = CommonTreeNodeStream(result.tree)
treeStream.tokenStream = tokens
val dexGen = smaliTreeWalker(treeStream)
dexGen.setDexBuilder(DexBuilder(Opcodes.getDefault()))
val classDef = dexGen.smali_file()
return classDef.methods.first().implementation!!.instructions.map { it as BuilderInstruction }
}
}
}
/**
* Compile lines of Smali code to a list of instructions.
*
* Note: Adding compiled instructions to an existing method with
* offset instructions WITHOUT specifying a parent method will not work.
* @param method The method to compile the instructions against.
* @returns A list of instructions.
*/
fun String.toInstructions(method: MutableMethod? = null): List<BuilderInstruction> {
return InlineSmaliCompiler.compile(this,
method?.parameters?.joinToString("") { it } ?: "",
method?.implementation?.registerCount ?: 1,
method?.let { AccessFlags.STATIC.isSet(it.accessFlags) } ?: true
)
}
/**
* Compile a line of Smali code to an instruction.
* @param templateMethod The method to compile the instructions against.
* @return The instruction.
*/
fun String.toInstruction(templateMethod: MutableMethod? = null) = this.toInstructions(templateMethod).first()

View File

@@ -1,21 +0,0 @@
package app.revanced.patcher.writer
import org.objectweb.asm.tree.AbstractInsnNode
import org.objectweb.asm.tree.InsnList
object ASMWriter {
fun InsnList.setAt(index: Int, node: AbstractInsnNode) {
this[this.get(index)] = node
}
fun InsnList.insertAt(index: Int = 0, vararg nodes: AbstractInsnNode) {
this.insert(this.get(index), nodes.toInsnList())
}
// TODO(Sculas): Should this be public?
private fun Array<out AbstractInsnNode>.toInsnList(): InsnList {
val list = InsnList()
this.forEach { list.add(it) }
return list
}
}

View File

@@ -0,0 +1 @@
version=${projectVersion}

View File

@@ -1,161 +0,0 @@
package app.revanced.patcher
import app.revanced.patcher.cache.Cache
import app.revanced.patcher.patch.Patch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.signature.Signature
import app.revanced.patcher.util.ExtraTypes
import app.revanced.patcher.util.TestUtil
import app.revanced.patcher.writer.ASMWriter.insertAt
import app.revanced.patcher.writer.ASMWriter.setAt
import org.junit.jupiter.api.assertDoesNotThrow
import org.objectweb.asm.Opcodes.*
import org.objectweb.asm.Type
import org.objectweb.asm.tree.FieldInsnNode
import org.objectweb.asm.tree.LdcInsnNode
import org.objectweb.asm.tree.MethodInsnNode
import java.io.ByteArrayOutputStream
import java.io.PrintStream
import kotlin.test.Test
internal class PatcherTest {
companion object {
val testSignatures: Array<Signature> = arrayOf(
// Java:
// public static void main(String[] args) {
// System.out.println("Hello, world!");
// }
// Bytecode:
// public static main(java.lang.String[] arg0) { // Method signature: ([Ljava/lang/String;)V
// getstatic java/lang/System.out:java.io.PrintStream
// ldc "Hello, world!" (java.lang.String)
// invokevirtual java/io/PrintStream.println(Ljava/lang/String;)V
// return
// }
Signature(
"mainMethod",
Type.VOID_TYPE,
ACC_PUBLIC or ACC_STATIC,
arrayOf(ExtraTypes.ArrayAny),
intArrayOf(
LDC,
INVOKEVIRTUAL
)
)
)
}
@Test
fun testPatcher() {
val patcher = Patcher(
PatcherTest::class.java.getResourceAsStream("/test1.jar")!!,
ByteArrayOutputStream(),
testSignatures
)
patcher.addPatches(
object : Patch("TestPatch") {
override fun execute(cache: Cache): PatchResult {
// Get the method from the resolver cache
val mainMethod = patcher.cache.methods["mainMethod"]
// Get the instruction list
val instructions = mainMethod.method.instructions!!
// Let's modify it, so it prints "Hello, ReVanced! Editing bytecode."
// Get the start index of our opcode pattern.
// This will be the index of the LDC instruction.
val startIndex = mainMethod.scanData.startIndex
TestUtil.assertNodeEqual(LdcInsnNode("Hello, world!"), instructions[startIndex]!!)
// Create a new LDC node and replace the LDC instruction.
val stringNode = LdcInsnNode("Hello, ReVanced! Editing bytecode.")
instructions.setAt(startIndex, stringNode)
// Now lets print our string twice!
// Insert our instructions after the second instruction by our pattern.
// This will place our instructions after the original INVOKEVIRTUAL call.
// You could also copy the instructions from the list and then modify the LDC instruction again,
// but this is to show a more advanced example of writing bytecode using the patcher and ASM.
instructions.insertAt(
startIndex + 1,
FieldInsnNode(
GETSTATIC,
Type.getInternalName(System::class.java), // "java/lang/System"
"out",
"L" + Type.getInternalName(PrintStream::class.java) // "Ljava/io/PrintStream"
),
LdcInsnNode("Hello, ReVanced! Adding bytecode."),
MethodInsnNode(
INVOKEVIRTUAL,
Type.getInternalName(PrintStream::class.java), // "java/io/PrintStream"
"println",
Type.getMethodDescriptor(
Type.VOID_TYPE,
Type.getType(String::class.java)
) // "(Ljava/lang/String;)V"
)
)
// Our code now looks like this:
// public static main(java.lang.String[] arg0) { // Method signature: ([Ljava/lang/String;)V
// getstatic java/lang/System.out:java.io.PrintStream
// ldc "Hello, ReVanced! Editing bytecode." (java.lang.String) // We overwrote this instruction.
// invokevirtual java/io/PrintStream.println(Ljava/lang/String;)V
// getstatic java/lang/System.out:java.io.PrintStream // This instruction and the 2 instructions below are written manually.
// ldc "Hello, ReVanced! Adding bytecode." (java.lang.String)
// invokevirtual java/io/PrintStream.println(Ljava/lang/String;)V
// return
// }
// Finally, tell the patcher that this patch was a success.
// You can also return PatchResultError with a message.
// If an exception is thrown inside this function,
// a PatchResultError will be returned with the error message.
return PatchResultSuccess()
}
}
)
// Apply all patches loaded in the patcher
val patchResult = patcher.applyPatches()
// You can check if an error occurred
for ((patchName, result) in patchResult) {
if (result.isFailure) {
throw Exception("Patch $patchName failed", result.exceptionOrNull()!!)
}
}
patcher.save()
}
@Test
fun `test patcher with no changes`() {
val testData = PatcherTest::class.java.getResourceAsStream("/test1.jar")!!
// val available = testData.available()
val out = ByteArrayOutputStream()
Patcher(testData, out, testSignatures).save()
// FIXME(Sculas): There seems to be a 1-byte difference, not sure what it is.
// assertEquals(available, out.size())
out.close()
}
@Test()
fun `should not raise an exception if any signature member except the name is missing`() {
val sigName = "testMethod"
assertDoesNotThrow("Should raise an exception because opcodes is empty") {
Patcher(
PatcherTest::class.java.getResourceAsStream("/test1.jar")!!,
ByteArrayOutputStream(),
arrayOf(
Signature(
sigName,
null,
null,
null,
null
))
)
}
}
}

Some files were not shown because too many files have changed in this diff Show More