From 4484ff515669a66e025817a6b1d8890845d97154 Mon Sep 17 00:00:00 2001 From: TomXin <766781886@qq.com> Date: Thu, 24 Oct 2024 14:33:39 +0800 Subject: [PATCH 1/8] Relocate fernflower like decompiler --- recaf-core/build.gradle | 3 +- .../decompile/vineflower/BaseSource.java | 2 +- .../decompile/vineflower/ClassSource.java | 2 +- .../vineflower/DecompiledOutputSink.java | 2 +- .../vineflower/DummyResultSaver.java | 2 +- .../vineflower/VineflowerConfig.java | 4 +- .../vineflower/VineflowerDecompiler.java | 6 +- .../vineflower/VineflowerLogger.java | 2 +- recaf-relocation/build.gradle.kts | 112 ++++++++++++++++++ settings.gradle | 1 + 10 files changed, 125 insertions(+), 11 deletions(-) create mode 100644 recaf-relocation/build.gradle.kts diff --git a/recaf-core/build.gradle b/recaf-core/build.gradle index 9d03caec7..91c691426 100644 --- a/recaf-core/build.gradle +++ b/recaf-core/build.gradle @@ -38,7 +38,8 @@ dependencies { api(libs.openrewrite) api(libs.regex) api(libs.bundles.jasm) - api(libs.vineflower) +// api(libs.vineflower) + api( project(':recaf-relocation')) api(libs.wordwrap) } diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/BaseSource.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/BaseSource.java index 7bc892e8e..6f0aa4597 100644 --- a/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/BaseSource.java +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/BaseSource.java @@ -1,7 +1,7 @@ package software.coley.recaf.services.decompile.vineflower; import jakarta.annotation.Nonnull; -import org.jetbrains.java.decompiler.main.extern.IContextSource; +import recaf.relocation.libs.vineflower.org.jetbrains.java.decompiler.main.extern.IContextSource; import software.coley.recaf.info.JvmClassInfo; import software.coley.recaf.path.ClassPathNode; import software.coley.recaf.workspace.model.Workspace; diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/ClassSource.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/ClassSource.java index 23ceb2116..9eb876163 100644 --- a/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/ClassSource.java +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/ClassSource.java @@ -1,7 +1,7 @@ package software.coley.recaf.services.decompile.vineflower; import jakarta.annotation.Nonnull; -import org.jetbrains.java.decompiler.main.extern.IResultSaver; +import recaf.relocation.libs.vineflower.org.jetbrains.java.decompiler.main.extern.IResultSaver; import software.coley.recaf.info.InnerClassInfo; import software.coley.recaf.info.JvmClassInfo; import software.coley.recaf.workspace.model.Workspace; diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/DecompiledOutputSink.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/DecompiledOutputSink.java index 0ddc62cb6..0c5c2ee1e 100644 --- a/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/DecompiledOutputSink.java +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/DecompiledOutputSink.java @@ -1,7 +1,7 @@ package software.coley.recaf.services.decompile.vineflower; import jakarta.annotation.Nonnull; -import org.jetbrains.java.decompiler.main.extern.IContextSource; +import recaf.relocation.libs.vineflower.org.jetbrains.java.decompiler.main.extern.IContextSource; import software.coley.recaf.info.JvmClassInfo; import java.io.IOException; diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/DummyResultSaver.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/DummyResultSaver.java index d94a89cc6..87ddd110f 100644 --- a/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/DummyResultSaver.java +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/DummyResultSaver.java @@ -1,6 +1,6 @@ package software.coley.recaf.services.decompile.vineflower; -import org.jetbrains.java.decompiler.main.extern.IResultSaver; +import recaf.relocation.libs.vineflower.org.jetbrains.java.decompiler.main.extern.IResultSaver; import java.util.jar.Manifest; diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/VineflowerConfig.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/VineflowerConfig.java index 574894221..5bc39f7dc 100644 --- a/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/VineflowerConfig.java +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/VineflowerConfig.java @@ -3,8 +3,8 @@ import jakarta.annotation.Nonnull; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; -import org.jetbrains.java.decompiler.main.Fernflower; -import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; +import recaf.relocation.libs.vineflower.org.jetbrains.java.decompiler.main.Fernflower; +import recaf.relocation.libs.vineflower.org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; import org.slf4j.event.Level; import software.coley.observables.ObservableBoolean; import software.coley.observables.ObservableObject; diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/VineflowerDecompiler.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/VineflowerDecompiler.java index 00461616f..d1b31b796 100644 --- a/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/VineflowerDecompiler.java +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/VineflowerDecompiler.java @@ -3,9 +3,9 @@ import jakarta.annotation.Nonnull; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; -import org.jetbrains.java.decompiler.main.Fernflower; -import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; -import org.jetbrains.java.decompiler.main.extern.IResultSaver; +import recaf.relocation.libs.vineflower.org.jetbrains.java.decompiler.main.Fernflower; +import recaf.relocation.libs.vineflower.org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; +import recaf.relocation.libs.vineflower.org.jetbrains.java.decompiler.main.extern.IResultSaver; import software.coley.recaf.info.JvmClassInfo; import software.coley.recaf.services.decompile.AbstractJvmDecompiler; import software.coley.recaf.services.decompile.DecompileResult; diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/VineflowerLogger.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/VineflowerLogger.java index 1167f117a..022602b12 100644 --- a/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/VineflowerLogger.java +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/VineflowerLogger.java @@ -1,7 +1,7 @@ package software.coley.recaf.services.decompile.vineflower; import jakarta.annotation.Nonnull; -import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; +import recaf.relocation.libs.vineflower.org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; import org.slf4j.Logger; import org.slf4j.event.Level; import software.coley.observables.ObservableObject; diff --git a/recaf-relocation/build.gradle.kts b/recaf-relocation/build.gradle.kts new file mode 100644 index 000000000..cc1fcc124 --- /dev/null +++ b/recaf-relocation/build.gradle.kts @@ -0,0 +1,112 @@ +import org.objectweb.asm.ClassReader +import org.objectweb.asm.ClassWriter +import org.objectweb.asm.commons.ClassRemapper +import org.objectweb.asm.commons.Remapper +import java.util.zip.ZipEntry +import java.util.zip.ZipFile +import java.util.zip.ZipOutputStream + +buildscript { + repositories { + mavenCentral() + maven { + url = uri("https://plugins.gradle.org/m2/") + } + } + dependencies { + classpath(libs.bundles.asm) + } + +} + +plugins { + id("java-library") +} + +val artifactTypeAttribute = Attribute.of("artifactType", String::class.java) +val repackagedAttribute = Attribute.of("repackaged", Boolean::class.javaObjectType) + +val repackage: Configuration by configurations.creating { + attributes.attribute(repackagedAttribute, true) +} + +// Configure project's dependencies +abstract class MyRepackager : TransformAction { + @InputArtifact + abstract fun getInputArtifact(): Provider + override fun transform(outputs: TransformOutputs) { + val input = getInputArtifact().get().asFile + val output = outputs.file( + input.name.let { + if (it.endsWith(".jar")) + it.replaceRange(it.length - 4, it.length, "-repackaged.jar") + else + "$it-repackaged" + } + ) + println("Repackaging ${input.absolutePath} to ${output.absolutePath}") + ZipOutputStream(output.outputStream()).use { zipOut -> + relocate(zipOut, ZipFile(input), "recaf/relocation/libs/vineflower/") + zipOut.flush() + } + } + + fun relocate(zipOut: ZipOutputStream, zipFile: ZipFile, repackPrefix: String) { + zipFile.use { zipIn -> + val entriesList = zipIn.entries().toList() + val entriesSet = entriesList.mapTo(mutableSetOf()) { it.name } + for (entry in entriesList) { + val newName = if (entry.name.contains("/") && !entry.name.startsWith("META-INF/")) { + repackPrefix + entry.name + } else { + entry.name + } + zipOut.putNextEntry(ZipEntry(newName)) + if (entry.name.endsWith(".class")) { + val writer = ClassWriter(0) + ClassReader(zipIn.getInputStream(entry)).accept( + ClassRemapper( + writer, + object : Remapper() { + override fun map(internalName: String?): String? { + if (internalName == null) return null + return if (entriesSet.contains("$internalName.class")) { + repackPrefix + internalName + } else { + internalName + } + } + } + ), + 0 + ) + zipOut.write( + writer.toByteArray() + ) + } else { + zipIn.getInputStream(entry).copyTo(zipOut) + } + // zipOut.putNextEntry(ZipEntry(entry.name)) + // zipIn.getInputStream(entry).copyTo(zipOut) + zipOut.closeEntry() + } + } + } +} + + +dependencies { + attributesSchema { + attribute(repackagedAttribute) + } + artifactTypes.getByName("jar") { + attributes.attribute(repackagedAttribute, false) + } + registerTransform(MyRepackager::class) { + from.attribute(repackagedAttribute, false).attribute(artifactTypeAttribute, "jar") + to.attribute(repackagedAttribute, true).attribute(artifactTypeAttribute, "jar") + } + + repackage(libs.vineflower) + api(files(repackage.files)) +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index aa3c95e07..0ca243794 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,6 @@ rootProject.name = 'Recaf' +include 'recaf-relocation' include 'recaf-core' include 'recaf-ui' From 15091af1276435b2699f0911873db9c0547fa791 Mon Sep 17 00:00:00 2001 From: TomXin <766781886@qq.com> Date: Thu, 24 Oct 2024 15:30:18 +0800 Subject: [PATCH 2/8] Relocate the embedded jar in fernflower like decompiler --- recaf-relocation/build.gradle.kts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/recaf-relocation/build.gradle.kts b/recaf-relocation/build.gradle.kts index cc1fcc124..dddc29f56 100644 --- a/recaf-relocation/build.gradle.kts +++ b/recaf-relocation/build.gradle.kts @@ -2,6 +2,7 @@ import org.objectweb.asm.ClassReader import org.objectweb.asm.ClassWriter import org.objectweb.asm.commons.ClassRemapper import org.objectweb.asm.commons.Remapper +import java.io.ByteArrayOutputStream import java.util.zip.ZipEntry import java.util.zip.ZipFile import java.util.zip.ZipOutputStream @@ -83,11 +84,25 @@ abstract class MyRepackager : TransformAction { zipOut.write( writer.toByteArray() ) + } else if (entry.name.endsWith(".jar")) { + val tempJar = File.createTempFile("recaf-relocate-", ".jar") + + // zipIn.getInputStream(entry).copyTo(fo) + tempJar.writeBytes(zipIn.getInputStream(entry).readBytes()) + ByteArrayOutputStream().use { bo -> + ZipOutputStream(bo).use { zos -> + relocate(zos, ZipFile(tempJar), repackPrefix) + zos.flush() + } + bo.flush() + zipOut.write(bo.toByteArray()) + } + if (tempJar.exists()) { + tempJar.delete() + } } else { zipIn.getInputStream(entry).copyTo(zipOut) } - // zipOut.putNextEntry(ZipEntry(entry.name)) - // zipIn.getInputStream(entry).copyTo(zipOut) zipOut.closeEntry() } } From 5cd45a0bbf724407bf28578caa1ff5af5e38dc01 Mon Sep 17 00:00:00 2001 From: TomXin <766781886@qq.com> Date: Thu, 24 Oct 2024 18:36:34 +0800 Subject: [PATCH 3/8] Special handling of some files in jar packages --- recaf-relocation/build.gradle.kts | 110 +++++++++++++++++++----------- 1 file changed, 70 insertions(+), 40 deletions(-) diff --git a/recaf-relocation/build.gradle.kts b/recaf-relocation/build.gradle.kts index dddc29f56..18630a079 100644 --- a/recaf-relocation/build.gradle.kts +++ b/recaf-relocation/build.gradle.kts @@ -2,7 +2,9 @@ import org.objectweb.asm.ClassReader import org.objectweb.asm.ClassWriter import org.objectweb.asm.commons.ClassRemapper import org.objectweb.asm.commons.Remapper +import java.io.BufferedReader import java.io.ByteArrayOutputStream +import java.io.InputStreamReader import java.util.zip.ZipEntry import java.util.zip.ZipFile import java.util.zip.ZipOutputStream @@ -47,61 +49,89 @@ abstract class MyRepackager : TransformAction { ) println("Repackaging ${input.absolutePath} to ${output.absolutePath}") ZipOutputStream(output.outputStream()).use { zipOut -> - relocate(zipOut, ZipFile(input), "recaf/relocation/libs/vineflower/") + relocate(zipOut, ZipFile(input), "recaf/relocation/libs/vineflower/", null) zipOut.flush() } } - fun relocate(zipOut: ZipOutputStream, zipFile: ZipFile, repackPrefix: String) { + fun relocate( + zipOut: ZipOutputStream, + zipFile: ZipFile, + repackPrefix: String, + prententriesSet: MutableSet? + ) { zipFile.use { zipIn -> val entriesList = zipIn.entries().toList() val entriesSet = entriesList.mapTo(mutableSetOf()) { it.name } + if (prententriesSet != null) { + entriesSet.addAll(prententriesSet) + } for (entry in entriesList) { - val newName = if (entry.name.contains("/") && !entry.name.startsWith("META-INF/")) { - repackPrefix + entry.name - } else { - entry.name + if (entry.name.endsWith("module-info.class")) { + continue } + val newName = + if (!entry.isDirectory && entry.name.startsWith("META-INF/services/")) { + "META-INF/services/" + repackPrefix.replace( + '/', + '.' + ) + entry.name.substring(entry.name.lastIndexOf('/') + 1) + } else if (entry.name.contains("/") && !entry.name.startsWith("META-INF/")) { + repackPrefix + entry.name + } else { + entry.name + } zipOut.putNextEntry(ZipEntry(newName)) - if (entry.name.endsWith(".class")) { - val writer = ClassWriter(0) - ClassReader(zipIn.getInputStream(entry)).accept( - ClassRemapper( - writer, - object : Remapper() { - override fun map(internalName: String?): String? { - if (internalName == null) return null - return if (entriesSet.contains("$internalName.class")) { - repackPrefix + internalName - } else { - internalName + if (!entry.isDirectory) { + if (entry.name.endsWith(".class")) { + val writer = ClassWriter(0) + ClassReader(zipIn.getInputStream(entry)).accept( + ClassRemapper( + writer, + object : Remapper() { + override fun map(internalName: String?): String? { + if (internalName == null) return null + return if (entriesSet.contains("$internalName.class")) { + repackPrefix + internalName + } else { + internalName + } } } - } - ), - 0 - ) - zipOut.write( - writer.toByteArray() - ) - } else if (entry.name.endsWith(".jar")) { - val tempJar = File.createTempFile("recaf-relocate-", ".jar") + ), + 0 + ) + zipOut.write( + writer.toByteArray() + ) + } else if (entry.name.endsWith(".jar")) { + val tempJar = File.createTempFile("recaf-relocate-", ".jar") - // zipIn.getInputStream(entry).copyTo(fo) - tempJar.writeBytes(zipIn.getInputStream(entry).readBytes()) - ByteArrayOutputStream().use { bo -> - ZipOutputStream(bo).use { zos -> - relocate(zos, ZipFile(tempJar), repackPrefix) - zos.flush() + // zipIn.getInputStream(entry).copyTo(fo) + tempJar.writeBytes(zipIn.getInputStream(entry).readBytes()) + ByteArrayOutputStream().use { bo -> + ZipOutputStream(bo).use { zos -> + relocate(zos, ZipFile(tempJar), repackPrefix, entriesSet) + zos.flush() + } + bo.flush() + zipOut.write(bo.toByteArray()) } - bo.flush() - zipOut.write(bo.toByteArray()) - } - if (tempJar.exists()) { - tempJar.delete() + if (tempJar.exists()) { + tempJar.delete() + } + } else if (entry.name.contains("/") && entry.name.startsWith("META-INF/services/")) { + val bufferedReader = BufferedReader(InputStreamReader(zipIn.getInputStream(entry))) + zipOut.write( + repackPrefix.replace( + '/', + '.' + ).toByteArray(Charsets.UTF_8) + ) + zipOut.write(bufferedReader.readLine().toByteArray(Charsets.UTF_8)) + } else { + zipIn.getInputStream(entry).copyTo(zipOut) } - } else { - zipIn.getInputStream(entry).copyTo(zipOut) } zipOut.closeEntry() } From 3cc7742d9fedb5c2771c9188310dc3ad012a3015 Mon Sep 17 00:00:00 2001 From: TomXin <766781886@qq.com> Date: Thu, 24 Oct 2024 18:42:51 +0800 Subject: [PATCH 4/8] Remove redundant content --- recaf-relocation/build.gradle.kts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/recaf-relocation/build.gradle.kts b/recaf-relocation/build.gradle.kts index 18630a079..7f5e2c14b 100644 --- a/recaf-relocation/build.gradle.kts +++ b/recaf-relocation/build.gradle.kts @@ -10,16 +10,9 @@ import java.util.zip.ZipFile import java.util.zip.ZipOutputStream buildscript { - repositories { - mavenCentral() - maven { - url = uri("https://plugins.gradle.org/m2/") - } - } dependencies { classpath(libs.bundles.asm) } - } plugins { From 8e8f7784a8847919c7b2c909e77e93a94908b9ce Mon Sep 17 00:00:00 2001 From: TomXin <766781886@qq.com> Date: Fri, 25 Oct 2024 00:03:24 +0800 Subject: [PATCH 5/8] Add fernflower and forgeflower --- build.gradle | 2 ++ gradle/libs.versions.toml | 6 ++++++ recaf-relocation/build.gradle.kts | 26 ++++++++++++++++++++++---- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index af978ba29..e81b4f682 100644 --- a/build.gradle +++ b/build.gradle @@ -21,6 +21,8 @@ subprojects { google() maven { url 'https://maven.quiltmc.org/repository/release/' } maven { url 'https://jitpack.io' } + maven { url 'https://www.jetbrains.com/intellij-repository/releases' } + maven { url 'https://maven.minecraftforge.net' } } // ======================= DEPENDENCIES ======================== diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b2b6f849a..b5ec7962d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -37,6 +37,8 @@ regex = "0.1.16" richtextfx = "0.11.3" treemapfx = "1.1.0" vineflower = "1.10.1" +fernflower = "242.23726.103" +forgeflower = "2.0.674.2" wordwrap = "0.1.12" benmanes-versions = "0.42.0" gradle-coverage-report-aggregator = "1.3.0" @@ -128,6 +130,10 @@ treemapfx = { module = "software.coley:treemap-fx", version.ref = "treemapfx" } vineflower = { module = "org.vineflower:vineflower", version.ref = "vineflower" } +fernflower = { module = "com.jetbrains.intellij.java:java-decompiler-engine", version.ref = "fernflower" } + +forgeflower = { module = "net.minecraftforge:forgeflower", version.ref = "forgeflower" } + wordwrap = { module = "com.github.davidmoten:word-wrap", version.ref = "wordwrap" } [bundles] diff --git a/recaf-relocation/build.gradle.kts b/recaf-relocation/build.gradle.kts index 7f5e2c14b..5c3868537 100644 --- a/recaf-relocation/build.gradle.kts +++ b/recaf-relocation/build.gradle.kts @@ -22,16 +22,28 @@ plugins { val artifactTypeAttribute = Attribute.of("artifactType", String::class.java) val repackagedAttribute = Attribute.of("repackaged", Boolean::class.javaObjectType) + val repackage: Configuration by configurations.creating { attributes.attribute(repackagedAttribute, true) } // Configure project's dependencies -abstract class MyRepackager : TransformAction { +abstract class MyAbsRepackager : TransformAction { + @InputArtifact abstract fun getInputArtifact(): Provider + override fun transform(outputs: TransformOutputs) { val input = getInputArtifact().get().asFile + val repackPrefix = if (input.name.contains(Regex("vineflower"))) { + "recaf/relocation/libs/vineflower/" + } else if (input.name.contains(Regex("java-decompiler-engine"))) { + "recaf/relocation/libs/fernflower/" + } else if (input.name.contains(Regex("forgeflower"))) { + "recaf/relocation/libs/forgeflower/" + } else { + "" + } val output = outputs.file( input.name.let { if (it.endsWith(".jar")) @@ -42,11 +54,12 @@ abstract class MyRepackager : TransformAction { ) println("Repackaging ${input.absolutePath} to ${output.absolutePath}") ZipOutputStream(output.outputStream()).use { zipOut -> - relocate(zipOut, ZipFile(input), "recaf/relocation/libs/vineflower/", null) + relocate(zipOut, ZipFile(input), repackPrefix, null) zipOut.flush() } } + fun relocate( zipOut: ZipOutputStream, zipFile: ZipFile, @@ -133,18 +146,23 @@ abstract class MyRepackager : TransformAction { } + dependencies { attributesSchema { attribute(repackagedAttribute) + // attribute(f_repackagedAttribute) } artifactTypes.getByName("jar") { attributes.attribute(repackagedAttribute, false) + // attributes.attribute(f_repackagedAttribute, false) } - registerTransform(MyRepackager::class) { + registerTransform(MyAbsRepackager::class) { from.attribute(repackagedAttribute, false).attribute(artifactTypeAttribute, "jar") to.attribute(repackagedAttribute, true).attribute(artifactTypeAttribute, "jar") } - repackage(libs.vineflower) + repackage(libs.fernflower) + repackage(libs.forgeflower) + api(files(repackage.files)) } \ No newline at end of file From 66271569f0041ab044a704e336dd44ecf8520702 Mon Sep 17 00:00:00 2001 From: TomXin <766781886@qq.com> Date: Mon, 28 Oct 2024 16:40:10 +0800 Subject: [PATCH 6/8] Added Fernflower rough support --- gradle/libs.versions.toml | 3 + .../decompile/fernflower/FakeFile.java | 29 ++++++ .../fernflower/FernflowerConfig.java | 26 +++++ .../fernflower/FernflowerDecompiler.java | 94 +++++++++++++++++++ .../fernflower/FernflowerLogger.java | 44 +++++++++ .../fernflower/MyBytecodeProvider.java | 29 ++++++ .../decompile/fernflower/MyResultSaver.java | 75 +++++++++++++++ recaf-relocation/build.gradle.kts | 5 +- 8 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FakeFile.java create mode 100644 recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FernflowerConfig.java create mode 100644 recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FernflowerDecompiler.java create mode 100644 recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FernflowerLogger.java create mode 100644 recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/MyBytecodeProvider.java create mode 100644 recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/MyResultSaver.java diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c6d36588f..fdea135fc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,6 +39,7 @@ treemapfx = "1.1.0" vineflower = "1.10.1" fernflower = "242.23726.103" forgeflower = "2.0.674.2" +annotations = "24.0.0" wordwrap = "0.1.12" benmanes-versions = "0.42.0" gradle-coverage-report-aggregator = "1.3.0" @@ -134,6 +135,8 @@ fernflower = { module = "com.jetbrains.intellij.java:java-decompiler-engine", ve forgeflower = { module = "net.minecraftforge:forgeflower", version.ref = "forgeflower" } +annotations = { module = "org.jetbrains:annotations", version.ref = "annotations" } + wordwrap = { module = "com.github.davidmoten:word-wrap", version.ref = "wordwrap" } [bundles] diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FakeFile.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FakeFile.java new file mode 100644 index 000000000..66aafe23e --- /dev/null +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FakeFile.java @@ -0,0 +1,29 @@ +package software.coley.recaf.services.decompile.fernflower; + +import java.io.File; + +/** + * FakeFile + * + * @author meiMingle + */ +public class FakeFile extends File { + + String absolutePath; + + + public FakeFile(String path) { + super(path); + this.absolutePath = path; + } + + @Override + public boolean isDirectory() { + return false; + } + + @Override + public String getAbsolutePath() { + return absolutePath; + } +} diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FernflowerConfig.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FernflowerConfig.java new file mode 100644 index 000000000..607d6b5a2 --- /dev/null +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FernflowerConfig.java @@ -0,0 +1,26 @@ +package software.coley.recaf.services.decompile.fernflower; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import org.slf4j.event.Level; +import software.coley.observables.ObservableObject; +import software.coley.recaf.services.decompile.BaseDecompilerConfig; + +/** + * FernflowerConfig + * + * @author meiMingle + */ +@ApplicationScoped +public class FernflowerConfig extends BaseDecompilerConfig { + + @Inject + public FernflowerConfig() { + super("decompiler-fernflower" + CONFIG_SUFFIX); + registerConfigValuesHashUpdates(); + } + + public ObservableObject getLoggingLevel() { + return new ObservableObject<>(Level.WARN); + } +} diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FernflowerDecompiler.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FernflowerDecompiler.java new file mode 100644 index 000000000..288ac1f2f --- /dev/null +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FernflowerDecompiler.java @@ -0,0 +1,94 @@ +package software.coley.recaf.services.decompile.fernflower; + +import jakarta.annotation.Nonnull; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import recaf.relocation.libs.fernflower.org.jetbrains.java.decompiler.main.decompiler.BaseDecompiler; +import recaf.relocation.libs.fernflower.org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; +import software.coley.recaf.info.InnerClassInfo; +import software.coley.recaf.info.JvmClassInfo; +import software.coley.recaf.services.decompile.AbstractJvmDecompiler; +import software.coley.recaf.services.decompile.DecompileResult; +import software.coley.recaf.workspace.model.Workspace; +import software.coley.recaf.workspace.model.resource.BasicWorkspaceFileResource; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Fernflower decompiler implementation. + * + * @author meiMingle + */ +@ApplicationScoped +public class FernflowerDecompiler extends AbstractJvmDecompiler { + public static final String NAME = "Fernflower"; + private final FernflowerConfig config; + private final IFernflowerLogger logger; + // private final IResultSaver dummySaver = new DummyResultSaver(); + + /** + * New Fernflower decompiler instance. + * + * @param config Decompiler configuration. + */ + @Inject + public FernflowerDecompiler(@Nonnull FernflowerConfig config) { + // Change this version to be dynamic when / if the Fernflower authors make a function that returns the version... + super(NAME, "242.23726.103", config); + this.config = config; + logger = new FernflowerLogger(config); + } + + @Nonnull + @Override + public DecompileResult decompileInternal(@Nonnull Workspace workspace, @Nonnull JvmClassInfo info) { + + + Map options = new HashMap<>(); + + options.put("hdc", "0"); + options.put("dgs", "1"); + options.put("rsy", "1"); + options.put("rbr", "1"); + options.put("nls", "1"); + options.put("ban", "//Recreated by Recaf (powered by FernFlower decompiler)\n\n"); + options.put("mpm", 60); + options.put("ind", " "); + options.put("iib", "1"); + options.put("vac", "1"); + options.put("cps", "1"); + options.put("crp", "1"); + + options.put("bsm", "1");// "decompiler.use.line.mapping" + options.put("__dump_original_lines__", "1");// "decompiler.dump.original.lines" + + MyResultSaver saver = new MyResultSaver(); + MyBytecodeProvider provider = new MyBytecodeProvider(workspace); + + BaseDecompiler decompiler = new BaseDecompiler( + provider, + saver, + options, + logger + ); + + try { + String path = ((BasicWorkspaceFileResource) workspace.getPrimaryResource()).getFileInfo().getName() + "!" + info.getName() + ".class"; + decompiler.addSource(new FakeFile(path)); + List innerClasses = info.getInnerClasses(); + innerClasses.forEach(inner -> decompiler.addSource(new FakeFile(((BasicWorkspaceFileResource) workspace.getPrimaryResource()).getFileInfo().getName() + "!" + inner.getName() + ".class"))); + decompiler.decompileContext(); + if (saver.getResult() == null || saver.getResult().isEmpty()) { + return new DecompileResult(new IllegalStateException("Missing decompilation output"), 0); + } + + return new DecompileResult(saver.getResult(), 0); + } catch (Exception e) { + return new DecompileResult(e, 0); + } + } + + +} diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FernflowerLogger.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FernflowerLogger.java new file mode 100644 index 000000000..52ee02782 --- /dev/null +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FernflowerLogger.java @@ -0,0 +1,44 @@ +package software.coley.recaf.services.decompile.fernflower; + +import jakarta.annotation.Nonnull; +import org.slf4j.Logger; +import org.slf4j.event.Level; +import recaf.relocation.libs.fernflower.org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; +import software.coley.observables.ObservableObject; +import software.coley.recaf.analytics.logging.Logging; + +/** + * Logger for Fernflower + * + * @author meiMingle + */ +public class FernflowerLogger extends IFernflowerLogger { + private static final Logger logger = Logging.get(FernflowerLogger.class); + private static final String VF_PREFIX = "VF: "; + private final ObservableObject level; + + public FernflowerLogger(@Nonnull FernflowerConfig config) { + this.level = config.getLoggingLevel(); + } + + @Override + public void writeMessage(String message, Severity severity) { + switch (severity) { + case TRACE -> { + if (level.getValue().compareTo(Level.TRACE) >= 0) logger.trace(VF_PREFIX + message); + } + case INFO -> { + if (level.getValue().compareTo(Level.INFO) >= 0) logger.info(VF_PREFIX + message); + } + case WARN -> { + if (level.getValue().compareTo(Level.WARN) >= 0) logger.warn(VF_PREFIX + message); + } + case ERROR -> logger.error(VF_PREFIX + message); + } + } + + @Override + public void writeMessage(String message, Severity severity, Throwable throwable) { + logger.error(VF_PREFIX + message, throwable); + } +} diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/MyBytecodeProvider.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/MyBytecodeProvider.java new file mode 100644 index 000000000..0c5a87f06 --- /dev/null +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/MyBytecodeProvider.java @@ -0,0 +1,29 @@ +package software.coley.recaf.services.decompile.fernflower; + +import recaf.relocation.libs.fernflower.org.jetbrains.java.decompiler.main.extern.IBytecodeProvider; +import software.coley.recaf.path.ClassPathNode; +import software.coley.recaf.workspace.model.Workspace; + + +/** + * MyBytecodeProvider + * + * @author meiMingle + */ +public class MyBytecodeProvider implements IBytecodeProvider { + Workspace workspace; + + public MyBytecodeProvider(Workspace workspace) { + this.workspace = workspace; + } + + @Override + public byte[] getBytecode(String absolutePath, String internalPath) { + String[] split = absolutePath.split("!"); + String path = split[0]; + String name = split[1]; + + ClassPathNode aClass = workspace.findClass(name.substring(0, name.lastIndexOf('.'))); + return aClass.getValue().asJvmClass().getBytecode(); + } +} \ No newline at end of file diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/MyResultSaver.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/MyResultSaver.java new file mode 100644 index 000000000..9dc2a238d --- /dev/null +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/MyResultSaver.java @@ -0,0 +1,75 @@ +package software.coley.recaf.services.decompile.fernflower; + + +import recaf.relocation.libs.fernflower.org.jetbrains.java.decompiler.main.extern.IResultSaver; + +import java.util.jar.Manifest; + +/** + * MyResultSaver + * + * @author meiMingle + */ +public class MyResultSaver implements IResultSaver { + private String result = ""; + private int[] mapping; + + public final String getResult() { + return this.result; + } + + public final void setResult(String string) { + this.result = string; + } + + public final int[] getMapping() { + return this.mapping; + } + + public final void setMapping(int[] nArray) { + this.mapping = nArray; + } + + @Override + public void saveClassFile(String path, String qualifiedName, String entryName, String content, int[] mapping) { + if (((CharSequence) this.result).length() == 0) { + this.result = content; + this.mapping = mapping; + } + } + + @Override + public void saveFolder(String path) { + // no-op + } + + @Override + public void copyFile(String source, String path, String entryName) { + // no-op + } + + @Override + public void createArchive(String path, String archiveName, Manifest manifest) { + // no-op + } + + @Override + public void saveDirEntry(String s, String s1, String s2) { + // no-op + } + + @Override + public void copyEntry(String s, String s1, String s2, String s3) { + // no-op + } + + @Override + public void saveClassEntry(String s, String s1, String s2, String s3, String s4) { + // no-op + } + + @Override + public void closeArchive(String s, String s1) { + // no-op + } +} \ No newline at end of file diff --git a/recaf-relocation/build.gradle.kts b/recaf-relocation/build.gradle.kts index 5c3868537..099bc9299 100644 --- a/recaf-relocation/build.gradle.kts +++ b/recaf-relocation/build.gradle.kts @@ -152,17 +152,20 @@ dependencies { attribute(repackagedAttribute) // attribute(f_repackagedAttribute) } + artifactTypes.getByName("jar") { attributes.attribute(repackagedAttribute, false) // attributes.attribute(f_repackagedAttribute, false) } + registerTransform(MyAbsRepackager::class) { from.attribute(repackagedAttribute, false).attribute(artifactTypeAttribute, "jar") to.attribute(repackagedAttribute, true).attribute(artifactTypeAttribute, "jar") } + repackage(libs.vineflower) repackage(libs.fernflower) repackage(libs.forgeflower) - + api(libs.annotations) api(files(repackage.files)) } \ No newline at end of file From 0f8d4ea9f2aa48aabb2e24c66d5b017ec150cb79 Mon Sep 17 00:00:00 2001 From: TomXin <766781886@qq.com> Date: Mon, 28 Oct 2024 17:10:05 +0800 Subject: [PATCH 7/8] Added Forgeflower rough support --- .../decompile/{fernflower => }/FakeFile.java | 2 +- .../fernflower/FernflowerDecompiler.java | 2 +- .../fernflower/FernflowerLogger.java | 2 +- .../forgeflower/ForgeflowerConfig.java | 26 +++++ .../forgeflower/ForgeflowerDecompiler.java | 94 +++++++++++++++++++ .../forgeflower/ForgeflowerLogger.java | 44 +++++++++ .../forgeflower/MyBytecodeProvider.java | 29 ++++++ .../decompile/forgeflower/MyResultSaver.java | 75 +++++++++++++++ 8 files changed, 271 insertions(+), 3 deletions(-) rename recaf-core/src/main/java/software/coley/recaf/services/decompile/{fernflower => }/FakeFile.java (86%) create mode 100644 recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/ForgeflowerConfig.java create mode 100644 recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/ForgeflowerDecompiler.java create mode 100644 recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/ForgeflowerLogger.java create mode 100644 recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/MyBytecodeProvider.java create mode 100644 recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/MyResultSaver.java diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FakeFile.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/FakeFile.java similarity index 86% rename from recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FakeFile.java rename to recaf-core/src/main/java/software/coley/recaf/services/decompile/FakeFile.java index 66aafe23e..9d7a3c0b8 100644 --- a/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FakeFile.java +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/FakeFile.java @@ -1,4 +1,4 @@ -package software.coley.recaf.services.decompile.fernflower; +package software.coley.recaf.services.decompile; import java.io.File; diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FernflowerDecompiler.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FernflowerDecompiler.java index 288ac1f2f..894b5df85 100644 --- a/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FernflowerDecompiler.java +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FernflowerDecompiler.java @@ -9,6 +9,7 @@ import software.coley.recaf.info.JvmClassInfo; import software.coley.recaf.services.decompile.AbstractJvmDecompiler; import software.coley.recaf.services.decompile.DecompileResult; +import software.coley.recaf.services.decompile.FakeFile; import software.coley.recaf.workspace.model.Workspace; import software.coley.recaf.workspace.model.resource.BasicWorkspaceFileResource; @@ -26,7 +27,6 @@ public class FernflowerDecompiler extends AbstractJvmDecompiler { public static final String NAME = "Fernflower"; private final FernflowerConfig config; private final IFernflowerLogger logger; - // private final IResultSaver dummySaver = new DummyResultSaver(); /** * New Fernflower decompiler instance. diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FernflowerLogger.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FernflowerLogger.java index 52ee02782..9bfcb6c35 100644 --- a/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FernflowerLogger.java +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/fernflower/FernflowerLogger.java @@ -14,7 +14,7 @@ */ public class FernflowerLogger extends IFernflowerLogger { private static final Logger logger = Logging.get(FernflowerLogger.class); - private static final String VF_PREFIX = "VF: "; + private static final String VF_PREFIX = "FF: "; private final ObservableObject level; public FernflowerLogger(@Nonnull FernflowerConfig config) { diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/ForgeflowerConfig.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/ForgeflowerConfig.java new file mode 100644 index 000000000..57a651915 --- /dev/null +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/ForgeflowerConfig.java @@ -0,0 +1,26 @@ +package software.coley.recaf.services.decompile.forgeflower; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import org.slf4j.event.Level; +import software.coley.observables.ObservableObject; +import software.coley.recaf.services.decompile.BaseDecompilerConfig; + +/** + * ForgeflowerConfig + * + * @author meiMingle + */ +@ApplicationScoped +public class ForgeflowerConfig extends BaseDecompilerConfig { + + @Inject + public ForgeflowerConfig() { + super("decompiler-forgeflower" + CONFIG_SUFFIX); + registerConfigValuesHashUpdates(); + } + + public ObservableObject getLoggingLevel() { + return new ObservableObject<>(Level.WARN); + } +} diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/ForgeflowerDecompiler.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/ForgeflowerDecompiler.java new file mode 100644 index 000000000..fda3a2924 --- /dev/null +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/ForgeflowerDecompiler.java @@ -0,0 +1,94 @@ +package software.coley.recaf.services.decompile.forgeflower; + +import jakarta.annotation.Nonnull; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import recaf.relocation.libs.forgeflower.org.jetbrains.java.decompiler.main.decompiler.BaseDecompiler; +import recaf.relocation.libs.forgeflower.org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; +import software.coley.recaf.info.InnerClassInfo; +import software.coley.recaf.info.JvmClassInfo; +import software.coley.recaf.services.decompile.AbstractJvmDecompiler; +import software.coley.recaf.services.decompile.DecompileResult; +import software.coley.recaf.services.decompile.FakeFile; +import software.coley.recaf.workspace.model.Workspace; +import software.coley.recaf.workspace.model.resource.BasicWorkspaceFileResource; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Forgeflower decompiler implementation. + * + * @author meiMingle + */ +@ApplicationScoped +public class ForgeflowerDecompiler extends AbstractJvmDecompiler { + public static final String NAME = "Forgeflower"; + private final ForgeflowerConfig config; + private final IFernflowerLogger logger; + + /** + * New Fernflower decompiler instance. + * + * @param config Decompiler configuration. + */ + @Inject + public ForgeflowerDecompiler(@Nonnull ForgeflowerConfig config) { + // Change this version to be dynamic when / if the Fernflower authors make a function that returns the version... + super(NAME, "2.0.674.2", config); + this.config = config; + logger = new ForgeflowerLogger(config); + } + + @Nonnull + @Override + public DecompileResult decompileInternal(@Nonnull Workspace workspace, @Nonnull JvmClassInfo info) { + + + Map options = new HashMap<>(); + + options.put("hdc", "0"); + options.put("dgs", "1"); + options.put("rsy", "1"); + options.put("rbr", "1"); + options.put("nls", "1"); + options.put("ban", List.of("//Recreated by Recaf (powered by ForgeFlower decompiler)\n\n")); + options.put("mpm", 60); + options.put("ind", " "); + options.put("iib", "1"); + options.put("vac", "1"); + options.put("cps", "1"); + options.put("crp", "1"); + + options.put("bsm", "1");// "decompiler.use.line.mapping" + options.put("__dump_original_lines__", "1");// "decompiler.dump.original.lines" + + MyResultSaver saver = new MyResultSaver(); + MyBytecodeProvider provider = new MyBytecodeProvider(workspace); + + BaseDecompiler decompiler = new BaseDecompiler( + provider, + saver, + options, + logger + ); + + try { + String path = ((BasicWorkspaceFileResource) workspace.getPrimaryResource()).getFileInfo().getName() + "!" + info.getName() + ".class"; + decompiler.addSource(new FakeFile(path)); + List innerClasses = info.getInnerClasses(); + innerClasses.forEach(inner -> decompiler.addSource(new FakeFile(((BasicWorkspaceFileResource) workspace.getPrimaryResource()).getFileInfo().getName() + "!" + inner.getName() + ".class"))); + decompiler.decompileContext(); + if (saver.getResult() == null || saver.getResult().isEmpty()) { + return new DecompileResult(new IllegalStateException("Missing decompilation output"), 0); + } + + return new DecompileResult(saver.getResult(), 0); + } catch (Exception e) { + return new DecompileResult(e, 0); + } + } + + +} diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/ForgeflowerLogger.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/ForgeflowerLogger.java new file mode 100644 index 000000000..8cd158ec0 --- /dev/null +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/ForgeflowerLogger.java @@ -0,0 +1,44 @@ +package software.coley.recaf.services.decompile.forgeflower; + +import jakarta.annotation.Nonnull; +import org.slf4j.Logger; +import org.slf4j.event.Level; +import recaf.relocation.libs.forgeflower.org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; +import software.coley.observables.ObservableObject; +import software.coley.recaf.analytics.logging.Logging; + +/** + * Logger for Forgeflower + * + * @author meiMingle + */ +public class ForgeflowerLogger extends IFernflowerLogger { + private static final Logger logger = Logging.get(ForgeflowerLogger.class); + private static final String VF_PREFIX = "FgF: "; + private final ObservableObject level; + + public ForgeflowerLogger(@Nonnull ForgeflowerConfig config) { + this.level = config.getLoggingLevel(); + } + + @Override + public void writeMessage(String message, Severity severity) { + switch (severity) { + case TRACE -> { + if (level.getValue().compareTo(Level.TRACE) >= 0) logger.trace(VF_PREFIX + message); + } + case INFO -> { + if (level.getValue().compareTo(Level.INFO) >= 0) logger.info(VF_PREFIX + message); + } + case WARN -> { + if (level.getValue().compareTo(Level.WARN) >= 0) logger.warn(VF_PREFIX + message); + } + case ERROR -> logger.error(VF_PREFIX + message); + } + } + + @Override + public void writeMessage(String message, Severity severity, Throwable throwable) { + logger.error(VF_PREFIX + message, throwable); + } +} diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/MyBytecodeProvider.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/MyBytecodeProvider.java new file mode 100644 index 000000000..633c7d0c8 --- /dev/null +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/MyBytecodeProvider.java @@ -0,0 +1,29 @@ +package software.coley.recaf.services.decompile.forgeflower; + +import recaf.relocation.libs.forgeflower.org.jetbrains.java.decompiler.main.extern.IBytecodeProvider; +import software.coley.recaf.path.ClassPathNode; +import software.coley.recaf.workspace.model.Workspace; + + +/** + * MyBytecodeProvider + * + * @author meiMingle + */ +public class MyBytecodeProvider implements IBytecodeProvider { + Workspace workspace; + + public MyBytecodeProvider(Workspace workspace) { + this.workspace = workspace; + } + + @Override + public byte[] getBytecode(String absolutePath, String internalPath) { + String[] split = absolutePath.split("!"); + String path = split[0]; + String name = split[1]; + + ClassPathNode aClass = workspace.findClass(name.substring(0, name.lastIndexOf('.'))); + return aClass.getValue().asJvmClass().getBytecode(); + } +} \ No newline at end of file diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/MyResultSaver.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/MyResultSaver.java new file mode 100644 index 000000000..020174fce --- /dev/null +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/MyResultSaver.java @@ -0,0 +1,75 @@ +package software.coley.recaf.services.decompile.forgeflower; + + +import recaf.relocation.libs.forgeflower.org.jetbrains.java.decompiler.main.extern.IResultSaver; + +import java.util.jar.Manifest; + +/** + * MyResultSaver + * + * @author meiMingle + */ +public class MyResultSaver implements IResultSaver { + private String result = ""; + private int[] mapping; + + public final String getResult() { + return this.result; + } + + public final void setResult(String string) { + this.result = string; + } + + public final int[] getMapping() { + return this.mapping; + } + + public final void setMapping(int[] nArray) { + this.mapping = nArray; + } + + @Override + public void saveClassFile(String path, String qualifiedName, String entryName, String content, int[] mapping) { + if (((CharSequence) this.result).length() == 0) { + this.result = content; + this.mapping = mapping; + } + } + + @Override + public void saveFolder(String path) { + // no-op + } + + @Override + public void copyFile(String source, String path, String entryName) { + // no-op + } + + @Override + public void createArchive(String path, String archiveName, Manifest manifest) { + // no-op + } + + @Override + public void saveDirEntry(String s, String s1, String s2) { + // no-op + } + + @Override + public void copyEntry(String s, String s1, String s2, String s3) { + // no-op + } + + @Override + public void saveClassEntry(String s, String s1, String s2, String s3, String s4) { + // no-op + } + + @Override + public void closeArchive(String s, String s1) { + // no-op + } +} \ No newline at end of file From aad7bd0dfc00ae7b645ecd6d39bcf0250a1caa58 Mon Sep 17 00:00:00 2001 From: TomXin <766781886@qq.com> Date: Mon, 28 Oct 2024 17:17:37 +0800 Subject: [PATCH 8/8] Add banner for Vineflower decompiler output --- .../decompile/forgeflower/ForgeflowerDecompiler.java | 2 +- .../services/decompile/vineflower/VineflowerDecompiler.java | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/ForgeflowerDecompiler.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/ForgeflowerDecompiler.java index fda3a2924..93f4e0f0f 100644 --- a/recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/ForgeflowerDecompiler.java +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/forgeflower/ForgeflowerDecompiler.java @@ -53,7 +53,7 @@ public DecompileResult decompileInternal(@Nonnull Workspace workspace, @Nonnull options.put("rsy", "1"); options.put("rbr", "1"); options.put("nls", "1"); - options.put("ban", List.of("//Recreated by Recaf (powered by ForgeFlower decompiler)\n\n")); + options.put("ban", List.of("//Recreated by Recaf (powered by ForgeFlower decompiler)\n")); options.put("mpm", 60); options.put("ind", " "); options.put("iib", "1"); diff --git a/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/VineflowerDecompiler.java b/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/VineflowerDecompiler.java index d1b31b796..aaf92e3b7 100644 --- a/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/VineflowerDecompiler.java +++ b/recaf-core/src/main/java/software/coley/recaf/services/decompile/vineflower/VineflowerDecompiler.java @@ -11,6 +11,8 @@ import software.coley.recaf.services.decompile.DecompileResult; import software.coley.recaf.workspace.model.Workspace; +import java.util.Map; + /** * Vineflower decompiler implementation. * @@ -40,7 +42,9 @@ public VineflowerDecompiler(@Nonnull VineflowerConfig config) { @Nonnull @Override public DecompileResult decompileInternal(@Nonnull Workspace workspace, @Nonnull JvmClassInfo info) { - Fernflower fernflower = new Fernflower(dummySaver, config.getFernflowerProperties(), logger); + Map customProperties = this.config.getFernflowerProperties(); + customProperties.put("banner", "//Recreated by Recaf (powered by VineFlower decompiler)\n\n"); + Fernflower fernflower = new Fernflower(dummySaver, customProperties, logger); try { ClassSource source = new ClassSource(workspace, info);