From 1ac293c7b848bc51a2ac8a6e67adc43d899cfab4 Mon Sep 17 00:00:00 2001 From: Konloch Date: Wed, 2 Oct 2024 19:16:14 -0600 Subject: [PATCH] Procyon Decompiler Update --- .../decompilers/impl/ProcyonDecompiler.java | 229 +++++++++--------- 1 file changed, 118 insertions(+), 111 deletions(-) diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/impl/ProcyonDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/impl/ProcyonDecompiler.java index 6bd94d7e..f21198d8 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/impl/ProcyonDecompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/impl/ProcyonDecompiler.java @@ -27,6 +27,7 @@ import com.strobel.decompiler.PlainTextOutput; import com.strobel.decompiler.languages.java.JavaFormattingOptions; import org.objectweb.asm.tree.ClassNode; import the.bytecode.club.bytecodeviewer.BytecodeViewer; +import the.bytecode.club.bytecodeviewer.Constants; import the.bytecode.club.bytecodeviewer.api.ExceptionUI; import the.bytecode.club.bytecodeviewer.decompilers.AbstractDecompiler; import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings; @@ -42,8 +43,7 @@ import java.util.zip.ZipException; import java.util.zip.ZipOutputStream; import static the.bytecode.club.bytecodeviewer.Constants.*; -import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERROR; -import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.PROCYON; +import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.*; /** * Procyon Java Decompiler Wrapper @@ -51,12 +51,13 @@ import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.PRO * @author Konloch * @author DeathMarine */ + public class ProcyonDecompiler extends AbstractDecompiler { public ProcyonDecompiler() { - super("Procyon Decompiler", "proycon"); + super("Procyon Decompiler", "procyon"); } @Override @@ -69,34 +70,43 @@ public class ProcyonDecompiler extends AbstractDecompiler { //create the temporary files tempFile = TempFile.createTemporaryFile(false, ".class"); - File tempClassFile = tempFile.getFile(); + File tempInputClassFile = tempFile.getFile(); //write the ClassNode bytes to the temp file - try (FileOutputStream fos = new FileOutputStream(tempClassFile)) + try (FileOutputStream fos = new FileOutputStream(tempInputClassFile)) { fos.write(bytes); } - //setup proycon decompiler settings + //initialize procyon DecompilerSettings settings = getDecompilerSettings(); - LuytenTypeLoader typeLoader = new LuytenTypeLoader(); MetadataSystem metadataSystem = new MetadataSystem(typeLoader); - TypeReference type = metadataSystem.lookupType(tempClassFile.getCanonicalPath()); - DecompilationOptions decompilationOptions = new DecompilationOptions(); + StringWriter writer = new StringWriter(); + + //lookup the class-file + TypeReference type = metadataSystem.lookupType(tempInputClassFile.getCanonicalPath()); + + //configure procyon decompilationOptions.setSettings(settings); decompilationOptions.setFullDecompilation(true); + //parse class-file TypeDefinition resolvedType; if (type == null || ((resolvedType = type.resolve()) == null)) - throw new Exception("Unable to resolve type."); + throw new Exception("Unable to resolve class-filetype."); - StringWriter stringwriter = new StringWriter(); - settings.getLanguage().decompileType(resolvedType, new PlainTextOutput(stringwriter), decompilationOptions); + //decompile the class-file + settings.getLanguage().decompileType(resolvedType, new PlainTextOutput(writer), decompilationOptions); - return EncodeUtils.unicodeToString(stringwriter.toString()); + //handle simulated errors + if(Constants.DEV_FLAG_DECOMPILERS_SIMULATED_ERRORS) + throw new RuntimeException(DEV_MODE_SIMULATED_ERROR.toString()); + + //return the writer contents + return EncodeUtils.unicodeToString(writer.toString()); } catch (Throwable e) { @@ -106,7 +116,7 @@ public class ProcyonDecompiler extends AbstractDecompiler { //delete all temporary files if(tempFile != null) - tempFile.delete(); + tempFile.cleanup(); } return PROCYON + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL @@ -118,7 +128,100 @@ public class ProcyonDecompiler extends AbstractDecompiler { try { - doSaveJarDecompiled(new File(sourceJar), new File(zipName)); + try (JarFile jarFile = new JarFile(sourceJar); + FileOutputStream destination = new FileOutputStream(zipName); + BufferedOutputStream buffer = new BufferedOutputStream(destination); + ZipOutputStream zip = new ZipOutputStream(buffer)) + { + byte[] data = new byte[1024]; + + //initialize procyon + DecompilerSettings settings = getDecompilerSettings(); + LuytenTypeLoader typeLoader = new LuytenTypeLoader(); + MetadataSystem metadataSystem = new MetadataSystem(typeLoader); + ITypeLoader jarLoader = new JarTypeLoader(jarFile); + + //lookup the jar-file + typeLoader.getTypeLoaders().add(jarLoader); + + //configure procyon + DecompilationOptions decompilationOptions = new DecompilationOptions(); + decompilationOptions.setSettings(settings); + decompilationOptions.setFullDecompilation(true); + + //setup jar output + Enumeration ent = jarFile.entries(); + Set history = new HashSet<>(); + + while (ent.hasMoreElements()) + { + JarEntry entry = ent.nextElement(); + + if (entry.getName().endsWith(".class")) + { + JarEntry etn = new JarEntry(entry.getName().replace(".class", ".java")); + + if (history.add(etn)) + { + zip.putNextEntry(etn); + + try + { + String internalName = StringUtilities.removeRight(entry.getName(), ".class"); + TypeReference type = metadataSystem.lookupType(internalName); + TypeDefinition resolvedType; + + if ((type == null) || ((resolvedType = type.resolve()) == null)) + throw new Exception("Unable to resolve type."); + + Writer writer = new OutputStreamWriter(zip); + settings.getLanguage().decompileType(resolvedType, new PlainTextOutput(writer), decompilationOptions); + writer.flush(); + } + finally + { + zip.closeEntry(); + } + } + } + else + { + try + { + JarEntry etn = new JarEntry(entry.getName()); + + if (history.add(etn)) + continue; + + history.add(etn); + zip.putNextEntry(etn); + + try (InputStream in = jarFile.getInputStream(entry)) + { + if (in != null) + { + int count; + + while ((count = in.read(data, 0, 1024)) != -1) + { + zip.write(data, 0, count); + } + } + } + finally + { + zip.closeEntry(); + } + } + catch (ZipException ze) + { + // some jars contain duplicate pom.xml entries: ignore it + if (!ze.getMessage().contains("duplicate")) + throw ze; + } + } + } + } } catch (StackOverflowError | Exception e) { @@ -126,102 +229,6 @@ public class ProcyonDecompiler extends AbstractDecompiler } } - /** - * @author DeathMarine - */ - private void doSaveJarDecompiled(File inFile, File outFile) throws Exception - { - try (JarFile jfile = new JarFile(inFile); - FileOutputStream dest = new FileOutputStream(outFile); - BufferedOutputStream buffDest = new BufferedOutputStream(dest); - ZipOutputStream out = new ZipOutputStream(buffDest)) - { - byte[] data = new byte[1024]; - DecompilerSettings settings = getDecompilerSettings(); - LuytenTypeLoader typeLoader = new LuytenTypeLoader(); - MetadataSystem metadataSystem = new MetadataSystem(typeLoader); - ITypeLoader jarLoader = new JarTypeLoader(jfile); - typeLoader.getTypeLoaders().add(jarLoader); - - DecompilationOptions decompilationOptions = new DecompilationOptions(); - decompilationOptions.setSettings(settings); - decompilationOptions.setFullDecompilation(true); - - Enumeration ent = jfile.entries(); - Set history = new HashSet<>(); - - while (ent.hasMoreElements()) - { - JarEntry entry = ent.nextElement(); - - if (entry.getName().endsWith(".class")) - { - JarEntry etn = new JarEntry(entry.getName().replace(".class", ".java")); - - if (history.add(etn)) - { - out.putNextEntry(etn); - - try - { - String internalName = StringUtilities.removeRight(entry.getName(), ".class"); - TypeReference type = metadataSystem.lookupType(internalName); - TypeDefinition resolvedType; - - if ((type == null) || ((resolvedType = type.resolve()) == null)) - { - throw new Exception("Unable to resolve type."); - } - - Writer writer = new OutputStreamWriter(out); - settings.getLanguage().decompileType(resolvedType, new PlainTextOutput(writer), decompilationOptions); - writer.flush(); - } - finally - { - out.closeEntry(); - } - } - } - else - { - try - { - JarEntry etn = new JarEntry(entry.getName()); - - if (history.add(etn)) - continue; - - history.add(etn); - out.putNextEntry(etn); - - try (InputStream in = jfile.getInputStream(entry)) - { - if (in != null) - { - int count; - while ((count = in.read(data, 0, 1024)) != -1) - { - out.write(data, 0, count); - } - } - } - finally - { - out.closeEntry(); - } - } - catch (ZipException ze) - { - // some jars contain duplicate pom.xml entries: ignore it - if (!ze.getMessage().contains("duplicate")) - throw ze; - } - } - } - } - } - public DecompilerSettings getDecompilerSettings() { DecompilerSettings settings = new DecompilerSettings();