diff --git a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/impl/CFRDecompiler.java b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/impl/CFRDecompiler.java index abcfc6d7..e56f90e2 100644 --- a/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/impl/CFRDecompiler.java +++ b/src/main/java/the/bytecode/club/bytecodeviewer/decompilers/impl/CFRDecompiler.java @@ -29,10 +29,12 @@ import org.benf.cfr.reader.util.getopt.Options; import org.benf.cfr.reader.util.getopt.OptionsImpl; 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.resources.ResourceContainer; import the.bytecode.club.bytecodeviewer.translation.TranslatedStrings; +import the.bytecode.club.bytecodeviewer.util.ExceptionUtils; import java.io.*; import java.nio.charset.StandardCharsets; @@ -44,15 +46,14 @@ import java.util.zip.ZipException; import java.util.zip.ZipOutputStream; import static the.bytecode.club.bytecodeviewer.Constants.NL; -import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.CFR; -import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.ERROR; +import static the.bytecode.club.bytecodeviewer.translation.TranslatedStrings.*; /** * CFR Java Wrapper * - * @author GraxCode - * Taken mostly out of Threadtear. + * @author GraxCode (Taken mostly out of Threadtear) */ + public class CFRDecompiler extends AbstractDecompiler { @@ -71,59 +72,69 @@ public class CFRDecompiler extends AbstractDecompiler private String decompile(ClassNode cn, String name, byte[] content) { + String exception; + try { String classPath = name + (name.endsWith(CLASS_SUFFIX) ? "" : CLASS_SUFFIX); - StringBuilder builder = new StringBuilder(); Consumer dumpDecompiled = d -> builder.append(d.getJava()); + //initialize CFR Options options = generateOptions(); ClassFileSource source = new BCVDataSource(options, cn, classPath, content); CfrDriver driver = new CfrDriver.Builder().withClassFileSource(source).withBuiltOptions(options).withOutputSink(new BCVOutputSinkFactory(dumpDecompiled)).build(); + + //decompile the class-file driver.analyse(Collections.singletonList(name)); + //handle simulated errors + if(Constants.DEV_FLAG_DECOMPILERS_SIMULATED_ERRORS) + throw new RuntimeException(DEV_MODE_SIMULATED_ERROR.toString()); + + //return the builder contents return builder.toString(); } - catch (Throwable t) + catch (Throwable e) { - t.printStackTrace(); - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - t.printStackTrace(pw); - return CFR + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL + sw; + exception = ExceptionUtils.exceptionToString(e); } + + return CFR + " " + ERROR + "! " + ExceptionUI.SEND_STACKTRACE_TO + NL + NL + + TranslatedStrings.SUGGESTED_FIX_DECOMPILER_ERROR + NL + NL + exception; } @Override public void decompileToZip(String sourceJar, String outJar) { - try (JarFile jfile = new JarFile(new File(sourceJar)); - FileOutputStream dest = new FileOutputStream(outJar); - BufferedOutputStream buffDest = new BufferedOutputStream(dest); - ZipOutputStream out = new ZipOutputStream(buffDest)) + try (JarFile jarFile = new JarFile(new File(sourceJar)); + FileOutputStream destination = new FileOutputStream(outJar); + BufferedOutputStream buffer = new BufferedOutputStream(destination); + ZipOutputStream zip = new ZipOutputStream(buffer)) { byte[] data = new byte[1024]; - - Enumeration ent = jfile.entries(); + Enumeration ent = jarFile.entries(); Set history = new HashSet<>(); + while (ent.hasMoreElements()) { JarEntry entry = ent.nextElement(); + if (entry.getName().endsWith(CLASS_SUFFIX)) { JarEntry etn = new JarEntry(entry.getName().replace(CLASS_SUFFIX, ".java")); if (history.add(etn)) { - out.putNextEntry(etn); + zip.putNextEntry(etn); + try { - IOUtils.write(decompile(null, entry.getName(), IOUtils.toByteArray(jfile.getInputStream(entry))), out, StandardCharsets.UTF_8); + IOUtils.write(decompile(null, entry.getName(), IOUtils.toByteArray(jarFile.getInputStream(entry))), zip, StandardCharsets.UTF_8); } finally { - out.closeEntry(); + zip.closeEntry(); } } } @@ -131,34 +142,36 @@ public class CFRDecompiler extends AbstractDecompiler { try { - JarEntry etn = new JarEntry(entry.getName()); - if (history.add(etn)) + JarEntry jarEntry = new JarEntry(entry.getName()); + + if (history.add(jarEntry)) continue; - history.add(etn); - out.putNextEntry(etn); - try (InputStream in = jfile.getInputStream(entry)) + + history.add(jarEntry); + zip.putNextEntry(jarEntry); + + try (InputStream input = jarFile.getInputStream(entry)) { - if (in != null) + if (input != null) { int count; - while ((count = in.read(data, 0, 1024)) != -1) + + while ((count = input.read(data, 0, 1024)) != -1) { - out.write(data, 0, count); + zip.write(data, 0, count); } } } finally { - out.closeEntry(); + zip.closeEntry(); } } - catch (ZipException ze) + catch (ZipException e) { // some jars contain duplicate pom.xml entries: ignore it - if (!ze.getMessage().contains("duplicate")) - { - throw ze; - } + if (!e.getMessage().contains("duplicate")) + throw e; } } } @@ -226,7 +239,8 @@ public class CFRDecompiler extends AbstractDecompiler private BCVDataSource(Options options, ClassNode cn, String classFilePath, byte[] content) { super(options); - this.container = BytecodeViewer.getResourceContainers().stream().filter(rc -> rc.resourceClasses.containsValue(cn)).findFirst().orElse(null); + this.container = BytecodeViewer.getResourceContainers() + .stream().filter(rc -> rc.resourceClasses.containsValue(cn)).findFirst().orElse(null); this.classFilePath = classFilePath; this.content = content; } @@ -247,7 +261,6 @@ public class CFRDecompiler extends AbstractDecompiler return Pair.make(data, classFilePath); } - } private static class BCVOutputSinkFactory implements OutputSinkFactory @@ -274,9 +287,7 @@ public class CFRDecompiler extends AbstractDecompiler return x -> dumpDecompiled.accept((SinkReturns.Decompiled) x); } - return ignore -> - { - }; + return ignore -> {}; } }