package club.bytecode.the.jda.decompilers; import club.bytecode.the.jda.FileContainer; import club.bytecode.the.jda.JDA; import club.bytecode.the.jda.api.JDANamespace; import club.bytecode.the.jda.settings.JDADecompilerSettings.SettingsEntry; import com.strobel.assembler.InputTypeLoader; import com.strobel.assembler.metadata.*; import com.strobel.decompiler.DecompilationOptions; import com.strobel.decompiler.DecompilerSettings; import com.strobel.decompiler.PlainTextOutput; import org.objectweb.asm.tree.ClassNode; import java.io.StringWriter; import java.util.Map; /** * Procyon Java Decompiler Wrapper * * @author Konloch * @author DeathMarine */ public final class ProcyonDecompiler extends JDADecompiler { public ProcyonDecompiler() { // output modes: Bytecode AST, raw bytecode, Java settings.registerSetting(new SettingsEntry("ci", "Use wildcard imports", false)); settings.registerSetting(new SettingsEntry("dl", "Show LVT comments", false)); settings.registerSetting(new SettingsEntry("disable-foreach", "Disable 'for each'", false)); settings.registerSetting(new SettingsEntry("eml", "Eager method loading", false)); settings.registerSetting(new SettingsEntry("ent", "Exclude nested types", false)); settings.registerSetting(new SettingsEntry("ei", "Explicit type arguments", false)); settings.registerSetting(new SettingsEntry("fsb", "Flatten switch blocks", false)); settings.registerSetting(new SettingsEntry("mv", "Merge variables aggressively", false)); settings.registerSetting(new SettingsEntry("ec", "Retain redundant casts", false)); settings.registerSetting(new SettingsEntry("ps", "Retain pointless switches", false)); settings.registerSetting(new SettingsEntry("ss", "Show synthetic members", true)); settings.registerSetting(new SettingsEntry("sm", "Simplify member references", false)); settings.registerSetting(new SettingsEntry("sl", "Stretch lines to match LVT", false)); settings.registerSetting(new SettingsEntry("unicode", "Do not escape non-ASCII characters", false)); // settings.registerSetting(new SettingsEntry("u", "Unoptimized AST", false)); } @Override public String getName() { return "Procyon"; } @Override public JDANamespace getNamespace() { return JDA.namespace; } public DecompilerSettings getDecompilerSettings() { DecompilerSettings procyonSettings = new DecompilerSettings(); procyonSettings.setFlattenSwitchBlocks(settings.getEntry("fsb").getBool()); procyonSettings.setForceExplicitImports(!settings.getEntry("ci").getBool()); procyonSettings.setForceExplicitTypeArguments(settings.getEntry("ei").getBool()); procyonSettings.setRetainRedundantCasts(settings.getEntry("ec").getBool()); procyonSettings.setShowSyntheticMembers(settings.getEntry("ss").getBool()); procyonSettings.setExcludeNestedTypes(settings.getEntry("ent").getBool()); // procyonSettings.setOutputDirectory(options.getOutputDirectory()); procyonSettings.setIncludeLineNumbersInBytecode(settings.getEntry("dl").getBool()); procyonSettings.setRetainPointlessSwitches(settings.getEntry("ps").getBool()); procyonSettings.setUnicodeOutputEnabled(settings.getEntry("unicode").getBool()); procyonSettings.setMergeVariables(settings.getEntry("mv").getBool()); procyonSettings.setShowDebugLineNumbers(settings.getEntry("dl").getBool()); procyonSettings.setSimplifyMemberReferences(settings.getEntry("sm").getBool()); procyonSettings.setDisableForEachTransforms(settings.getEntry("disable-foreach").getBool()); procyonSettings.setTypeLoader(new InputTypeLoader()); // procyonSettings.setLanguage(Languages.bytecode()); // procyonSettings.setLanguage(settings.getEntry("Unoptimized AST").getBool() ? Languages.bytecodeAstUnoptimized() : Languages.bytecodeAst()); return procyonSettings; } @Override public String decompileClassNode(FileContainer container, final ClassNode cn) { try { byte[] bytes = JDA.getClassBytes(container, cn); MetadataSystem metadataSystem = new MetadataSystem(new ITypeLoader() { private InputTypeLoader backLoader = new InputTypeLoader(); @Override public boolean tryLoadType(String s, Buffer buffer) { if (s.equals(cn.name)) { buffer.putByteArray(bytes, 0, bytes.length); buffer.position(0); return true; } else { String classFilename = s + ".class"; FileContainer otherContainer = JDA.findContainerForFile(classFilename); if (otherContainer != null) { byte[] toUse = otherContainer.getFiles().get(classFilename); if (toUse != null) { buffer.putByteArray(toUse, 0, toUse.length); buffer.position(0); return true; } } return backLoader.tryLoadType(s, buffer); } } }); TypeReference type = metadataSystem.lookupType(cn.name); DecompilationOptions decompilationOptions = new DecompilationOptions(); DecompilerSettings settings = getDecompilerSettings(); decompilationOptions.setSettings(settings); decompilationOptions.setFullDecompilation(true); TypeDefinition resolvedType; if (type == null || ((resolvedType = type.resolve()) == null)) { throw new Exception("Unable to resolve type."); } StringWriter stringwriter = new StringWriter(); settings.getLanguage().decompileType(resolvedType, new PlainTextOutput(stringwriter), decompilationOptions); String decompiledSource = stringwriter.toString(); return decompiledSource; } catch (Throwable e) { return parseException(e); } } }