diff options
| author | 2025-09-10 20:26:11 +0100 | |
|---|---|---|
| committer | 2025-09-13 09:14:23 +0100 | |
| commit | 79ab43c66f9b40d9f6780f14b8d423a489e77c5c (patch) | |
| tree | 73b1ef41b099ea468703898ea74131d5b2713d5a | |
| parent | Add more utility methods (diff) | |
| download | enigma-79ab43c66f9b40d9f6780f14b8d423a489e77c5c.tar.gz enigma-79ab43c66f9b40d9f6780f14b8d423a489e77c5c.tar.xz enigma-79ab43c66f9b40d9f6780f14b8d423a489e77c5c.zip | |
Add a way to transform the decompiler input
6 files changed, 74 insertions, 7 deletions
diff --git a/enigma-cli/src/main/java/cuchaz/enigma/command/DecompileCommand.java b/enigma-cli/src/main/java/cuchaz/enigma/command/DecompileCommand.java index 020bd979..baed29a6 100644 --- a/enigma-cli/src/main/java/cuchaz/enigma/command/DecompileCommand.java +++ b/enigma-cli/src/main/java/cuchaz/enigma/command/DecompileCommand.java | |||
| @@ -47,7 +47,7 @@ public class DecompileCommand extends Command { | |||
| 47 | ProgressListener progress = new ConsoleProgressListener(); | 47 | ProgressListener progress = new ConsoleProgressListener(); |
| 48 | 48 | ||
| 49 | EnigmaProject.JarExport jar = project.exportRemappedJar(progress); | 49 | EnigmaProject.JarExport jar = project.exportRemappedJar(progress); |
| 50 | EnigmaProject.SourceExport source = jar.decompile(progress, decompilerService, DecompileErrorStrategy.TRACE_AS_SOURCE); | 50 | EnigmaProject.SourceExport source = jar.decompile(project, progress, decompilerService, DecompileErrorStrategy.TRACE_AS_SOURCE); |
| 51 | 51 | ||
| 52 | source.write(fileJarOut, progress); | 52 | source.write(fileJarOut, progress); |
| 53 | } | 53 | } |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java index 1c4549d6..7691f39c 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/GuiController.java | |||
| @@ -311,7 +311,7 @@ public class GuiController implements ClientPacketHandler, GuiView, DataInvalida | |||
| 311 | 311 | ||
| 312 | return ProgressDialog.runOffThread(this.gui.getFrame(), progress -> { | 312 | return ProgressDialog.runOffThread(this.gui.getFrame(), progress -> { |
| 313 | EnigmaProject.JarExport jar = project.exportRemappedJar(progress); | 313 | EnigmaProject.JarExport jar = project.exportRemappedJar(progress); |
| 314 | jar.decompileStream(progress, chp.getDecompilerService(), EnigmaProject.DecompileErrorStrategy.TRACE_AS_SOURCE).forEach(source -> { | 314 | jar.decompileStream(project, progress, chp.getDecompilerService(), EnigmaProject.DecompileErrorStrategy.TRACE_AS_SOURCE).forEach(source -> { |
| 315 | try { | 315 | try { |
| 316 | source.writeTo(source.resolvePath(path)); | 316 | source.writeTo(source.resolvePath(path)); |
| 317 | } catch (IOException e) { | 317 | } catch (IOException e) { |
diff --git a/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java b/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java index 3f4a0673..4a528a7b 100644 --- a/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java +++ b/enigma/src/main/java/cuchaz/enigma/EnigmaProject.java | |||
| @@ -27,6 +27,7 @@ import cuchaz.enigma.analysis.EntryReference; | |||
| 27 | import cuchaz.enigma.analysis.index.JarIndex; | 27 | import cuchaz.enigma.analysis.index.JarIndex; |
| 28 | import cuchaz.enigma.api.DataInvalidationEvent; | 28 | import cuchaz.enigma.api.DataInvalidationEvent; |
| 29 | import cuchaz.enigma.api.DataInvalidationListener; | 29 | import cuchaz.enigma.api.DataInvalidationListener; |
| 30 | import cuchaz.enigma.api.service.DecompilerInputTransformerService; | ||
| 30 | import cuchaz.enigma.api.service.NameProposalService; | 31 | import cuchaz.enigma.api.service.NameProposalService; |
| 31 | import cuchaz.enigma.api.service.ObfuscationTestService; | 32 | import cuchaz.enigma.api.service.ObfuscationTestService; |
| 32 | import cuchaz.enigma.api.view.ProjectView; | 33 | import cuchaz.enigma.api.view.ProjectView; |
| @@ -277,13 +278,20 @@ public class EnigmaProject implements ProjectView { | |||
| 277 | } | 278 | } |
| 278 | } | 279 | } |
| 279 | 280 | ||
| 280 | public SourceExport decompile(ProgressListener progress, DecompilerService decompilerService, DecompileErrorStrategy errorStrategy) { | 281 | public SourceExport decompile(EnigmaProject project, ProgressListener progress, DecompilerService decompilerService, DecompileErrorStrategy errorStrategy) { |
| 281 | List<ClassSource> decompiled = this.decompileStream(progress, decompilerService, errorStrategy).toList(); | 282 | List<ClassSource> decompiled = this.decompileStream(project, progress, decompilerService, errorStrategy).toList(); |
| 282 | return new SourceExport(decompiled); | 283 | return new SourceExport(decompiled); |
| 283 | } | 284 | } |
| 284 | 285 | ||
| 285 | public Stream<ClassSource> decompileStream(ProgressListener progress, DecompilerService decompilerService, DecompileErrorStrategy errorStrategy) { | 286 | public Stream<ClassSource> decompileStream(EnigmaProject project, ProgressListener progress, DecompilerService decompilerService, DecompileErrorStrategy errorStrategy) { |
| 286 | Collection<ClassNode> classes = this.compiled.values().stream().filter(classNode -> classNode.name.indexOf('$') == -1).toList(); | 287 | Collection<ClassNode> classes = this.compiled.values().stream() |
| 288 | .filter(classNode -> classNode.name.indexOf('$') == -1) | ||
| 289 | .peek(classNode -> { | ||
| 290 | for (DecompilerInputTransformerService transformer : project.enigma.getServices().get(DecompilerInputTransformerService.TYPE)) { | ||
| 291 | transformer.transform(classNode); | ||
| 292 | } | ||
| 293 | }) | ||
| 294 | .toList(); | ||
| 287 | 295 | ||
| 288 | progress.init(classes.size(), I18n.translate("progress.classes.decompiling")); | 296 | progress.init(classes.size(), I18n.translate("progress.classes.decompiling")); |
| 289 | 297 | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/api/service/DecompilerInputTransformerService.java b/enigma/src/main/java/cuchaz/enigma/api/service/DecompilerInputTransformerService.java new file mode 100644 index 00000000..a560515a --- /dev/null +++ b/enigma/src/main/java/cuchaz/enigma/api/service/DecompilerInputTransformerService.java | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | package cuchaz.enigma.api.service; | ||
| 2 | |||
| 3 | import org.objectweb.asm.tree.ClassNode; | ||
| 4 | |||
| 5 | public interface DecompilerInputTransformerService extends EnigmaService { | ||
| 6 | EnigmaServiceType<DecompilerInputTransformerService> TYPE = EnigmaServiceType.create("decompiler_input_transformer"); | ||
| 7 | |||
| 8 | void transform(ClassNode classNode); | ||
| 9 | } | ||
diff --git a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java index cb80dda9..36c10cc1 100644 --- a/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java +++ b/enigma/src/main/java/cuchaz/enigma/classhandle/ClassHandleProvider.java | |||
| @@ -24,6 +24,7 @@ import org.jetbrains.annotations.Nullable; | |||
| 24 | 24 | ||
| 25 | import cuchaz.enigma.EnigmaProject; | 25 | import cuchaz.enigma.EnigmaProject; |
| 26 | import cuchaz.enigma.classprovider.CachingClassProvider; | 26 | import cuchaz.enigma.classprovider.CachingClassProvider; |
| 27 | import cuchaz.enigma.classprovider.DecompilerInputTransformingClassProvider; | ||
| 27 | import cuchaz.enigma.classprovider.ObfuscationFixClassProvider; | 28 | import cuchaz.enigma.classprovider.ObfuscationFixClassProvider; |
| 28 | import cuchaz.enigma.events.ClassHandleListener; | 29 | import cuchaz.enigma.events.ClassHandleListener; |
| 29 | import cuchaz.enigma.events.ClassHandleListener.InvalidationType; | 30 | import cuchaz.enigma.events.ClassHandleListener.InvalidationType; |
| @@ -104,7 +105,13 @@ public final class ClassHandleProvider { | |||
| 104 | } | 105 | } |
| 105 | 106 | ||
| 106 | private Decompiler createDecompiler() { | 107 | private Decompiler createDecompiler() { |
| 107 | return ds.create(new CachingClassProvider(new ObfuscationFixClassProvider(project.getClassProvider(), project.getJarIndex())), new SourceSettings(true, true)); | 108 | return ds.create( |
| 109 | new DecompilerInputTransformingClassProvider( | ||
| 110 | new CachingClassProvider(new ObfuscationFixClassProvider(project.getClassProvider(), project.getJarIndex())), | ||
| 111 | project.getEnigma().getServices() | ||
| 112 | ), | ||
| 113 | new SourceSettings(true, true) | ||
| 114 | ); | ||
| 108 | } | 115 | } |
| 109 | 116 | ||
| 110 | /** | 117 | /** |
diff --git a/enigma/src/main/java/cuchaz/enigma/classprovider/DecompilerInputTransformingClassProvider.java b/enigma/src/main/java/cuchaz/enigma/classprovider/DecompilerInputTransformingClassProvider.java new file mode 100644 index 00000000..960221dd --- /dev/null +++ b/enigma/src/main/java/cuchaz/enigma/classprovider/DecompilerInputTransformingClassProvider.java | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | package cuchaz.enigma.classprovider; | ||
| 2 | |||
| 3 | import java.util.Collection; | ||
| 4 | |||
| 5 | import org.jetbrains.annotations.Nullable; | ||
| 6 | import org.objectweb.asm.tree.ClassNode; | ||
| 7 | |||
| 8 | import cuchaz.enigma.EnigmaServices; | ||
| 9 | import cuchaz.enigma.api.service.DecompilerInputTransformerService; | ||
| 10 | |||
| 11 | public class DecompilerInputTransformingClassProvider implements ClassProvider { | ||
| 12 | private final ClassProvider delegate; | ||
| 13 | private final EnigmaServices services; | ||
| 14 | |||
| 15 | public DecompilerInputTransformingClassProvider(ClassProvider delegate, EnigmaServices services) { | ||
| 16 | this.delegate = delegate; | ||
| 17 | this.services = services; | ||
| 18 | } | ||
| 19 | |||
| 20 | @Override | ||
| 21 | public Collection<String> getClassNames() { | ||
| 22 | return delegate.getClassNames(); | ||
| 23 | } | ||
| 24 | |||
| 25 | @Override | ||
| 26 | @Nullable | ||
| 27 | public ClassNode get(String name) { | ||
| 28 | ClassNode classNode = delegate.get(name); | ||
| 29 | |||
| 30 | if (classNode == null) { | ||
| 31 | return null; | ||
| 32 | } | ||
| 33 | |||
| 34 | // copy the class, so that the input class isn't modified (which could lead to the class being retransformed if | ||
| 35 | // it's cached) | ||
| 36 | ClassNode classCopy = new ClassNode(); | ||
| 37 | classNode.accept(classCopy); | ||
| 38 | |||
| 39 | services.get(DecompilerInputTransformerService.TYPE).forEach(transformer -> transformer.transform(classCopy)); | ||
| 40 | |||
| 41 | return classCopy; | ||
| 42 | } | ||
| 43 | } | ||