// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.java.decompiler.main; import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode; import org.jetbrains.java.decompiler.main.extern.*; import org.jetbrains.java.decompiler.modules.renamer.ConverterHelper; import org.jetbrains.java.decompiler.modules.renamer.IdentifierConverter; import org.jetbrains.java.decompiler.modules.renamer.PoolInterceptor; import org.jetbrains.java.decompiler.struct.IDecompiledData; import org.jetbrains.java.decompiler.struct.StructClass; import org.jetbrains.java.decompiler.struct.StructContext; import org.jetbrains.java.decompiler.struct.lazy.LazyLoader; import java.util.Map; public class Fernflower implements IDecompiledData { private final StructContext structContext; private final ClassesProcessor classProcessor; private IIdentifierRenamer helper; private IdentifierConverter converter; public Fernflower(IBytecodeProvider provider, IResultSaver saver, Map options, IFernflowerLogger logger) { structContext = new StructContext(saver, this, new LazyLoader(provider)); classProcessor = new ClassesProcessor(structContext); PoolInterceptor interceptor = null; Object rename = options.get(IFernflowerPreferences.RENAME_ENTITIES); if ("1".equals(rename) || rename == null && "1".equals(IFernflowerPreferences.DEFAULTS.get(IFernflowerPreferences.RENAME_ENTITIES))) { helper = loadHelper((String)options.get(IFernflowerPreferences.USER_RENAMER_CLASS)); interceptor = new PoolInterceptor(); converter = new IdentifierConverter(structContext, helper, interceptor); } DecompilerContext.initContext(options, logger, structContext, classProcessor, interceptor); } public void decompileContext() { if (converter != null) { converter.rename(); } classProcessor.loadClasses(helper); structContext.saveContext(); } private static IIdentifierRenamer loadHelper(String className) { if (className != null) { try { Class renamerClass = Fernflower.class.getClassLoader().loadClass(className); return (IIdentifierRenamer) renamerClass.getDeclaredConstructor().newInstance(); } catch (Exception ignored) { } } return new ConverterHelper(); } public void clearContext() { DecompilerContext.clearContext(); } public StructContext getStructContext() { return structContext; } @Override public String getClassEntryName(StructClass cl, String entryName) { ClassNode node = classProcessor.getMapRootClasses().get(cl.qualifiedName); if (node.type != ClassNode.CLASS_ROOT) { return null; } else if (converter != null) { String simpleClassName = cl.qualifiedName.substring(cl.qualifiedName.lastIndexOf('/') + 1); return entryName.substring(0, entryName.lastIndexOf('/') + 1) + simpleClassName + ".java"; } else { return entryName.substring(0, entryName.lastIndexOf(".class")) + ".java"; } } @Override public String getClassContent(StructClass cl) { try { TextBuffer buffer = new TextBuffer(ClassesProcessor.AVERAGE_CLASS_SIZE); buffer.append(DecompilerContext.getProperty(IFernflowerPreferences.BANNER).toString()); classProcessor.writeClass(cl, buffer); return buffer.toString(); } catch (Throwable ex) { DecompilerContext.getLogger().writeMessage("Class " + cl.qualifiedName + " couldn't be fully decompiled.", ex); return null; } } }