From 4be005617b3b8c3578cca07c5d085d12916f0d1d Mon Sep 17 00:00:00 2001 From: lclc98 Date: Thu, 30 Jun 2016 00:49:21 +1000 Subject: Json format (#2) * Added new format * Fixed bug * Updated Version --- src/cuchaz/enigma/CommandMain.java | 186 ---- src/cuchaz/enigma/Constants.java | 20 - src/cuchaz/enigma/ConvertMain.java | 379 ------- src/cuchaz/enigma/Deobfuscator.java | 551 ---------- src/cuchaz/enigma/ExceptionIgnorer.java | 34 - src/cuchaz/enigma/Main.java | 51 - src/cuchaz/enigma/MainFormatConverter.java | 130 --- src/cuchaz/enigma/TranslatingTypeLoader.java | 249 ----- src/cuchaz/enigma/Util.java | 104 -- src/cuchaz/enigma/analysis/Access.java | 43 - .../enigma/analysis/BehaviorReferenceTreeNode.java | 93 -- src/cuchaz/enigma/analysis/BridgeMarker.java | 43 - .../analysis/ClassImplementationsTreeNode.java | 80 -- .../enigma/analysis/ClassInheritanceTreeNode.java | 85 -- src/cuchaz/enigma/analysis/EntryReference.java | 126 --- src/cuchaz/enigma/analysis/EntryRenamer.java | 192 ---- .../enigma/analysis/FieldReferenceTreeNode.java | 81 -- src/cuchaz/enigma/analysis/JarClassIterator.java | 137 --- src/cuchaz/enigma/analysis/JarIndex.java | 839 --------------- .../analysis/MethodImplementationsTreeNode.java | 101 -- .../enigma/analysis/MethodInheritanceTreeNode.java | 114 -- src/cuchaz/enigma/analysis/ReferenceTreeNode.java | 18 - .../enigma/analysis/RelatedMethodChecker.java | 106 -- src/cuchaz/enigma/analysis/SourceIndex.java | 184 ---- .../analysis/SourceIndexBehaviorVisitor.java | 150 --- .../enigma/analysis/SourceIndexClassVisitor.java | 112 -- src/cuchaz/enigma/analysis/SourceIndexVisitor.java | 452 -------- src/cuchaz/enigma/analysis/Token.java | 56 - src/cuchaz/enigma/analysis/TranslationIndex.java | 298 ------ src/cuchaz/enigma/analysis/TreeDumpVisitor.java | 512 --------- src/cuchaz/enigma/bytecode/CheckCastIterator.java | 127 --- src/cuchaz/enigma/bytecode/ClassProtectifier.java | 51 - src/cuchaz/enigma/bytecode/ClassPublifier.java | 51 - src/cuchaz/enigma/bytecode/ClassRenamer.java | 544 ---------- src/cuchaz/enigma/bytecode/ClassTranslator.java | 157 --- src/cuchaz/enigma/bytecode/ConstPoolEditor.java | 263 ----- src/cuchaz/enigma/bytecode/InfoType.java | 317 ------ src/cuchaz/enigma/bytecode/InnerClassWriter.java | 132 --- .../enigma/bytecode/LocalVariableRenamer.java | 123 --- .../enigma/bytecode/MethodParameterWriter.java | 70 -- .../enigma/bytecode/MethodParametersAttribute.java | 86 -- .../bytecode/accessors/ClassInfoAccessor.java | 55 - .../bytecode/accessors/ConstInfoAccessor.java | 156 --- .../accessors/InvokeDynamicInfoAccessor.java | 74 -- .../bytecode/accessors/MemberRefInfoAccessor.java | 74 -- .../accessors/MethodHandleInfoAccessor.java | 74 -- .../bytecode/accessors/MethodTypeInfoAccessor.java | 55 - .../accessors/NameAndTypeInfoAccessor.java | 74 -- .../bytecode/accessors/StringInfoAccessor.java | 55 - .../bytecode/accessors/Utf8InfoAccessor.java | 28 - src/cuchaz/enigma/convert/ClassForest.java | 60 -- src/cuchaz/enigma/convert/ClassIdentifier.java | 54 - src/cuchaz/enigma/convert/ClassIdentity.java | 473 --------- src/cuchaz/enigma/convert/ClassMatch.java | 88 -- src/cuchaz/enigma/convert/ClassMatches.java | 163 --- src/cuchaz/enigma/convert/ClassMatching.java | 155 --- src/cuchaz/enigma/convert/ClassNamer.java | 66 -- src/cuchaz/enigma/convert/FieldMatches.java | 155 --- src/cuchaz/enigma/convert/MappingsConverter.java | 602 ----------- src/cuchaz/enigma/convert/MatchesReader.java | 113 -- src/cuchaz/enigma/convert/MatchesWriter.java | 121 --- src/cuchaz/enigma/convert/MemberMatches.java | 159 --- src/cuchaz/enigma/gui/AboutDialog.java | 86 -- src/cuchaz/enigma/gui/BoxHighlightPainter.java | 64 -- src/cuchaz/enigma/gui/BrowserCaret.java | 45 - src/cuchaz/enigma/gui/ClassListCellRenderer.java | 36 - src/cuchaz/enigma/gui/ClassMatchingGui.java | 622 ----------- src/cuchaz/enigma/gui/ClassSelector.java | 293 ----- src/cuchaz/enigma/gui/ClassSelectorClassNode.java | 50 - .../enigma/gui/ClassSelectorPackageNode.java | 45 - src/cuchaz/enigma/gui/CodeReader.java | 222 ---- src/cuchaz/enigma/gui/CrashDialog.java | 101 -- .../enigma/gui/DeobfuscatedHighlightPainter.java | 21 - src/cuchaz/enigma/gui/Gui.java | 1122 -------------------- src/cuchaz/enigma/gui/GuiController.java | 358 ------- src/cuchaz/enigma/gui/GuiTricks.java | 56 - src/cuchaz/enigma/gui/MemberMatchingGui.java | 499 --------- .../enigma/gui/ObfuscatedHighlightPainter.java | 21 - src/cuchaz/enigma/gui/OtherHighlightPainter.java | 21 - src/cuchaz/enigma/gui/ProgressDialog.java | 105 -- src/cuchaz/enigma/gui/ReadableToken.java | 36 - src/cuchaz/enigma/gui/RenameListener.java | 17 - src/cuchaz/enigma/gui/ScoredClassEntry.java | 30 - .../enigma/gui/SelectionHighlightPainter.java | 34 - src/cuchaz/enigma/gui/TokenListCellRenderer.java | 38 - src/cuchaz/enigma/mapping/ArgumentEntry.java | 116 -- src/cuchaz/enigma/mapping/ArgumentMapping.java | 49 - src/cuchaz/enigma/mapping/BehaviorEntry.java | 15 - src/cuchaz/enigma/mapping/ClassEntry.java | 172 --- src/cuchaz/enigma/mapping/ClassMapping.java | 460 -------- src/cuchaz/enigma/mapping/ClassNameReplacer.java | 15 - src/cuchaz/enigma/mapping/ConstructorEntry.java | 116 -- src/cuchaz/enigma/mapping/Entry.java | 18 - src/cuchaz/enigma/mapping/EntryFactory.java | 166 --- src/cuchaz/enigma/mapping/EntryPair.java | 22 - src/cuchaz/enigma/mapping/FieldEntry.java | 99 -- src/cuchaz/enigma/mapping/FieldMapping.java | 89 -- .../enigma/mapping/IllegalNameException.java | 44 - .../enigma/mapping/MappingParseException.java | 29 - src/cuchaz/enigma/mapping/Mappings.java | 216 ---- src/cuchaz/enigma/mapping/MappingsChecker.java | 107 -- src/cuchaz/enigma/mapping/MappingsReader.java | 134 --- src/cuchaz/enigma/mapping/MappingsRenamer.java | 237 ----- src/cuchaz/enigma/mapping/MappingsWriter.java | 88 -- src/cuchaz/enigma/mapping/MemberMapping.java | 17 - src/cuchaz/enigma/mapping/MethodEntry.java | 104 -- src/cuchaz/enigma/mapping/MethodMapping.java | 191 ---- src/cuchaz/enigma/mapping/NameValidator.java | 80 -- src/cuchaz/enigma/mapping/ProcyonEntryFactory.java | 55 - src/cuchaz/enigma/mapping/Signature.java | 117 -- src/cuchaz/enigma/mapping/SignatureUpdater.java | 94 -- .../enigma/mapping/TranslationDirection.java | 29 - src/cuchaz/enigma/mapping/Translator.java | 289 ----- src/cuchaz/enigma/mapping/Type.java | 247 ----- 114 files changed, 17638 deletions(-) delete mode 100644 src/cuchaz/enigma/CommandMain.java delete mode 100644 src/cuchaz/enigma/Constants.java delete mode 100644 src/cuchaz/enigma/ConvertMain.java delete mode 100644 src/cuchaz/enigma/Deobfuscator.java delete mode 100644 src/cuchaz/enigma/ExceptionIgnorer.java delete mode 100644 src/cuchaz/enigma/Main.java delete mode 100644 src/cuchaz/enigma/MainFormatConverter.java delete mode 100644 src/cuchaz/enigma/TranslatingTypeLoader.java delete mode 100644 src/cuchaz/enigma/Util.java delete mode 100644 src/cuchaz/enigma/analysis/Access.java delete mode 100644 src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java delete mode 100644 src/cuchaz/enigma/analysis/BridgeMarker.java delete mode 100644 src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java delete mode 100644 src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java delete mode 100644 src/cuchaz/enigma/analysis/EntryReference.java delete mode 100644 src/cuchaz/enigma/analysis/EntryRenamer.java delete mode 100644 src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java delete mode 100644 src/cuchaz/enigma/analysis/JarClassIterator.java delete mode 100644 src/cuchaz/enigma/analysis/JarIndex.java delete mode 100644 src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java delete mode 100644 src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java delete mode 100644 src/cuchaz/enigma/analysis/ReferenceTreeNode.java delete mode 100644 src/cuchaz/enigma/analysis/RelatedMethodChecker.java delete mode 100644 src/cuchaz/enigma/analysis/SourceIndex.java delete mode 100644 src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java delete mode 100644 src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java delete mode 100644 src/cuchaz/enigma/analysis/SourceIndexVisitor.java delete mode 100644 src/cuchaz/enigma/analysis/Token.java delete mode 100644 src/cuchaz/enigma/analysis/TranslationIndex.java delete mode 100644 src/cuchaz/enigma/analysis/TreeDumpVisitor.java delete mode 100644 src/cuchaz/enigma/bytecode/CheckCastIterator.java delete mode 100644 src/cuchaz/enigma/bytecode/ClassProtectifier.java delete mode 100644 src/cuchaz/enigma/bytecode/ClassPublifier.java delete mode 100644 src/cuchaz/enigma/bytecode/ClassRenamer.java delete mode 100644 src/cuchaz/enigma/bytecode/ClassTranslator.java delete mode 100644 src/cuchaz/enigma/bytecode/ConstPoolEditor.java delete mode 100644 src/cuchaz/enigma/bytecode/InfoType.java delete mode 100644 src/cuchaz/enigma/bytecode/InnerClassWriter.java delete mode 100644 src/cuchaz/enigma/bytecode/LocalVariableRenamer.java delete mode 100644 src/cuchaz/enigma/bytecode/MethodParameterWriter.java delete mode 100644 src/cuchaz/enigma/bytecode/MethodParametersAttribute.java delete mode 100644 src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java delete mode 100644 src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java delete mode 100644 src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java delete mode 100644 src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java delete mode 100644 src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java delete mode 100644 src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java delete mode 100644 src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java delete mode 100644 src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java delete mode 100644 src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java delete mode 100644 src/cuchaz/enigma/convert/ClassForest.java delete mode 100644 src/cuchaz/enigma/convert/ClassIdentifier.java delete mode 100644 src/cuchaz/enigma/convert/ClassIdentity.java delete mode 100644 src/cuchaz/enigma/convert/ClassMatch.java delete mode 100644 src/cuchaz/enigma/convert/ClassMatches.java delete mode 100644 src/cuchaz/enigma/convert/ClassMatching.java delete mode 100644 src/cuchaz/enigma/convert/ClassNamer.java delete mode 100644 src/cuchaz/enigma/convert/FieldMatches.java delete mode 100644 src/cuchaz/enigma/convert/MappingsConverter.java delete mode 100644 src/cuchaz/enigma/convert/MatchesReader.java delete mode 100644 src/cuchaz/enigma/convert/MatchesWriter.java delete mode 100644 src/cuchaz/enigma/convert/MemberMatches.java delete mode 100644 src/cuchaz/enigma/gui/AboutDialog.java delete mode 100644 src/cuchaz/enigma/gui/BoxHighlightPainter.java delete mode 100644 src/cuchaz/enigma/gui/BrowserCaret.java delete mode 100644 src/cuchaz/enigma/gui/ClassListCellRenderer.java delete mode 100644 src/cuchaz/enigma/gui/ClassMatchingGui.java delete mode 100644 src/cuchaz/enigma/gui/ClassSelector.java delete mode 100644 src/cuchaz/enigma/gui/ClassSelectorClassNode.java delete mode 100644 src/cuchaz/enigma/gui/ClassSelectorPackageNode.java delete mode 100644 src/cuchaz/enigma/gui/CodeReader.java delete mode 100644 src/cuchaz/enigma/gui/CrashDialog.java delete mode 100644 src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java delete mode 100644 src/cuchaz/enigma/gui/Gui.java delete mode 100644 src/cuchaz/enigma/gui/GuiController.java delete mode 100644 src/cuchaz/enigma/gui/GuiTricks.java delete mode 100644 src/cuchaz/enigma/gui/MemberMatchingGui.java delete mode 100644 src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java delete mode 100644 src/cuchaz/enigma/gui/OtherHighlightPainter.java delete mode 100644 src/cuchaz/enigma/gui/ProgressDialog.java delete mode 100644 src/cuchaz/enigma/gui/ReadableToken.java delete mode 100644 src/cuchaz/enigma/gui/RenameListener.java delete mode 100644 src/cuchaz/enigma/gui/ScoredClassEntry.java delete mode 100644 src/cuchaz/enigma/gui/SelectionHighlightPainter.java delete mode 100644 src/cuchaz/enigma/gui/TokenListCellRenderer.java delete mode 100644 src/cuchaz/enigma/mapping/ArgumentEntry.java delete mode 100644 src/cuchaz/enigma/mapping/ArgumentMapping.java delete mode 100644 src/cuchaz/enigma/mapping/BehaviorEntry.java delete mode 100644 src/cuchaz/enigma/mapping/ClassEntry.java delete mode 100644 src/cuchaz/enigma/mapping/ClassMapping.java delete mode 100644 src/cuchaz/enigma/mapping/ClassNameReplacer.java delete mode 100644 src/cuchaz/enigma/mapping/ConstructorEntry.java delete mode 100644 src/cuchaz/enigma/mapping/Entry.java delete mode 100644 src/cuchaz/enigma/mapping/EntryFactory.java delete mode 100644 src/cuchaz/enigma/mapping/EntryPair.java delete mode 100644 src/cuchaz/enigma/mapping/FieldEntry.java delete mode 100644 src/cuchaz/enigma/mapping/FieldMapping.java delete mode 100644 src/cuchaz/enigma/mapping/IllegalNameException.java delete mode 100644 src/cuchaz/enigma/mapping/MappingParseException.java delete mode 100644 src/cuchaz/enigma/mapping/Mappings.java delete mode 100644 src/cuchaz/enigma/mapping/MappingsChecker.java delete mode 100644 src/cuchaz/enigma/mapping/MappingsReader.java delete mode 100644 src/cuchaz/enigma/mapping/MappingsRenamer.java delete mode 100644 src/cuchaz/enigma/mapping/MappingsWriter.java delete mode 100644 src/cuchaz/enigma/mapping/MemberMapping.java delete mode 100644 src/cuchaz/enigma/mapping/MethodEntry.java delete mode 100644 src/cuchaz/enigma/mapping/MethodMapping.java delete mode 100644 src/cuchaz/enigma/mapping/NameValidator.java delete mode 100644 src/cuchaz/enigma/mapping/ProcyonEntryFactory.java delete mode 100644 src/cuchaz/enigma/mapping/Signature.java delete mode 100644 src/cuchaz/enigma/mapping/SignatureUpdater.java delete mode 100644 src/cuchaz/enigma/mapping/TranslationDirection.java delete mode 100644 src/cuchaz/enigma/mapping/Translator.java delete mode 100644 src/cuchaz/enigma/mapping/Type.java (limited to 'src/cuchaz') diff --git a/src/cuchaz/enigma/CommandMain.java b/src/cuchaz/enigma/CommandMain.java deleted file mode 100644 index 540cfb95..00000000 --- a/src/cuchaz/enigma/CommandMain.java +++ /dev/null @@ -1,186 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma; - -import java.io.File; -import java.io.FileReader; -import java.util.jar.JarFile; - -import cuchaz.enigma.Deobfuscator.ProgressListener; -import cuchaz.enigma.mapping.Mappings; -import cuchaz.enigma.mapping.MappingsReader; - -public class CommandMain { - - public static class ConsoleProgressListener implements ProgressListener { - - private static final int ReportTime = 5000; // 5s - - private int m_totalWork; - private long m_startTime; - private long m_lastReportTime; - - @Override - public void init(int totalWork, String title) { - m_totalWork = totalWork; - m_startTime = System.currentTimeMillis(); - m_lastReportTime = m_startTime; - System.out.println(title); - } - - @Override - public void onProgress(int numDone, String message) { - - long now = System.currentTimeMillis(); - boolean isLastUpdate = numDone == m_totalWork; - boolean shouldReport = isLastUpdate || now - m_lastReportTime > ReportTime; - - if (shouldReport) { - int percent = numDone*100/m_totalWork; - System.out.println(String.format("\tProgress: %3d%%", percent)); - m_lastReportTime = now; - } - if (isLastUpdate) { - double elapsedSeconds = (now - m_startTime)/1000; - System.out.println(String.format("Finished in %.1f seconds", elapsedSeconds)); - } - } - } - - public static void main(String[] args) - throws Exception { - - try { - - // process the command - String command = getArg(args, 0, "command", true); - if (command.equalsIgnoreCase("deobfuscate")) { - deobfuscate(args); - } else if (command.equalsIgnoreCase("decompile")) { - decompile(args); - } else if (command.equalsIgnoreCase("protectify")) { - protectify(args); - } else if (command.equalsIgnoreCase("publify")) { - publify(args); - } else { - throw new IllegalArgumentException("Command not recognized: " + command); - } - } catch (IllegalArgumentException ex) { - System.out.println(ex.getMessage()); - printHelp(); - } - } - - private static void printHelp() { - System.out.println(String.format("%s - %s", Constants.Name, Constants.Version)); - System.out.println("Usage:"); - System.out.println("\tjava -cp enigma.jar cuchaz.enigma.CommandMain "); - System.out.println("\twhere is one of:"); - System.out.println("\t\tdeobfuscate []"); - System.out.println("\t\tdecompile []"); - System.out.println("\t\tprotectify "); - } - - private static void decompile(String[] args) - throws Exception { - File fileJarIn = getReadableFile(getArg(args, 1, "in jar", true)); - File fileJarOut = getWritableFolder(getArg(args, 2, "out folder", true)); - File fileMappings = getReadableFile(getArg(args, 3, "mappings file", false)); - Deobfuscator deobfuscator = getDeobfuscator(fileMappings, new JarFile(fileJarIn)); - deobfuscator.writeSources(fileJarOut, new ConsoleProgressListener()); - } - - private static void deobfuscate(String[] args) - throws Exception { - File fileJarIn = getReadableFile(getArg(args, 1, "in jar", true)); - File fileJarOut = getWritableFile(getArg(args, 2, "out jar", true)); - File fileMappings = getReadableFile(getArg(args, 3, "mappings file", false)); - Deobfuscator deobfuscator = getDeobfuscator(fileMappings, new JarFile(fileJarIn)); - deobfuscator.writeJar(fileJarOut, new ConsoleProgressListener()); - } - - private static void protectify(String[] args) - throws Exception { - File fileJarIn = getReadableFile(getArg(args, 1, "in jar", true)); - File fileJarOut = getWritableFile(getArg(args, 2, "out jar", true)); - Deobfuscator deobfuscator = getDeobfuscator(null, new JarFile(fileJarIn)); - deobfuscator.protectifyJar(fileJarOut, new ConsoleProgressListener()); - } - - private static void publify(String[] args) - throws Exception { - File fileJarIn = getReadableFile(getArg(args, 1, "in jar", true)); - File fileJarOut = getWritableFile(getArg(args, 2, "out jar", true)); - Deobfuscator deobfuscator = getDeobfuscator(null, new JarFile(fileJarIn)); - deobfuscator.publifyJar(fileJarOut, new ConsoleProgressListener()); - } - - private static Deobfuscator getDeobfuscator(File fileMappings, JarFile jar) - throws Exception { - System.out.println("Reading jar..."); - Deobfuscator deobfuscator = new Deobfuscator(jar); - if (fileMappings != null) { - System.out.println("Reading mappings..."); - Mappings mappings = new MappingsReader().read(new FileReader(fileMappings)); - deobfuscator.setMappings(mappings); - } - return deobfuscator; - } - - private static String getArg(String[] args, int i, String name, boolean required) { - if (i >= args.length) { - if (required) { - throw new IllegalArgumentException(name + " is required"); - } else { - return null; - } - } - return args[i]; - } - - private static File getWritableFile(String path) { - if (path == null) { - return null; - } - File file = new File(path).getAbsoluteFile(); - File dir = file.getParentFile(); - if (dir == null) { - throw new IllegalArgumentException("Cannot write to folder: " + dir); - } - // quick fix to avoid stupid stuff in Gradle code - if (!dir.isDirectory()) { - dir.mkdirs(); - } - return file; - } - - private static File getWritableFolder(String path) { - if (path == null) { - return null; - } - File dir = new File(path).getAbsoluteFile(); - if (!dir.exists()) { - throw new IllegalArgumentException("Cannot write to folder: " + dir); - } - return dir; - } - - private static File getReadableFile(String path) { - if (path == null) { - return null; - } - File file = new File(path).getAbsoluteFile(); - if (!file.exists()) { - throw new IllegalArgumentException("Cannot find file: " + file.getAbsolutePath()); - } - return file; - } -} diff --git a/src/cuchaz/enigma/Constants.java b/src/cuchaz/enigma/Constants.java deleted file mode 100644 index 598cf38f..00000000 --- a/src/cuchaz/enigma/Constants.java +++ /dev/null @@ -1,20 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma; - -public class Constants { - public static final String Name = "Enigma"; - public static final String Version = "0.11 beta"; - public static final String Url = "http://www.cuchazinteractive.com/enigma"; - public static final int MiB = 1024 * 1024; // 1 mebibyte - public static final int KiB = 1024; // 1 kebibyte - public static final String NonePackage = "none"; -} diff --git a/src/cuchaz/enigma/ConvertMain.java b/src/cuchaz/enigma/ConvertMain.java deleted file mode 100644 index 48a15881..00000000 --- a/src/cuchaz/enigma/ConvertMain.java +++ /dev/null @@ -1,379 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma; - -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.util.jar.JarFile; - -import cuchaz.enigma.convert.ClassMatches; -import cuchaz.enigma.convert.MappingsConverter; -import cuchaz.enigma.convert.MatchesReader; -import cuchaz.enigma.convert.MatchesWriter; -import cuchaz.enigma.convert.MemberMatches; -import cuchaz.enigma.gui.ClassMatchingGui; -import cuchaz.enigma.gui.MemberMatchingGui; -import cuchaz.enigma.mapping.BehaviorEntry; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.ClassMapping; -import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.FieldMapping; -import cuchaz.enigma.mapping.MappingParseException; -import cuchaz.enigma.mapping.Mappings; -import cuchaz.enigma.mapping.MappingsChecker; -import cuchaz.enigma.mapping.MappingsReader; -import cuchaz.enigma.mapping.MappingsWriter; -import cuchaz.enigma.mapping.MethodMapping; - - -public class ConvertMain { - - public static void main(String[] args) - throws IOException, MappingParseException { - try{ - //Get all are args - String JarOld = getArg(args, 1, "Path to Old Jar", true); - String JarNew = getArg(args, 2, "Path to New Jar", true); - String OldMappings = getArg(args, 3, "Path to old .mappings file", true); - String NewMappings = getArg(args,4,"Path to new .mappings file",true); - String ClassMatches = getArg(args, 5, "Path to Class .matches file", true); - String FieldMatches = getArg(args, 6, "Path to Field .matches file", true); - String MethodMatches = getArg(args, 7, "Path to Method .matches file", true); - //OldJar - JarFile sourceJar = new JarFile(new File(JarOld)); - //NewJar - JarFile destJar = new JarFile(new File(JarNew)); - //Get the mapping files - File inMappingsFile = new File(OldMappings); - File outMappingsFile = new File(NewMappings); - Mappings mappings = new MappingsReader().read(new FileReader(inMappingsFile)); - //Make the Match Files.. - File classMatchesFile = new File(ClassMatches); - File fieldMatchesFile = new File(FieldMatches); - File methodMatchesFile = new File(MethodMatches); - - String command = getArg(args, 0, "command", true); - - if(command.equalsIgnoreCase("computeClassMatches")){ - computeClassMatches(classMatchesFile, sourceJar, destJar, mappings); - convertMappings(outMappingsFile, sourceJar, destJar, mappings, classMatchesFile); - }else if(command.equalsIgnoreCase("editClassMatches")){ - editClasssMatches(classMatchesFile, sourceJar, destJar, mappings); - convertMappings(outMappingsFile, sourceJar, destJar, mappings, classMatchesFile); - }else if(command.equalsIgnoreCase("computeFieldMatches")){ - computeFieldMatches(fieldMatchesFile, destJar, outMappingsFile, classMatchesFile); - convertMappings(outMappingsFile, sourceJar, destJar, mappings, classMatchesFile, fieldMatchesFile); - }else if(command.equalsIgnoreCase("editFieldMatches")){ - editFieldMatches(sourceJar, destJar, outMappingsFile, mappings, classMatchesFile, fieldMatchesFile); - convertMappings(outMappingsFile, sourceJar, destJar, mappings, classMatchesFile, fieldMatchesFile); - }else if(command.equalsIgnoreCase("computeMethodMatches")){ - computeMethodMatches(methodMatchesFile, destJar, outMappingsFile, classMatchesFile); - convertMappings(outMappingsFile, sourceJar, destJar, mappings, classMatchesFile, fieldMatchesFile, methodMatchesFile); - }else if(command.equalsIgnoreCase("editMethodMatches")){ - editMethodMatches(sourceJar, destJar, outMappingsFile, mappings, classMatchesFile, methodMatchesFile); - convertMappings(outMappingsFile, sourceJar, destJar, mappings, classMatchesFile, fieldMatchesFile, methodMatchesFile); - }else if(command.equalsIgnoreCase("convertMappings")){ - convertMappings(outMappingsFile, sourceJar, destJar, mappings, classMatchesFile, fieldMatchesFile, methodMatchesFile); - } - }catch (IllegalArgumentException ex) { - System.out.println(ex.getMessage()); - printHelp(); - } - } - - private static void printHelp() { - System.out.println(String.format("%s - %s", Constants.Name, Constants.Version)); - System.out.println("Usage:"); - System.out.println("\tjava -cp enigma.jar cuchaz.enigma.ConvertMain "); - System.out.println("\tWhere is one of:"); - System.out.println("\t\tcomputeClassMatches"); - System.out.println("\t\teditClassMatches"); - System.out.println("\t\tcomputeFieldMatches"); - System.out.println("\t\teditFieldMatches"); - System.out.println("\t\teditMethodMatches"); - System.out.println("\t\tconvertMappings"); - System.out.println("\tWhere is the already mapped jar."); - System.out.println("\tWhere is the unmapped jar."); - System.out.println("\tWhere is the path to the mappings for the old jar."); - System.out.println("\tWhere is the new mappings. (Where you want to save them and there name)"); - System.out.println("\tWhere is the class matches file."); - System.out.println("\tWhere is the field matches file."); - System.out.println("\tWhere is the method matches file."); - } - - //Copy of getArg from CommandMain.... Should make a utils class. - private static String getArg(String[] args, int i, String name, boolean required) { - if (i >= args.length) { - if (required) { - throw new IllegalArgumentException(name + " is required"); - } else { - return null; - } - } - return args[i]; - } - - private static void computeClassMatches(File classMatchesFile, JarFile sourceJar, JarFile destJar, Mappings mappings) - throws IOException { - ClassMatches classMatches = MappingsConverter.computeClassMatches(sourceJar, destJar, mappings); - MatchesWriter.writeClasses(classMatches, classMatchesFile); - System.out.println("Wrote:\n\t" + classMatchesFile.getAbsolutePath()); - } - - private static void editClasssMatches(final File classMatchesFile, JarFile sourceJar, JarFile destJar, Mappings mappings) - throws IOException { - System.out.println("Reading class matches..."); - ClassMatches classMatches = MatchesReader.readClasses(classMatchesFile); - Deobfuscators deobfuscators = new Deobfuscators(sourceJar, destJar); - deobfuscators.source.setMappings(mappings); - System.out.println("Starting GUI..."); - new ClassMatchingGui(classMatches, deobfuscators.source, deobfuscators.dest).setSaveListener(new ClassMatchingGui.SaveListener() { - @Override - public void save(ClassMatches matches) { - try { - MatchesWriter.writeClasses(matches, classMatchesFile); - } catch (IOException ex) { - throw new Error(ex); - } - } - }); - } - - @SuppressWarnings("unused") - private static void convertMappings(File outMappingsFile, JarFile sourceJar, JarFile destJar, Mappings mappings, File classMatchesFile) - throws IOException { - System.out.println("Reading class matches..."); - ClassMatches classMatches = MatchesReader.readClasses(classMatchesFile); - Deobfuscators deobfuscators = new Deobfuscators(sourceJar, destJar); - deobfuscators.source.setMappings(mappings); - - Mappings newMappings = MappingsConverter.newMappings(classMatches, mappings, deobfuscators.source, deobfuscators.dest); - - try (FileWriter out = new FileWriter(outMappingsFile)) { - new MappingsWriter().write(out, newMappings); - } - System.out.println("Write converted mappings to: " + outMappingsFile.getAbsolutePath()); - } - - private static void computeFieldMatches(File memberMatchesFile, JarFile destJar, File destMappingsFile, File classMatchesFile) - throws IOException, MappingParseException { - - System.out.println("Reading class matches..."); - ClassMatches classMatches = MatchesReader.readClasses(classMatchesFile); - System.out.println("Reading mappings..."); - Mappings destMappings = new MappingsReader().read(new FileReader(destMappingsFile)); - System.out.println("Indexing dest jar..."); - Deobfuscator destDeobfuscator = new Deobfuscator(destJar); - - System.out.println("Writing matches..."); - - // get the matched and unmatched mappings - MemberMatches fieldMatches = MappingsConverter.computeMemberMatches( - destDeobfuscator, - destMappings, - classMatches, - MappingsConverter.getFieldDoer() - ); - - MatchesWriter.writeMembers(fieldMatches, memberMatchesFile); - System.out.println("Wrote:\n\t" + memberMatchesFile.getAbsolutePath()); - } - - private static void editFieldMatches(JarFile sourceJar, JarFile destJar, File destMappingsFile, Mappings sourceMappings, File classMatchesFile, final File fieldMatchesFile) - throws IOException, MappingParseException { - - System.out.println("Reading matches..."); - ClassMatches classMatches = MatchesReader.readClasses(classMatchesFile); - MemberMatches fieldMatches = MatchesReader.readMembers(fieldMatchesFile); - - // prep deobfuscators - Deobfuscators deobfuscators = new Deobfuscators(sourceJar, destJar); - deobfuscators.source.setMappings(sourceMappings); - Mappings destMappings = new MappingsReader().read(new FileReader(destMappingsFile)); - MappingsChecker checker = new MappingsChecker(deobfuscators.dest.getJarIndex()); - checker.dropBrokenMappings(destMappings); - deobfuscators.dest.setMappings(destMappings); - - new MemberMatchingGui(classMatches, fieldMatches, deobfuscators.source, deobfuscators.dest).setSaveListener(new MemberMatchingGui.SaveListener() { - @Override - public void save(MemberMatches matches) { - try { - MatchesWriter.writeMembers(matches, fieldMatchesFile); - } catch (IOException ex) { - throw new Error(ex); - } - } - }); - } - - @SuppressWarnings("unused") - private static void convertMappings(File outMappingsFile, JarFile sourceJar, JarFile destJar, Mappings mappings, File classMatchesFile, File fieldMatchesFile) - throws IOException { - - System.out.println("Reading matches..."); - ClassMatches classMatches = MatchesReader.readClasses(classMatchesFile); - MemberMatches fieldMatches = MatchesReader.readMembers(fieldMatchesFile); - - Deobfuscators deobfuscators = new Deobfuscators(sourceJar, destJar); - deobfuscators.source.setMappings(mappings); - - // apply matches - Mappings newMappings = MappingsConverter.newMappings(classMatches, mappings, deobfuscators.source, deobfuscators.dest); - MappingsConverter.applyMemberMatches(newMappings, classMatches, fieldMatches, MappingsConverter.getFieldDoer()); - - // write out the converted mappings - try (FileWriter out = new FileWriter(outMappingsFile)) { - new MappingsWriter().write(out, newMappings); - } - System.out.println("Wrote converted mappings to:\n\t" + outMappingsFile.getAbsolutePath()); - } - - - private static void computeMethodMatches(File methodMatchesFile, JarFile destJar, File destMappingsFile, File classMatchesFile) - throws IOException, MappingParseException { - - System.out.println("Reading class matches..."); - ClassMatches classMatches = MatchesReader.readClasses(classMatchesFile); - System.out.println("Reading mappings..."); - Mappings destMappings = new MappingsReader().read(new FileReader(destMappingsFile)); - System.out.println("Indexing dest jar..."); - Deobfuscator destDeobfuscator = new Deobfuscator(destJar); - - System.out.println("Writing method matches..."); - - // get the matched and unmatched mappings - MemberMatches methodMatches = MappingsConverter.computeMemberMatches( - destDeobfuscator, - destMappings, - classMatches, - MappingsConverter.getMethodDoer() - ); - - MatchesWriter.writeMembers(methodMatches, methodMatchesFile); - System.out.println("Wrote:\n\t" + methodMatchesFile.getAbsolutePath()); - } - - private static void editMethodMatches(JarFile sourceJar, JarFile destJar, File destMappingsFile, Mappings sourceMappings, File classMatchesFile, final File methodMatchesFile) - throws IOException, MappingParseException { - - System.out.println("Reading matches..."); - ClassMatches classMatches = MatchesReader.readClasses(classMatchesFile); - MemberMatches methodMatches = MatchesReader.readMembers(methodMatchesFile); - - // prep deobfuscators - Deobfuscators deobfuscators = new Deobfuscators(sourceJar, destJar); - deobfuscators.source.setMappings(sourceMappings); - Mappings destMappings = new MappingsReader().read(new FileReader(destMappingsFile)); - MappingsChecker checker = new MappingsChecker(deobfuscators.dest.getJarIndex()); - checker.dropBrokenMappings(destMappings); - deobfuscators.dest.setMappings(destMappings); - - new MemberMatchingGui(classMatches, methodMatches, deobfuscators.source, deobfuscators.dest).setSaveListener(new MemberMatchingGui.SaveListener() { - @Override - public void save(MemberMatches matches) { - try { - MatchesWriter.writeMembers(matches, methodMatchesFile); - } catch (IOException ex) { - throw new Error(ex); - } - } - }); - } - - private static void convertMappings(File outMappingsFile, JarFile sourceJar, JarFile destJar, Mappings mappings, File classMatchesFile, File fieldMatchesFile, File methodMatchesFile) - throws IOException { - - System.out.println("Reading matches..."); - ClassMatches classMatches = MatchesReader.readClasses(classMatchesFile); - MemberMatches fieldMatches = MatchesReader.readMembers(fieldMatchesFile); - MemberMatches methodMatches = MatchesReader.readMembers(methodMatchesFile); - - Deobfuscators deobfuscators = new Deobfuscators(sourceJar, destJar); - deobfuscators.source.setMappings(mappings); - - // apply matches - Mappings newMappings = MappingsConverter.newMappings(classMatches, mappings, deobfuscators.source, deobfuscators.dest); - MappingsConverter.applyMemberMatches(newMappings, classMatches, fieldMatches, MappingsConverter.getFieldDoer()); - MappingsConverter.applyMemberMatches(newMappings, classMatches, methodMatches, MappingsConverter.getMethodDoer()); - - // check the final mappings - MappingsChecker checker = new MappingsChecker(deobfuscators.dest.getJarIndex()); - checker.dropBrokenMappings(newMappings); - - for (java.util.Map.Entry mapping : checker.getDroppedClassMappings().entrySet()) { - System.out.println("WARNING: Broken class entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ")"); - } - for (java.util.Map.Entry mapping : checker.getDroppedInnerClassMappings().entrySet()) { - System.out.println("WARNING: Broken inner class entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ")"); - } - for (java.util.Map.Entry mapping : checker.getDroppedFieldMappings().entrySet()) { - System.out.println("WARNING: Broken field entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ")"); - } - for (java.util.Map.Entry mapping : checker.getDroppedMethodMappings().entrySet()) { - System.out.println("WARNING: Broken behavior entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ")"); - } - - // write out the converted mappings - try (FileWriter out = new FileWriter(outMappingsFile)) { - new MappingsWriter().write(out, newMappings); - } - System.out.println("Wrote converted mappings to:\n\t" + outMappingsFile.getAbsolutePath()); - } - - private static class Deobfuscators { - - public Deobfuscator source; - public Deobfuscator dest; - - public Deobfuscators(JarFile sourceJar, JarFile destJar) { - System.out.println("Indexing source jar..."); - IndexerThread sourceIndexer = new IndexerThread(sourceJar); - sourceIndexer.start(); - System.out.println("Indexing dest jar..."); - IndexerThread destIndexer = new IndexerThread(destJar); - destIndexer.start(); - sourceIndexer.joinOrBail(); - destIndexer.joinOrBail(); - source = sourceIndexer.deobfuscator; - dest = destIndexer.deobfuscator; - } - } - - private static class IndexerThread extends Thread { - - private JarFile m_jarFile; - public Deobfuscator deobfuscator; - - public IndexerThread(JarFile jarFile) { - m_jarFile = jarFile; - deobfuscator = null; - } - - public void joinOrBail() { - try { - join(); - } catch (InterruptedException ex) { - throw new Error(ex); - } - } - - @Override - public void run() { - try { - deobfuscator = new Deobfuscator(m_jarFile); - } catch (IOException ex) { - throw new Error(ex); - } - } - } -} \ No newline at end of file diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java deleted file mode 100644 index 82d1611b..00000000 --- a/src/cuchaz/enigma/Deobfuscator.java +++ /dev/null @@ -1,551 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.FileWriter; -import java.io.IOException; -import java.io.StringWriter; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.jar.JarOutputStream; - -import javassist.CtClass; -import javassist.bytecode.Descriptor; - -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.strobel.assembler.metadata.MetadataSystem; -import com.strobel.assembler.metadata.TypeDefinition; -import com.strobel.assembler.metadata.TypeReference; -import com.strobel.decompiler.DecompilerContext; -import com.strobel.decompiler.DecompilerSettings; -import com.strobel.decompiler.PlainTextOutput; -import com.strobel.decompiler.languages.java.JavaOutputVisitor; -import com.strobel.decompiler.languages.java.ast.AstBuilder; -import com.strobel.decompiler.languages.java.ast.CompilationUnit; -import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor; - -import cuchaz.enigma.analysis.EntryReference; -import cuchaz.enigma.analysis.JarClassIterator; -import cuchaz.enigma.analysis.JarIndex; -import cuchaz.enigma.analysis.SourceIndex; -import cuchaz.enigma.analysis.SourceIndexVisitor; -import cuchaz.enigma.analysis.Token; -import cuchaz.enigma.bytecode.ClassProtectifier; -import cuchaz.enigma.bytecode.ClassPublifier; -import cuchaz.enigma.mapping.ArgumentEntry; -import cuchaz.enigma.mapping.BehaviorEntry; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.ClassMapping; -import cuchaz.enigma.mapping.ConstructorEntry; -import cuchaz.enigma.mapping.Entry; -import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.FieldMapping; -import cuchaz.enigma.mapping.Mappings; -import cuchaz.enigma.mapping.MappingsChecker; -import cuchaz.enigma.mapping.MappingsRenamer; -import cuchaz.enigma.mapping.MethodEntry; -import cuchaz.enigma.mapping.MethodMapping; -import cuchaz.enigma.mapping.TranslationDirection; -import cuchaz.enigma.mapping.Translator; - -public class Deobfuscator { - - public interface ProgressListener { - void init(int totalWork, String title); - void onProgress(int numDone, String message); - } - - private JarFile m_jar; - private DecompilerSettings m_settings; - private JarIndex m_jarIndex; - private Mappings m_mappings; - private MappingsRenamer m_renamer; - private Map m_translatorCache; - - public Deobfuscator(JarFile jar) throws IOException { - m_jar = jar; - - // build the jar index - m_jarIndex = new JarIndex(); - m_jarIndex.indexJar(m_jar, true); - - // config the decompiler - m_settings = DecompilerSettings.javaDefaults(); - m_settings.setMergeVariables(true); - m_settings.setForceExplicitImports(true); - m_settings.setForceExplicitTypeArguments(true); - m_settings.setShowDebugLineNumbers(true); - // DEBUG - //m_settings.setShowSyntheticMembers(true); - - // init defaults - m_translatorCache = Maps.newTreeMap(); - - // init mappings - setMappings(new Mappings()); - } - - public JarFile getJar() { - return m_jar; - } - - public String getJarName() { - return m_jar.getName(); - } - - public JarIndex getJarIndex() { - return m_jarIndex; - } - - public Mappings getMappings() { - return m_mappings; - } - - public void setMappings(Mappings val) { - setMappings(val, true); - } - - public void setMappings(Mappings val, boolean warnAboutDrops) { - if (val == null) { - val = new Mappings(); - } - - // drop mappings that don't match the jar - MappingsChecker checker = new MappingsChecker(m_jarIndex); - checker.dropBrokenMappings(val); - if (warnAboutDrops) { - for (java.util.Map.Entry mapping : checker.getDroppedClassMappings().entrySet()) { - System.out.println("WARNING: Couldn't find class entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); - } - for (java.util.Map.Entry mapping : checker.getDroppedInnerClassMappings().entrySet()) { - System.out.println("WARNING: Couldn't find inner class entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); - } - for (java.util.Map.Entry mapping : checker.getDroppedFieldMappings().entrySet()) { - System.out.println("WARNING: Couldn't find field entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); - } - for (java.util.Map.Entry mapping : checker.getDroppedMethodMappings().entrySet()) { - System.out.println("WARNING: Couldn't find behavior entry " + mapping.getKey() + " (" + mapping.getValue().getDeobfName() + ") in jar. Mapping was dropped."); - } - } - - // check for related method inconsistencies - if (checker.getRelatedMethodChecker().hasProblems()) { - throw new Error("Related methods are inconsistent! Need to fix the mappings manually.\n" + checker.getRelatedMethodChecker().getReport()); - } - - m_mappings = val; - m_renamer = new MappingsRenamer(m_jarIndex, val); - m_translatorCache.clear(); - } - - public Translator getTranslator(TranslationDirection direction) { - Translator translator = m_translatorCache.get(direction); - if (translator == null) { - translator = m_mappings.getTranslator(direction, m_jarIndex.getTranslationIndex()); - m_translatorCache.put(direction, translator); - } - return translator; - } - - public void getSeparatedClasses(List obfClasses, List deobfClasses) { - for (ClassEntry obfClassEntry : m_jarIndex.getObfClassEntries()) { - // skip inner classes - if (obfClassEntry.isInnerClass()) { - continue; - } - - // separate the classes - ClassEntry deobfClassEntry = deobfuscateEntry(obfClassEntry); - if (!deobfClassEntry.equals(obfClassEntry)) { - // if the class has a mapping, clearly it's deobfuscated - deobfClasses.add(deobfClassEntry); - } else if (!obfClassEntry.getPackageName().equals(Constants.NonePackage)) { - // also call it deobufscated if it's not in the none package - deobfClasses.add(obfClassEntry); - } else { - // otherwise, assume it's still obfuscated - obfClasses.add(obfClassEntry); - } - } - } - - public CompilationUnit getSourceTree(String className) { - - // we don't know if this class name is obfuscated or deobfuscated - // we need to tell the decompiler the deobfuscated name so it doesn't get freaked out - // the decompiler only sees classes after deobfuscation, so we need to load it by the deobfuscated name if there is one - - // first, assume class name is deobf - String deobfClassName = className; - - // if it wasn't actually deobf, then we can find a mapping for it and get the deobf name - ClassMapping classMapping = m_mappings.getClassByObf(className); - if (classMapping != null && classMapping.getDeobfName() != null) { - deobfClassName = classMapping.getDeobfName(); - } - - // set the type loader - TranslatingTypeLoader loader = new TranslatingTypeLoader( - m_jar, - m_jarIndex, - getTranslator(TranslationDirection.Obfuscating), - getTranslator(TranslationDirection.Deobfuscating) - ); - m_settings.setTypeLoader(loader); - - // see if procyon can find the type - TypeReference type = new MetadataSystem(loader).lookupType(deobfClassName); - if (type == null) { - throw new Error(String.format("Unable to find type: %s (deobf: %s)\nTried class names: %s", - className, deobfClassName, loader.getClassNamesToTry(deobfClassName) - )); - } - TypeDefinition resolvedType = type.resolve(); - - // decompile it! - DecompilerContext context = new DecompilerContext(); - context.setCurrentType(resolvedType); - context.setSettings(m_settings); - AstBuilder builder = new AstBuilder(context); - builder.addType(resolvedType); - builder.runTransformations(null); - return builder.getCompilationUnit(); - } - - public SourceIndex getSourceIndex(CompilationUnit sourceTree, String source) { - return getSourceIndex(sourceTree, source, null); - } - - public SourceIndex getSourceIndex(CompilationUnit sourceTree, String source, Boolean ignoreBadTokens) { - - // build the source index - SourceIndex index; - if (ignoreBadTokens != null) { - index = new SourceIndex(source, ignoreBadTokens); - } else { - index = new SourceIndex(source); - } - sourceTree.acceptVisitor(new SourceIndexVisitor(), index); - - // DEBUG - // sourceTree.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); - - // resolve all the classes in the source references - for (Token token : index.referenceTokens()) { - EntryReference deobfReference = index.getDeobfReference(token); - - // get the obfuscated entry - Entry obfEntry = obfuscateEntry(deobfReference.entry); - - // try to resolve the class - ClassEntry resolvedObfClassEntry = m_jarIndex.getTranslationIndex().resolveEntryClass(obfEntry); - if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(obfEntry.getClassEntry())) { - // change the class of the entry - obfEntry = obfEntry.cloneToNewClass(resolvedObfClassEntry); - - // save the new deobfuscated reference - deobfReference.entry = deobfuscateEntry(obfEntry); - index.replaceDeobfReference(token, deobfReference); - } - - // DEBUG - // System.out.println( token + " -> " + reference + " -> " + index.getReferenceToken( reference ) ); - } - - return index; - } - - public String getSource(CompilationUnit sourceTree) { - // render the AST into source - StringWriter buf = new StringWriter(); - sourceTree.acceptVisitor(new InsertParenthesesVisitor(), null); - sourceTree.acceptVisitor(new JavaOutputVisitor(new PlainTextOutput(buf), m_settings), null); - return buf.toString(); - } - - public void writeSources(File dirOut, ProgressListener progress) throws IOException { - // get the classes to decompile - Set classEntries = Sets.newHashSet(); - for (ClassEntry obfClassEntry : m_jarIndex.getObfClassEntries()) { - // skip inner classes - if (obfClassEntry.isInnerClass()) { - continue; - } - - classEntries.add(obfClassEntry); - } - - if (progress != null) { - progress.init(classEntries.size(), "Decompiling classes..."); - } - - // DEOBFUSCATE ALL THE THINGS!! @_@ - int i = 0; - for (ClassEntry obfClassEntry : classEntries) { - ClassEntry deobfClassEntry = deobfuscateEntry(new ClassEntry(obfClassEntry)); - if (progress != null) { - progress.onProgress(i++, deobfClassEntry.toString()); - } - - try { - // get the source - String source = getSource(getSourceTree(obfClassEntry.getName())); - - // write the file - File file = new File(dirOut, deobfClassEntry.getName().replace('.', '/') + ".java"); - file.getParentFile().mkdirs(); - try (FileWriter out = new FileWriter(file)) { - out.write(source); - } - } catch (Throwable t) { - // don't crash the whole world here, just log the error and keep going - // TODO: set up logback via log4j - System.err.println("Unable to deobfuscate class " + deobfClassEntry.toString() + " (" + obfClassEntry.toString() + ")"); - t.printStackTrace(System.err); - } - } - if (progress != null) { - progress.onProgress(i, "Done!"); - } - } - - public void writeJar(File out, ProgressListener progress) { - final TranslatingTypeLoader loader = new TranslatingTypeLoader( - m_jar, - m_jarIndex, - getTranslator(TranslationDirection.Obfuscating), - getTranslator(TranslationDirection.Deobfuscating) - ); - transformJar(out, progress, new ClassTransformer() { - - @Override - public CtClass transform(CtClass c) throws Exception { - return loader.transformClass(c); - } - }); - } - - public void protectifyJar(File out, ProgressListener progress) { - transformJar(out, progress, new ClassTransformer() { - - @Override - public CtClass transform(CtClass c) throws Exception { - return ClassProtectifier.protectify(c); - } - }); - } - - public void publifyJar(File out, ProgressListener progress) { - transformJar(out, progress, new ClassTransformer() { - - @Override - public CtClass transform(CtClass c) throws Exception { - return ClassPublifier.publify(c); - } - }); - } - - private interface ClassTransformer { - public CtClass transform(CtClass c) throws Exception; - } - private void transformJar(File out, ProgressListener progress, ClassTransformer transformer) { - try (JarOutputStream outJar = new JarOutputStream(new FileOutputStream(out))) { - if (progress != null) { - progress.init(JarClassIterator.getClassEntries(m_jar).size(), "Transforming classes..."); - } - - int i = 0; - for (CtClass c : JarClassIterator.classes(m_jar)) { - if (progress != null) { - progress.onProgress(i++, c.getName()); - } - - try { - c = transformer.transform(c); - outJar.putNextEntry(new JarEntry(c.getName().replace('.', '/') + ".class")); - outJar.write(c.toBytecode()); - outJar.closeEntry(); - } catch (Throwable t) { - throw new Error("Unable to transform class " + c.getName(), t); - } - } - if (progress != null) { - progress.onProgress(i, "Done!"); - } - - outJar.close(); - } catch (IOException ex) { - throw new Error("Unable to write to Jar file!"); - } - } - - public T obfuscateEntry(T deobfEntry) { - if (deobfEntry == null) { - return null; - } - return getTranslator(TranslationDirection.Obfuscating).translateEntry(deobfEntry); - } - - public T deobfuscateEntry(T obfEntry) { - if (obfEntry == null) { - return null; - } - return getTranslator(TranslationDirection.Deobfuscating).translateEntry(obfEntry); - } - - public EntryReference obfuscateReference(EntryReference deobfReference) { - if (deobfReference == null) { - return null; - } - return new EntryReference( - obfuscateEntry(deobfReference.entry), - obfuscateEntry(deobfReference.context), - deobfReference - ); - } - - public EntryReference deobfuscateReference(EntryReference obfReference) { - if (obfReference == null) { - return null; - } - return new EntryReference( - deobfuscateEntry(obfReference.entry), - deobfuscateEntry(obfReference.context), - obfReference - ); - } - - public boolean isObfuscatedIdentifier(Entry obfEntry) { - - if (obfEntry instanceof MethodEntry) { - - // HACKHACK: Object methods are not obfuscated identifiers - MethodEntry obfMethodEntry = (MethodEntry)obfEntry; - String name = obfMethodEntry.getName(); - String sig = obfMethodEntry.getSignature().toString(); - if (name.equals("clone") && sig.equals("()Ljava/lang/Object;")) { - return false; - } else if (name.equals("equals") && sig.equals("(Ljava/lang/Object;)Z")) { - return false; - } else if (name.equals("finalize") && sig.equals("()V")) { - return false; - } else if (name.equals("getClass") && sig.equals("()Ljava/lang/Class;")) { - return false; - } else if (name.equals("hashCode") && sig.equals("()I")) { - return false; - } else if (name.equals("notify") && sig.equals("()V")) { - return false; - } else if (name.equals("notifyAll") && sig.equals("()V")) { - return false; - } else if (name.equals("toString") && sig.equals("()Ljava/lang/String;")) { - return false; - } else if (name.equals("wait") && sig.equals("()V")) { - return false; - } else if (name.equals("wait") && sig.equals("(J)V")) { - return false; - } else if (name.equals("wait") && sig.equals("(JI)V")) { - return false; - } - } - - return m_jarIndex.containsObfEntry(obfEntry); - } - - public boolean isRenameable(EntryReference obfReference) { - return obfReference.isNamed() && isObfuscatedIdentifier(obfReference.getNameableEntry()); - } - - // NOTE: these methods are a bit messy... oh well - - public boolean hasDeobfuscatedName(Entry obfEntry) { - Translator translator = getTranslator(TranslationDirection.Deobfuscating); - if (obfEntry instanceof ClassEntry) { - ClassEntry obfClass = (ClassEntry)obfEntry; - List mappingChain = m_mappings.getClassMappingChain(obfClass); - ClassMapping classMapping = mappingChain.get(mappingChain.size() - 1); - return classMapping != null && classMapping.getDeobfName() != null; - } else if (obfEntry instanceof FieldEntry) { - return translator.translate((FieldEntry)obfEntry) != null; - } else if (obfEntry instanceof MethodEntry) { - return translator.translate((MethodEntry)obfEntry) != null; - } else if (obfEntry instanceof ConstructorEntry) { - // constructors have no names - return false; - } else if (obfEntry instanceof ArgumentEntry) { - return translator.translate((ArgumentEntry)obfEntry) != null; - } else { - throw new Error("Unknown entry type: " + obfEntry.getClass().getName()); - } - } - - public void rename(Entry obfEntry, String newName) { - if (obfEntry instanceof ClassEntry) { - m_renamer.setClassName((ClassEntry)obfEntry, Descriptor.toJvmName(newName)); - } else if (obfEntry instanceof FieldEntry) { - m_renamer.setFieldName((FieldEntry)obfEntry, newName); - } else if (obfEntry instanceof MethodEntry) { - m_renamer.setMethodTreeName((MethodEntry)obfEntry, newName); - } else if (obfEntry instanceof ConstructorEntry) { - throw new IllegalArgumentException("Cannot rename constructors"); - } else if (obfEntry instanceof ArgumentEntry) { - m_renamer.setArgumentName((ArgumentEntry)obfEntry, newName); - } else { - throw new Error("Unknown entry type: " + obfEntry.getClass().getName()); - } - - // clear caches - m_translatorCache.clear(); - } - - public void removeMapping(Entry obfEntry) { - if (obfEntry instanceof ClassEntry) { - m_renamer.removeClassMapping((ClassEntry)obfEntry); - } else if (obfEntry instanceof FieldEntry) { - m_renamer.removeFieldMapping((FieldEntry)obfEntry); - } else if (obfEntry instanceof MethodEntry) { - m_renamer.removeMethodTreeMapping((MethodEntry)obfEntry); - } else if (obfEntry instanceof ConstructorEntry) { - throw new IllegalArgumentException("Cannot rename constructors"); - } else if (obfEntry instanceof ArgumentEntry) { - m_renamer.removeArgumentMapping((ArgumentEntry)obfEntry); - } else { - throw new Error("Unknown entry type: " + obfEntry); - } - - // clear caches - m_translatorCache.clear(); - } - - public void markAsDeobfuscated(Entry obfEntry) { - if (obfEntry instanceof ClassEntry) { - m_renamer.markClassAsDeobfuscated((ClassEntry)obfEntry); - } else if (obfEntry instanceof FieldEntry) { - m_renamer.markFieldAsDeobfuscated((FieldEntry)obfEntry); - } else if (obfEntry instanceof MethodEntry) { - m_renamer.markMethodTreeAsDeobfuscated((MethodEntry)obfEntry); - } else if (obfEntry instanceof ConstructorEntry) { - throw new IllegalArgumentException("Cannot rename constructors"); - } else if (obfEntry instanceof ArgumentEntry) { - m_renamer.markArgumentAsDeobfuscated((ArgumentEntry)obfEntry); - } else { - throw new Error("Unknown entry type: " + obfEntry); - } - - // clear caches - m_translatorCache.clear(); - } -} diff --git a/src/cuchaz/enigma/ExceptionIgnorer.java b/src/cuchaz/enigma/ExceptionIgnorer.java deleted file mode 100644 index d8726d13..00000000 --- a/src/cuchaz/enigma/ExceptionIgnorer.java +++ /dev/null @@ -1,34 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma; - -public class ExceptionIgnorer { - - public static boolean shouldIgnore(Throwable t) { - - // is this that pesky concurrent access bug in the highlight painter system? - // (ancient ui code is ancient) - if (t instanceof ArrayIndexOutOfBoundsException) { - StackTraceElement[] stackTrace = t.getStackTrace(); - if (stackTrace.length > 1) { - - // does this stack frame match javax.swing.text.DefaultHighlighter.paint*() ? - StackTraceElement frame = stackTrace[1]; - if (frame.getClassName().equals("javax.swing.text.DefaultHighlighter") && frame.getMethodName().startsWith("paint")) { - return true; - } - } - } - - return false; - } - -} diff --git a/src/cuchaz/enigma/Main.java b/src/cuchaz/enigma/Main.java deleted file mode 100644 index 4842a795..00000000 --- a/src/cuchaz/enigma/Main.java +++ /dev/null @@ -1,51 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma; - -import java.io.File; -import java.util.jar.JarFile; - -import cuchaz.enigma.gui.Gui; - -public class Main { - - public static void main(String[] args) throws Exception { - Gui gui = new Gui(); - - // parse command-line args - if (args.length >= 1) { - gui.getController().openJar(new JarFile(getFile(args[0]))); - } - if (args.length >= 2) { - gui.getController().openMappings(getFile(args[1])); - } - - // DEBUG - //gui.getController().openDeclaration(new ClassEntry("none/bxq")); - } - - private static File getFile(String path) { - // expand ~ to the home dir - if (path.startsWith("~")) { - // get the home dir - File dirHome = new File(System.getProperty("user.home")); - - // is the path just ~/ or is it ~user/ ? - if (path.startsWith("~/")) { - return new File(dirHome, path.substring(2)); - } else { - return new File(dirHome.getParentFile(), path.substring(1)); - } - } - - return new File(path); - } -} diff --git a/src/cuchaz/enigma/MainFormatConverter.java b/src/cuchaz/enigma/MainFormatConverter.java deleted file mode 100644 index 73ee41f4..00000000 --- a/src/cuchaz/enigma/MainFormatConverter.java +++ /dev/null @@ -1,130 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma; - -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.lang.reflect.Field; -import java.util.Map; -import java.util.jar.JarFile; - -import javassist.CtClass; -import javassist.CtField; - -import com.google.common.collect.Maps; - -import cuchaz.enigma.analysis.JarClassIterator; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.ClassMapping; -import cuchaz.enigma.mapping.ClassNameReplacer; -import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.FieldMapping; -import cuchaz.enigma.mapping.EntryFactory; -import cuchaz.enigma.mapping.Mappings; -import cuchaz.enigma.mapping.MappingsReader; -import cuchaz.enigma.mapping.MappingsWriter; -import cuchaz.enigma.mapping.Type; - -public class MainFormatConverter { - - public static void main(String[] args) - throws Exception { - - System.out.println("Getting field types from jar..."); - - JarFile jar = new JarFile(System.getProperty("user.home") + "/.minecraft/versions/1.8/1.8.jar"); - Map fieldTypes = Maps.newHashMap(); - for (CtClass c : JarClassIterator.classes(jar)) { - for (CtField field : c.getDeclaredFields()) { - FieldEntry fieldEntry = EntryFactory.getFieldEntry(field); - fieldTypes.put(getFieldKey(fieldEntry), moveClasssesOutOfDefaultPackage(fieldEntry.getType())); - } - } - - System.out.println("Reading mappings..."); - - File fileMappings = new File("../Enigma Mappings/1.8.mappings"); - MappingsReader mappingsReader = new MappingsReader() { - - @Override - protected FieldMapping readField(String[] parts) { - // assume the void type for now - return new FieldMapping(parts[1], new Type("V"), parts[2]); - } - }; - Mappings mappings = mappingsReader.read(new FileReader(fileMappings)); - - System.out.println("Updating field types..."); - - for (ClassMapping classMapping : mappings.classes()) { - updateFieldsInClass(fieldTypes, classMapping); - } - - System.out.println("Saving mappings..."); - - try (FileWriter writer = new FileWriter(fileMappings)) { - new MappingsWriter().write(writer, mappings); - } - - System.out.println("Done!"); - } - - private static Type moveClasssesOutOfDefaultPackage(Type type) { - return new Type(type, new ClassNameReplacer() { - @Override - public String replace(String className) { - ClassEntry entry = new ClassEntry(className); - if (entry.isInDefaultPackage()) { - return Constants.NonePackage + "/" + className; - } - return null; - } - }); - } - - private static void updateFieldsInClass(Map fieldTypes, ClassMapping classMapping) - throws Exception { - - // update the fields - for (FieldMapping fieldMapping : classMapping.fields()) { - setFieldType(fieldTypes, classMapping, fieldMapping); - } - - // recurse - for (ClassMapping innerClassMapping : classMapping.innerClasses()) { - updateFieldsInClass(fieldTypes, innerClassMapping); - } - } - - private static void setFieldType(Map fieldTypes, ClassMapping classMapping, FieldMapping fieldMapping) - throws Exception { - - // get the new type - Type newType = fieldTypes.get(getFieldKey(classMapping, fieldMapping)); - if (newType == null) { - throw new Error("Can't find type for field: " + getFieldKey(classMapping, fieldMapping)); - } - - // hack in the new field type - Field field = fieldMapping.getClass().getDeclaredField("m_obfType"); - field.setAccessible(true); - field.set(fieldMapping, newType); - } - - private static Object getFieldKey(ClassMapping classMapping, FieldMapping fieldMapping) { - return classMapping.getObfSimpleName() + "." + fieldMapping.getObfName(); - } - - private static String getFieldKey(FieldEntry obfFieldEntry) { - return obfFieldEntry.getClassEntry().getSimpleName() + "." + obfFieldEntry.getName(); - } -} diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java deleted file mode 100644 index a2185e5c..00000000 --- a/src/cuchaz/enigma/TranslatingTypeLoader.java +++ /dev/null @@ -1,249 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.List; -import java.util.Map; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; - -import javassist.ByteArrayClassPath; -import javassist.CannotCompileException; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.NotFoundException; -import javassist.bytecode.Descriptor; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.strobel.assembler.metadata.Buffer; -import com.strobel.assembler.metadata.ClasspathTypeLoader; -import com.strobel.assembler.metadata.ITypeLoader; - -import cuchaz.enigma.analysis.BridgeMarker; -import cuchaz.enigma.analysis.JarIndex; -import cuchaz.enigma.bytecode.ClassRenamer; -import cuchaz.enigma.bytecode.ClassTranslator; -import cuchaz.enigma.bytecode.InnerClassWriter; -import cuchaz.enigma.bytecode.LocalVariableRenamer; -import cuchaz.enigma.bytecode.MethodParameterWriter; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.Translator; - -public class TranslatingTypeLoader implements ITypeLoader { - - private JarFile m_jar; - private JarIndex m_jarIndex; - private Translator m_obfuscatingTranslator; - private Translator m_deobfuscatingTranslator; - private Map m_cache; - private ClasspathTypeLoader m_defaultTypeLoader; - - public TranslatingTypeLoader(JarFile jar, JarIndex jarIndex) { - this(jar, jarIndex, new Translator(), new Translator()); - } - - public TranslatingTypeLoader(JarFile jar, JarIndex jarIndex, Translator obfuscatingTranslator, Translator deobfuscatingTranslator) { - m_jar = jar; - m_jarIndex = jarIndex; - m_obfuscatingTranslator = obfuscatingTranslator; - m_deobfuscatingTranslator = deobfuscatingTranslator; - m_cache = Maps.newHashMap(); - m_defaultTypeLoader = new ClasspathTypeLoader(); - } - - public void clearCache() { - m_cache.clear(); - } - - @Override - public boolean tryLoadType(String className, Buffer out) { - - // check the cache - byte[] data; - if (m_cache.containsKey(className)) { - data = m_cache.get(className); - } else { - data = loadType(className); - m_cache.put(className, data); - } - - if (data == null) { - // chain to default type loader - return m_defaultTypeLoader.tryLoadType(className, out); - } - - // send the class to the decompiler - out.reset(data.length); - System.arraycopy(data, 0, out.array(), out.position(), data.length); - out.position(0); - return true; - } - - public CtClass loadClass(String deobfClassName) { - - byte[] data = loadType(deobfClassName); - if (data == null) { - return null; - } - - // return a javassist handle for the class - String javaClassFileName = Descriptor.toJavaName(deobfClassName); - ClassPool classPool = new ClassPool(); - classPool.insertClassPath(new ByteArrayClassPath(javaClassFileName, data)); - try { - return classPool.get(javaClassFileName); - } catch (NotFoundException ex) { - throw new Error(ex); - } - } - - private byte[] loadType(String className) { - - // NOTE: don't know if class name is obf or deobf - ClassEntry classEntry = new ClassEntry(className); - ClassEntry obfClassEntry = m_obfuscatingTranslator.translateEntry(classEntry); - - // is this an inner class referenced directly? (ie trying to load b instead of a$b) - if (!obfClassEntry.isInnerClass()) { - List classChain = m_jarIndex.getObfClassChain(obfClassEntry); - if (classChain.size() > 1) { - System.err.println(String.format("WARNING: no class %s after inner class reconstruction. Try %s", - className, obfClassEntry.buildClassEntry(classChain) - )); - return null; - } - } - - // is this a class we should even know about? - if (!m_jarIndex.containsObfClass(obfClassEntry)) { - return null; - } - - // DEBUG - //System.out.println(String.format("Looking for %s (obf: %s)", classEntry.getName(), obfClassEntry.getName())); - - // find the class in the jar - String classInJarName = findClassInJar(obfClassEntry); - if (classInJarName == null) { - // couldn't find it - return null; - } - - try { - // read the class file into a buffer - ByteArrayOutputStream data = new ByteArrayOutputStream(); - byte[] buf = new byte[1024 * 1024]; // 1 KiB - InputStream in = m_jar.getInputStream(m_jar.getJarEntry(classInJarName + ".class")); - while (true) { - int bytesRead = in.read(buf); - if (bytesRead <= 0) { - break; - } - data.write(buf, 0, bytesRead); - } - data.close(); - in.close(); - buf = data.toByteArray(); - - // load the javassist handle to the raw class - ClassPool classPool = new ClassPool(); - String classInJarJavaName = Descriptor.toJavaName(classInJarName); - classPool.insertClassPath(new ByteArrayClassPath(classInJarJavaName, buf)); - CtClass c = classPool.get(classInJarJavaName); - - c = transformClass(c); - - // sanity checking - assertClassName(c, classEntry); - - // DEBUG - //Util.writeClass( c ); - - // we have a transformed class! - return c.toBytecode(); - } catch (IOException | NotFoundException | CannotCompileException ex) { - throw new Error(ex); - } - } - - private String findClassInJar(ClassEntry obfClassEntry) { - - // try to find the class in the jar - for (String className : getClassNamesToTry(obfClassEntry)) { - JarEntry jarEntry = m_jar.getJarEntry(className + ".class"); - if (jarEntry != null) { - return className; - } - } - - // didn't find it ;_; - return null; - } - - public List getClassNamesToTry(String className) { - return getClassNamesToTry(m_obfuscatingTranslator.translateEntry(new ClassEntry(className))); - } - - public List getClassNamesToTry(ClassEntry obfClassEntry) { - List classNamesToTry = Lists.newArrayList(); - classNamesToTry.add(obfClassEntry.getName()); - if (obfClassEntry.getPackageName().equals(Constants.NonePackage)) { - // taking off the none package, if any - classNamesToTry.add(obfClassEntry.getSimpleName()); - } - if (obfClassEntry.isInnerClass()) { - // try just the inner class name - classNamesToTry.add(obfClassEntry.getInnermostClassName()); - } - return classNamesToTry; - } - - public CtClass transformClass(CtClass c) - throws IOException, NotFoundException, CannotCompileException { - - // we moved a lot of classes out of the default package into the none package - // make sure all the class references are consistent - ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); - - // reconstruct inner classes - new InnerClassWriter(m_jarIndex).write(c); - - // re-get the javassist handle since we changed class names - ClassEntry obfClassEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); - String javaClassReconstructedName = Descriptor.toJavaName(obfClassEntry.getName()); - ClassPool classPool = new ClassPool(); - classPool.insertClassPath(new ByteArrayClassPath(javaClassReconstructedName, c.toBytecode())); - c = classPool.get(javaClassReconstructedName); - - // check that the file is correct after inner class reconstruction (ie cause Javassist to fail fast if something is wrong) - assertClassName(c, obfClassEntry); - - // do all kinds of deobfuscating transformations on the class - new BridgeMarker(m_jarIndex).markBridges(c); - new MethodParameterWriter(m_deobfuscatingTranslator).writeMethodArguments(c); - new LocalVariableRenamer(m_deobfuscatingTranslator).rename(c); - new ClassTranslator(m_deobfuscatingTranslator).translate(c); - - return c; - } - - private void assertClassName(CtClass c, ClassEntry obfClassEntry) { - String name1 = Descriptor.toJvmName(c.getName()); - assert (name1.equals(obfClassEntry.getName())) : String.format("Looking for %s, instead found %s", obfClassEntry.getName(), name1); - - String name2 = Descriptor.toJvmName(c.getClassFile().getName()); - assert (name2.equals(obfClassEntry.getName())) : String.format("Looking for %s, instead found %s", obfClassEntry.getName(), name2); - } -} diff --git a/src/cuchaz/enigma/Util.java b/src/cuchaz/enigma/Util.java deleted file mode 100644 index c7e509fa..00000000 --- a/src/cuchaz/enigma/Util.java +++ /dev/null @@ -1,104 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma; - -import java.awt.Desktop; -import java.io.Closeable; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Arrays; -import java.util.jar.JarFile; - -import javassist.CannotCompileException; -import javassist.CtClass; -import javassist.bytecode.Descriptor; - -import com.google.common.io.CharStreams; - -public class Util { - - public static int combineHashesOrdered(Object... objs) { - return combineHashesOrdered(Arrays.asList(objs)); - } - - public static int combineHashesOrdered(Iterable objs) { - final int prime = 67; - int result = 1; - for (Object obj : objs) { - result *= prime; - if (obj != null) { - result += obj.hashCode(); - } - } - return result; - } - - public static void closeQuietly(Closeable closeable) { - if (closeable != null) { - try { - closeable.close(); - } catch (IOException ex) { - // just ignore any further exceptions - } - } - } - - public static void closeQuietly(JarFile jarFile) { - // silly library should implement Closeable... - if (jarFile != null) { - try { - jarFile.close(); - } catch (IOException ex) { - // just ignore any further exceptions - } - } - } - - public static String readStreamToString(InputStream in) throws IOException { - return CharStreams.toString(new InputStreamReader(in, "UTF-8")); - } - - public static String readResourceToString(String path) throws IOException { - InputStream in = Util.class.getResourceAsStream(path); - if (in == null) { - throw new IllegalArgumentException("Resource not found! " + path); - } - return readStreamToString(in); - } - - public static void openUrl(String url) { - if (Desktop.isDesktopSupported()) { - Desktop desktop = Desktop.getDesktop(); - try { - desktop.browse(new URI(url)); - } catch (IOException ex) { - throw new Error(ex); - } catch (URISyntaxException ex) { - throw new IllegalArgumentException(ex); - } - } - } - - public static void writeClass(CtClass c) { - String name = Descriptor.toJavaName(c.getName()); - File file = new File(name + ".class"); - try (FileOutputStream out = new FileOutputStream(file)) { - out.write(c.toBytecode()); - } catch (IOException | CannotCompileException ex) { - throw new Error(ex); - } - } -} diff --git a/src/cuchaz/enigma/analysis/Access.java b/src/cuchaz/enigma/analysis/Access.java deleted file mode 100644 index 1c8cfc48..00000000 --- a/src/cuchaz/enigma/analysis/Access.java +++ /dev/null @@ -1,43 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import java.lang.reflect.Modifier; - -import javassist.CtBehavior; -import javassist.CtField; - -public enum Access { - - Public, - Protected, - Private; - - public static Access get(CtBehavior behavior) { - return get(behavior.getModifiers()); - } - - public static Access get(CtField field) { - return get(field.getModifiers()); - } - - public static Access get(int modifiers) { - if (Modifier.isPublic(modifiers)) { - return Public; - } else if (Modifier.isProtected(modifiers)) { - return Protected; - } else if (Modifier.isPrivate(modifiers)) { - return Private; - } - // assume public by default - return Public; - } -} diff --git a/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java b/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java deleted file mode 100644 index 353a4bf0..00000000 --- a/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java +++ /dev/null @@ -1,93 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import java.util.Set; - -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.TreeNode; - -import com.google.common.collect.Sets; - -import cuchaz.enigma.mapping.BehaviorEntry; -import cuchaz.enigma.mapping.Entry; -import cuchaz.enigma.mapping.Translator; - -public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode { - - private static final long serialVersionUID = -3658163700783307520L; - - private Translator m_deobfuscatingTranslator; - private BehaviorEntry m_entry; - private EntryReference m_reference; - private Access m_access; - - public BehaviorReferenceTreeNode(Translator deobfuscatingTranslator, BehaviorEntry entry) { - m_deobfuscatingTranslator = deobfuscatingTranslator; - m_entry = entry; - m_reference = null; - } - - public BehaviorReferenceTreeNode(Translator deobfuscatingTranslator, EntryReference reference, Access access) { - m_deobfuscatingTranslator = deobfuscatingTranslator; - m_entry = reference.entry; - m_reference = reference; - m_access = access; - } - - @Override - public BehaviorEntry getEntry() { - return m_entry; - } - - @Override - public EntryReference getReference() { - return m_reference; - } - - @Override - public String toString() { - if (m_reference != null) { - return String.format("%s (%s)", m_deobfuscatingTranslator.translateEntry(m_reference.context), m_access); - } - return m_deobfuscatingTranslator.translateEntry(m_entry).toString(); - } - - public void load(JarIndex index, boolean recurse) { - // get all the child nodes - for (EntryReference reference : index.getBehaviorReferences(m_entry)) { - add(new BehaviorReferenceTreeNode(m_deobfuscatingTranslator, reference, index.getAccess(m_entry))); - } - - if (recurse && children != null) { - for (Object child : children) { - if (child instanceof BehaviorReferenceTreeNode) { - BehaviorReferenceTreeNode node = (BehaviorReferenceTreeNode)child; - - // don't recurse into ancestor - Set ancestors = Sets.newHashSet(); - TreeNode n = (TreeNode)node; - while (n.getParent() != null) { - n = n.getParent(); - if (n instanceof BehaviorReferenceTreeNode) { - ancestors.add( ((BehaviorReferenceTreeNode)n).getEntry()); - } - } - if (ancestors.contains(node.getEntry())) { - continue; - } - - node.load(index, true); - } - } - } - } -} diff --git a/src/cuchaz/enigma/analysis/BridgeMarker.java b/src/cuchaz/enigma/analysis/BridgeMarker.java deleted file mode 100644 index 650b3a78..00000000 --- a/src/cuchaz/enigma/analysis/BridgeMarker.java +++ /dev/null @@ -1,43 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import javassist.CtClass; -import javassist.CtMethod; -import javassist.bytecode.AccessFlag; -import cuchaz.enigma.mapping.EntryFactory; -import cuchaz.enigma.mapping.MethodEntry; - -public class BridgeMarker { - - private JarIndex m_jarIndex; - - public BridgeMarker(JarIndex jarIndex) { - m_jarIndex = jarIndex; - } - - public void markBridges(CtClass c) { - - for (CtMethod method : c.getDeclaredMethods()) { - MethodEntry methodEntry = EntryFactory.getMethodEntry(method); - - // is this a bridge method? - MethodEntry bridgedMethodEntry = m_jarIndex.getBridgedMethod(methodEntry); - if (bridgedMethodEntry != null) { - - // it's a bridge method! add the bridge flag - int flags = method.getMethodInfo().getAccessFlags(); - flags |= AccessFlag.BRIDGE; - method.getMethodInfo().setAccessFlags(flags); - } - } - } -} diff --git a/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java deleted file mode 100644 index cc70f51e..00000000 --- a/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java +++ /dev/null @@ -1,80 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import java.util.List; - -import javax.swing.tree.DefaultMutableTreeNode; - -import com.google.common.collect.Lists; - -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.MethodEntry; -import cuchaz.enigma.mapping.Translator; - -public class ClassImplementationsTreeNode extends DefaultMutableTreeNode { - - private static final long serialVersionUID = 3112703459157851912L; - - private Translator m_deobfuscatingTranslator; - private ClassEntry m_entry; - - public ClassImplementationsTreeNode(Translator deobfuscatingTranslator, ClassEntry entry) { - m_deobfuscatingTranslator = deobfuscatingTranslator; - m_entry = entry; - } - - public ClassEntry getClassEntry() { - return m_entry; - } - - public String getDeobfClassName() { - return m_deobfuscatingTranslator.translateClass(m_entry.getClassName()); - } - - @Override - public String toString() { - String className = getDeobfClassName(); - if (className == null) { - className = m_entry.getClassName(); - } - return className; - } - - public void load(JarIndex index) { - // get all method implementations - List nodes = Lists.newArrayList(); - for (String implementingClassName : index.getImplementingClasses(m_entry.getClassName())) { - nodes.add(new ClassImplementationsTreeNode(m_deobfuscatingTranslator, new ClassEntry(implementingClassName))); - } - - // add them to this node - for (ClassImplementationsTreeNode node : nodes) { - this.add(node); - } - } - - public static ClassImplementationsTreeNode findNode(ClassImplementationsTreeNode node, MethodEntry entry) { - // is this the node? - if (node.m_entry.equals(entry)) { - return node; - } - - // recurse - for (int i = 0; i < node.getChildCount(); i++) { - ClassImplementationsTreeNode foundNode = findNode((ClassImplementationsTreeNode)node.getChildAt(i), entry); - if (foundNode != null) { - return foundNode; - } - } - return null; - } -} diff --git a/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java deleted file mode 100644 index 7542bd9d..00000000 --- a/src/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java +++ /dev/null @@ -1,85 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import java.util.List; - -import javax.swing.tree.DefaultMutableTreeNode; - -import com.google.common.collect.Lists; - -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.Translator; - -public class ClassInheritanceTreeNode extends DefaultMutableTreeNode { - - private static final long serialVersionUID = 4432367405826178490L; - - private Translator m_deobfuscatingTranslator; - private String m_obfClassName; - - public ClassInheritanceTreeNode(Translator deobfuscatingTranslator, String obfClassName) { - m_deobfuscatingTranslator = deobfuscatingTranslator; - m_obfClassName = obfClassName; - } - - public String getObfClassName() { - return m_obfClassName; - } - - public String getDeobfClassName() { - return m_deobfuscatingTranslator.translateClass(m_obfClassName); - } - - @Override - public String toString() { - String deobfClassName = getDeobfClassName(); - if (deobfClassName != null) { - return deobfClassName; - } - return m_obfClassName; - } - - public void load(TranslationIndex ancestries, boolean recurse) { - // get all the child nodes - List nodes = Lists.newArrayList(); - for (ClassEntry subclassEntry : ancestries.getSubclass(new ClassEntry(m_obfClassName))) { - nodes.add(new ClassInheritanceTreeNode(m_deobfuscatingTranslator, subclassEntry.getName())); - } - - // add them to this node - for (ClassInheritanceTreeNode node : nodes) { - this.add(node); - } - - if (recurse) { - for (ClassInheritanceTreeNode node : nodes) { - node.load(ancestries, true); - } - } - } - - public static ClassInheritanceTreeNode findNode(ClassInheritanceTreeNode node, ClassEntry entry) { - // is this the node? - if (node.getObfClassName().equals(entry.getName())) { - return node; - } - - // recurse - for (int i = 0; i < node.getChildCount(); i++) { - ClassInheritanceTreeNode foundNode = findNode((ClassInheritanceTreeNode)node.getChildAt(i), entry); - if (foundNode != null) { - return foundNode; - } - } - return null; - } -} diff --git a/src/cuchaz/enigma/analysis/EntryReference.java b/src/cuchaz/enigma/analysis/EntryReference.java deleted file mode 100644 index 85127239..00000000 --- a/src/cuchaz/enigma/analysis/EntryReference.java +++ /dev/null @@ -1,126 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import java.util.Arrays; -import java.util.List; - -import cuchaz.enigma.Util; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.ConstructorEntry; -import cuchaz.enigma.mapping.Entry; - -public class EntryReference { - - private static final List ConstructorNonNames = Arrays.asList("this", "super", "static"); - public E entry; - public C context; - - private boolean m_isNamed; - - public EntryReference(E entry, String sourceName) { - this(entry, sourceName, null); - } - - public EntryReference(E entry, String sourceName, C context) { - if (entry == null) { - throw new IllegalArgumentException("Entry cannot be null!"); - } - - this.entry = entry; - this.context = context; - - m_isNamed = sourceName != null && sourceName.length() > 0; - if (entry instanceof ConstructorEntry && ConstructorNonNames.contains(sourceName)) { - m_isNamed = false; - } - } - - public EntryReference(E entry, C context, EntryReference other) { - this.entry = entry; - this.context = context; - m_isNamed = other.m_isNamed; - } - - public ClassEntry getLocationClassEntry() { - if (context != null) { - return context.getClassEntry(); - } - return entry.getClassEntry(); - } - - public boolean isNamed() { - return m_isNamed; - } - - public Entry getNameableEntry() { - if (entry instanceof ConstructorEntry) { - // renaming a constructor really means renaming the class - return entry.getClassEntry(); - } - return entry; - } - - public String getNamableName() { - if (getNameableEntry() instanceof ClassEntry) { - ClassEntry classEntry = (ClassEntry)getNameableEntry(); - if (classEntry.isInnerClass()) { - // make sure we only rename the inner class name - return classEntry.getInnermostClassName(); - } - } - - return getNameableEntry().getName(); - } - - @Override - public int hashCode() { - if (context != null) { - return Util.combineHashesOrdered(entry.hashCode(), context.hashCode()); - } - return entry.hashCode(); - } - - @Override - public boolean equals(Object other) { - if (other instanceof EntryReference) { - return equals((EntryReference)other); - } - return false; - } - - public boolean equals(EntryReference other) { - // check entry first - boolean isEntrySame = entry.equals(other.entry); - if (!isEntrySame) { - return false; - } - - // check caller - if (context == null && other.context == null) { - return true; - } else if (context != null && other.context != null) { - return context.equals(other.context); - } - return false; - } - - @Override - public String toString() { - StringBuilder buf = new StringBuilder(); - buf.append(entry); - if (context != null) { - buf.append(" called from "); - buf.append(context); - } - return buf.toString(); - } -} diff --git a/src/cuchaz/enigma/analysis/EntryRenamer.java b/src/cuchaz/enigma/analysis/EntryRenamer.java deleted file mode 100644 index f748274f..00000000 --- a/src/cuchaz/enigma/analysis/EntryRenamer.java +++ /dev/null @@ -1,192 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import java.util.AbstractMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.google.common.collect.Lists; -import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; - -import cuchaz.enigma.mapping.ArgumentEntry; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.ClassNameReplacer; -import cuchaz.enigma.mapping.ConstructorEntry; -import cuchaz.enigma.mapping.Entry; -import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.MethodEntry; -import cuchaz.enigma.mapping.Signature; -import cuchaz.enigma.mapping.Type; - -public class EntryRenamer { - - public static void renameClassesInSet(Map renames, Set set) { - List entries = Lists.newArrayList(); - for (T val : set) { - entries.add(renameClassesInThing(renames, val)); - } - set.clear(); - set.addAll(entries); - } - - public static void renameClassesInMap(Map renames, Map map) { - // for each key/value pair... - Set> entriesToAdd = Sets.newHashSet(); - for (Map.Entry entry : map.entrySet()) { - entriesToAdd.add(new AbstractMap.SimpleEntry( - renameClassesInThing(renames, entry.getKey()), - renameClassesInThing(renames, entry.getValue()) - )); - } - map.clear(); - for (Map.Entry entry : entriesToAdd) { - map.put(entry.getKey(), entry.getValue()); - } - } - - public static void renameClassesInMultimap(Map renames, Multimap map) { - // for each key/value pair... - Set> entriesToAdd = Sets.newHashSet(); - for (Map.Entry entry : map.entries()) { - entriesToAdd.add(new AbstractMap.SimpleEntry( - renameClassesInThing(renames, entry.getKey()), - renameClassesInThing(renames, entry.getValue()) - )); - } - map.clear(); - for (Map.Entry entry : entriesToAdd) { - map.put(entry.getKey(), entry.getValue()); - } - } - - public static void renameMethodsInMultimap(Map renames, Multimap map) { - // for each key/value pair... - Set> entriesToAdd = Sets.newHashSet(); - for (Map.Entry entry : map.entries()) { - entriesToAdd.add(new AbstractMap.SimpleEntry( - renameMethodsInThing(renames, entry.getKey()), - renameMethodsInThing(renames, entry.getValue()) - )); - } - map.clear(); - for (Map.Entry entry : entriesToAdd) { - map.put(entry.getKey(), entry.getValue()); - } - } - - public static void renameMethodsInMap(Map renames, Map map) { - // for each key/value pair... - Set> entriesToAdd = Sets.newHashSet(); - for (Map.Entry entry : map.entrySet()) { - entriesToAdd.add(new AbstractMap.SimpleEntry( - renameMethodsInThing(renames, entry.getKey()), - renameMethodsInThing(renames, entry.getValue()) - )); - } - map.clear(); - for (Map.Entry entry : entriesToAdd) { - map.put(entry.getKey(), entry.getValue()); - } - } - - @SuppressWarnings("unchecked") - public static T renameMethodsInThing(Map renames, T thing) { - if (thing instanceof MethodEntry) { - MethodEntry methodEntry = (MethodEntry)thing; - MethodEntry newMethodEntry = renames.get(methodEntry); - if (newMethodEntry != null) { - return (T)new MethodEntry( - methodEntry.getClassEntry(), - newMethodEntry.getName(), - methodEntry.getSignature() - ); - } - return thing; - } else if (thing instanceof ArgumentEntry) { - ArgumentEntry argumentEntry = (ArgumentEntry)thing; - return (T)new ArgumentEntry( - renameMethodsInThing(renames, argumentEntry.getBehaviorEntry()), - argumentEntry.getIndex(), - argumentEntry.getName() - ); - } else if (thing instanceof EntryReference) { - EntryReference reference = (EntryReference)thing; - reference.entry = renameMethodsInThing(renames, reference.entry); - reference.context = renameMethodsInThing(renames, reference.context); - return thing; - } - return thing; - } - - @SuppressWarnings("unchecked") - public static T renameClassesInThing(final Map renames, T thing) { - if (thing instanceof String) { - String stringEntry = (String)thing; - if (renames.containsKey(stringEntry)) { - return (T)renames.get(stringEntry); - } - } else if (thing instanceof ClassEntry) { - ClassEntry classEntry = (ClassEntry)thing; - return (T)new ClassEntry(renameClassesInThing(renames, classEntry.getClassName())); - } else if (thing instanceof FieldEntry) { - FieldEntry fieldEntry = (FieldEntry)thing; - return (T)new FieldEntry( - renameClassesInThing(renames, fieldEntry.getClassEntry()), - fieldEntry.getName(), - renameClassesInThing(renames, fieldEntry.getType()) - ); - } else if (thing instanceof ConstructorEntry) { - ConstructorEntry constructorEntry = (ConstructorEntry)thing; - return (T)new ConstructorEntry( - renameClassesInThing(renames, constructorEntry.getClassEntry()), - renameClassesInThing(renames, constructorEntry.getSignature()) - ); - } else if (thing instanceof MethodEntry) { - MethodEntry methodEntry = (MethodEntry)thing; - return (T)new MethodEntry( - renameClassesInThing(renames, methodEntry.getClassEntry()), - methodEntry.getName(), - renameClassesInThing(renames, methodEntry.getSignature()) - ); - } else if (thing instanceof ArgumentEntry) { - ArgumentEntry argumentEntry = (ArgumentEntry)thing; - return (T)new ArgumentEntry( - renameClassesInThing(renames, argumentEntry.getBehaviorEntry()), - argumentEntry.getIndex(), - argumentEntry.getName() - ); - } else if (thing instanceof EntryReference) { - EntryReference reference = (EntryReference)thing; - reference.entry = renameClassesInThing(renames, reference.entry); - reference.context = renameClassesInThing(renames, reference.context); - return thing; - } else if (thing instanceof Signature) { - return (T)new Signature((Signature)thing, new ClassNameReplacer() { - @Override - public String replace(String className) { - return renameClassesInThing(renames, className); - } - }); - } else if (thing instanceof Type) { - return (T)new Type((Type)thing, new ClassNameReplacer() { - @Override - public String replace(String className) { - return renameClassesInThing(renames, className); - } - }); - } - - return thing; - } -} diff --git a/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java deleted file mode 100644 index 4ed8fee2..00000000 --- a/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java +++ /dev/null @@ -1,81 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import javax.swing.tree.DefaultMutableTreeNode; - -import cuchaz.enigma.mapping.BehaviorEntry; -import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.Translator; - -public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode { - - private static final long serialVersionUID = -7934108091928699835L; - - private Translator m_deobfuscatingTranslator; - private FieldEntry m_entry; - private EntryReference m_reference; - private Access m_access; - - public FieldReferenceTreeNode(Translator deobfuscatingTranslator, FieldEntry entry) { - m_deobfuscatingTranslator = deobfuscatingTranslator; - m_entry = entry; - m_reference = null; - } - - private FieldReferenceTreeNode(Translator deobfuscatingTranslator, EntryReference reference, Access access) { - m_deobfuscatingTranslator = deobfuscatingTranslator; - m_entry = reference.entry; - m_reference = reference; - m_access = access; - } - - @Override - public FieldEntry getEntry() { - return m_entry; - } - - @Override - public EntryReference getReference() { - return m_reference; - } - - @Override - public String toString() { - if (m_reference != null) { - return String.format("%s (%s)", m_deobfuscatingTranslator.translateEntry(m_reference.context), m_access); - } - return m_deobfuscatingTranslator.translateEntry(m_entry).toString(); - } - - public void load(JarIndex index, boolean recurse) { - // get all the child nodes - if (m_reference == null) { - for (EntryReference reference : index.getFieldReferences(m_entry)) { - add(new FieldReferenceTreeNode(m_deobfuscatingTranslator, reference, index.getAccess(m_entry))); - } - } else { - for (EntryReference reference : index.getBehaviorReferences(m_reference.context)) { - add(new BehaviorReferenceTreeNode(m_deobfuscatingTranslator, reference, index.getAccess(m_reference.context))); - } - } - - if (recurse && children != null) { - for (Object node : children) { - if (node instanceof BehaviorReferenceTreeNode) { - ((BehaviorReferenceTreeNode)node).load(index, true); - } else if (node instanceof FieldReferenceTreeNode) { - ((FieldReferenceTreeNode)node).load(index, true); - } - } - } - } -} diff --git a/src/cuchaz/enigma/analysis/JarClassIterator.java b/src/cuchaz/enigma/analysis/JarClassIterator.java deleted file mode 100644 index aa58e9ec..00000000 --- a/src/cuchaz/enigma/analysis/JarClassIterator.java +++ /dev/null @@ -1,137 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.List; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; - -import javassist.ByteArrayClassPath; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.NotFoundException; -import javassist.bytecode.Descriptor; - -import com.google.common.collect.Lists; - -import cuchaz.enigma.Constants; -import cuchaz.enigma.mapping.ClassEntry; - -public class JarClassIterator implements Iterator { - - private JarFile m_jar; - private Iterator m_iter; - - public JarClassIterator(JarFile jar) { - m_jar = jar; - - // get the jar entries that correspond to classes - List classEntries = Lists.newArrayList(); - Enumeration entries = m_jar.entries(); - while (entries.hasMoreElements()) { - JarEntry entry = entries.nextElement(); - - // is this a class file? - if (entry.getName().endsWith(".class")) { - classEntries.add(entry); - } - } - m_iter = classEntries.iterator(); - } - - @Override - public boolean hasNext() { - return m_iter.hasNext(); - } - - @Override - public CtClass next() { - JarEntry entry = m_iter.next(); - try { - return getClass(m_jar, entry); - } catch (IOException | NotFoundException ex) { - throw new Error("Unable to load class: " + entry.getName()); - } - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - - public static List getClassEntries(JarFile jar) { - List classEntries = Lists.newArrayList(); - Enumeration entries = jar.entries(); - while (entries.hasMoreElements()) { - JarEntry entry = entries.nextElement(); - - // is this a class file? - if (!entry.isDirectory() && entry.getName().endsWith(".class")) { - classEntries.add(getClassEntry(entry)); - } - } - return classEntries; - } - - public static Iterable classes(final JarFile jar) { - return new Iterable() { - @Override - public Iterator iterator() { - return new JarClassIterator(jar); - } - }; - } - - public static CtClass getClass(JarFile jar, ClassEntry classEntry) { - try { - return getClass(jar, new JarEntry(classEntry.getName() + ".class")); - } catch (IOException | NotFoundException ex) { - throw new Error("Unable to load class: " + classEntry.getName()); - } - } - - private static CtClass getClass(JarFile jar, JarEntry entry) throws IOException, NotFoundException { - // read the class into a buffer - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - byte[] buf = new byte[Constants.KiB]; - int totalNumBytesRead = 0; - InputStream in = jar.getInputStream(entry); - while (in.available() > 0) { - int numBytesRead = in.read(buf); - if (numBytesRead < 0) { - break; - } - bos.write(buf, 0, numBytesRead); - - // sanity checking - totalNumBytesRead += numBytesRead; - if (totalNumBytesRead > Constants.MiB) { - throw new Error("Class file " + entry.getName() + " larger than 1 MiB! Something is wrong!"); - } - } - - // get a javassist handle for the class - String className = Descriptor.toJavaName(getClassEntry(entry).getName()); - ClassPool classPool = new ClassPool(); - classPool.appendSystemPath(); - classPool.insertClassPath(new ByteArrayClassPath(className, bos.toByteArray())); - return classPool.get(className); - } - - private static ClassEntry getClassEntry(JarEntry entry) { - return new ClassEntry(entry.getName().substring(0, entry.getName().length() - ".class".length())); - } -} diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java deleted file mode 100644 index 7e3c1b59..00000000 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ /dev/null @@ -1,839 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import java.lang.reflect.Modifier; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.jar.JarFile; - -import javassist.CannotCompileException; -import javassist.CtBehavior; -import javassist.CtClass; -import javassist.CtConstructor; -import javassist.CtField; -import javassist.CtMethod; -import javassist.NotFoundException; -import javassist.bytecode.AccessFlag; -import javassist.bytecode.Descriptor; -import javassist.bytecode.EnclosingMethodAttribute; -import javassist.bytecode.FieldInfo; -import javassist.bytecode.InnerClassesAttribute; -import javassist.expr.ConstructorCall; -import javassist.expr.ExprEditor; -import javassist.expr.FieldAccess; -import javassist.expr.MethodCall; -import javassist.expr.NewExpr; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; - -import cuchaz.enigma.Constants; -import cuchaz.enigma.bytecode.ClassRenamer; -import cuchaz.enigma.mapping.ArgumentEntry; -import cuchaz.enigma.mapping.BehaviorEntry; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.ConstructorEntry; -import cuchaz.enigma.mapping.Entry; -import cuchaz.enigma.mapping.EntryFactory; -import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.MethodEntry; -import cuchaz.enigma.mapping.Translator; - -public class JarIndex { - - private Set m_obfClassEntries; - private TranslationIndex m_translationIndex; - private Map m_access; - private Multimap m_fields; - private Multimap m_behaviors; - private Multimap m_methodImplementations; - private Multimap> m_behaviorReferences; - private Multimap> m_fieldReferences; - private Multimap m_innerClassesByOuter; - private Map m_outerClassesByInner; - private Map m_anonymousClasses; - private Map m_bridgedMethods; - - public JarIndex() { - m_obfClassEntries = Sets.newHashSet(); - m_translationIndex = new TranslationIndex(); - m_access = Maps.newHashMap(); - m_fields = HashMultimap.create(); - m_behaviors = HashMultimap.create(); - m_methodImplementations = HashMultimap.create(); - m_behaviorReferences = HashMultimap.create(); - m_fieldReferences = HashMultimap.create(); - m_innerClassesByOuter = HashMultimap.create(); - m_outerClassesByInner = Maps.newHashMap(); - m_anonymousClasses = Maps.newHashMap(); - m_bridgedMethods = Maps.newHashMap(); - } - - public void indexJar(JarFile jar, boolean buildInnerClasses) { - - // step 1: read the class names - for (ClassEntry classEntry : JarClassIterator.getClassEntries(jar)) { - if (classEntry.isInDefaultPackage()) { - // move out of default package - classEntry = new ClassEntry(Constants.NonePackage + "/" + classEntry.getName()); - } - m_obfClassEntries.add(classEntry); - } - - // step 2: index field/method/constructor access - for (CtClass c : JarClassIterator.classes(jar)) { - ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); - for (CtField field : c.getDeclaredFields()) { - FieldEntry fieldEntry = EntryFactory.getFieldEntry(field); - m_access.put(fieldEntry, Access.get(field)); - m_fields.put(fieldEntry.getClassEntry(), fieldEntry); - } - for (CtBehavior behavior : c.getDeclaredBehaviors()) { - BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); - m_access.put(behaviorEntry, Access.get(behavior)); - m_behaviors.put(behaviorEntry.getClassEntry(), behaviorEntry); - } - } - - // step 3: index extends, implements, fields, and methods - for (CtClass c : JarClassIterator.classes(jar)) { - ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); - m_translationIndex.indexClass(c); - String className = Descriptor.toJvmName(c.getName()); - for (String interfaceName : c.getClassFile().getInterfaces()) { - className = Descriptor.toJvmName(className); - interfaceName = Descriptor.toJvmName(interfaceName); - if (className.equals(interfaceName)) { - throw new IllegalArgumentException("Class cannot be its own interface! " + className); - } - } - for (CtBehavior behavior : c.getDeclaredBehaviors()) { - indexBehavior(behavior); - } - } - - // step 4: index field, method, constructor references - for (CtClass c : JarClassIterator.classes(jar)) { - ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); - for (CtBehavior behavior : c.getDeclaredBehaviors()) { - indexBehaviorReferences(behavior); - } - } - - if (buildInnerClasses) { - - // step 5: index inner classes and anonymous classes - for (CtClass c : JarClassIterator.classes(jar)) { - ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); - ClassEntry innerClassEntry = EntryFactory.getClassEntry(c); - ClassEntry outerClassEntry = findOuterClass(c); - if (outerClassEntry != null) { - m_innerClassesByOuter.put(outerClassEntry, innerClassEntry); - boolean innerWasAdded = m_outerClassesByInner.put(innerClassEntry, outerClassEntry) == null; - assert (innerWasAdded); - - BehaviorEntry enclosingBehavior = isAnonymousClass(c, outerClassEntry); - if (enclosingBehavior != null) { - m_anonymousClasses.put(innerClassEntry, enclosingBehavior); - - // DEBUG - //System.out.println("ANONYMOUS: " + outerClassEntry.getName() + "$" + innerClassEntry.getSimpleName()); - } else { - // DEBUG - //System.out.println("INNER: " + outerClassEntry.getName() + "$" + innerClassEntry.getSimpleName()); - } - } - } - - // step 6: update other indices with inner class info - Map renames = Maps.newHashMap(); - for (ClassEntry innerClassEntry : m_innerClassesByOuter.values()) { - String newName = innerClassEntry.buildClassEntry(getObfClassChain(innerClassEntry)).getName(); - if (!innerClassEntry.getName().equals(newName)) { - // DEBUG - //System.out.println("REPLACE: " + innerClassEntry.getName() + " WITH " + newName); - renames.put(innerClassEntry.getName(), newName); - } - } - EntryRenamer.renameClassesInSet(renames, m_obfClassEntries); - m_translationIndex.renameClasses(renames); - EntryRenamer.renameClassesInMultimap(renames, m_methodImplementations); - EntryRenamer.renameClassesInMultimap(renames, m_behaviorReferences); - EntryRenamer.renameClassesInMultimap(renames, m_fieldReferences); - EntryRenamer.renameClassesInMap(renames, m_access); - } - } - - private void indexBehavior(CtBehavior behavior) { - // get the behavior entry - final BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); - if (behaviorEntry instanceof MethodEntry) { - MethodEntry methodEntry = (MethodEntry)behaviorEntry; - - // index implementation - m_methodImplementations.put(behaviorEntry.getClassName(), methodEntry); - - // look for bridge and bridged methods - CtMethod bridgedMethod = getBridgedMethod((CtMethod)behavior); - if (bridgedMethod != null) { - m_bridgedMethods.put(methodEntry, EntryFactory.getMethodEntry(bridgedMethod)); - } - } - // looks like we don't care about constructors here - } - - private void indexBehaviorReferences(CtBehavior behavior) { - // index method calls - final BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); - try { - behavior.instrument(new ExprEditor() { - @Override - public void edit(MethodCall call) { - MethodEntry calledMethodEntry = EntryFactory.getMethodEntry(call); - ClassEntry resolvedClassEntry = m_translationIndex.resolveEntryClass(calledMethodEntry); - if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledMethodEntry.getClassEntry())) { - calledMethodEntry = new MethodEntry( - resolvedClassEntry, - calledMethodEntry.getName(), - calledMethodEntry.getSignature() - ); - } - EntryReference reference = new EntryReference( - calledMethodEntry, - call.getMethodName(), - behaviorEntry - ); - m_behaviorReferences.put(calledMethodEntry, reference); - } - - @Override - public void edit(FieldAccess call) { - FieldEntry calledFieldEntry = EntryFactory.getFieldEntry(call); - ClassEntry resolvedClassEntry = m_translationIndex.resolveEntryClass(calledFieldEntry); - if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledFieldEntry.getClassEntry())) { - calledFieldEntry = new FieldEntry(calledFieldEntry, resolvedClassEntry); - } - EntryReference reference = new EntryReference( - calledFieldEntry, - call.getFieldName(), - behaviorEntry - ); - m_fieldReferences.put(calledFieldEntry, reference); - } - - @Override - public void edit(ConstructorCall call) { - ConstructorEntry calledConstructorEntry = EntryFactory.getConstructorEntry(call); - EntryReference reference = new EntryReference( - calledConstructorEntry, - call.getMethodName(), - behaviorEntry - ); - m_behaviorReferences.put(calledConstructorEntry, reference); - } - - @Override - public void edit(NewExpr call) { - ConstructorEntry calledConstructorEntry = EntryFactory.getConstructorEntry(call); - EntryReference reference = new EntryReference( - calledConstructorEntry, - call.getClassName(), - behaviorEntry - ); - m_behaviorReferences.put(calledConstructorEntry, reference); - } - }); - } catch (CannotCompileException ex) { - throw new Error(ex); - } - } - - private CtMethod getBridgedMethod(CtMethod method) { - - // bridge methods just call another method, cast it to the return type, and return the result - // let's see if we can detect this scenario - - // skip non-synthetic methods - if ((method.getModifiers() & AccessFlag.SYNTHETIC) == 0) { - return null; - } - - // get all the called methods - final List methodCalls = Lists.newArrayList(); - try { - method.instrument(new ExprEditor() { - @Override - public void edit(MethodCall call) { - methodCalls.add(call); - } - }); - } catch (CannotCompileException ex) { - // this is stupid... we're not even compiling anything - throw new Error(ex); - } - - // is there just one? - if (methodCalls.size() != 1) { - return null; - } - MethodCall call = methodCalls.get(0); - - try { - // we have a bridge method! - return call.getMethod(); - } catch (NotFoundException ex) { - // can't find the type? not a bridge method - return null; - } - } - - private ClassEntry findOuterClass(CtClass c) { - - ClassEntry classEntry = EntryFactory.getClassEntry(c); - - // does this class already have an outer class? - if (classEntry.isInnerClass()) { - return classEntry.getOuterClassEntry(); - } - - // inner classes: - // have constructors that can (illegally) set synthetic fields - // the outer class is the only class that calls constructors - - // use the synthetic fields to find the synthetic constructors - for (CtConstructor constructor : c.getDeclaredConstructors()) { - Set syntheticFieldTypes = Sets.newHashSet(); - if (!isIllegalConstructor(syntheticFieldTypes, constructor)) { - continue; - } - - ConstructorEntry constructorEntry = EntryFactory.getConstructorEntry(constructor); - - // gather the classes from the illegally-set synthetic fields - Set illegallySetClasses = Sets.newHashSet(); - for (String type : syntheticFieldTypes) { - if (type.startsWith("L")) { - ClassEntry outerClassEntry = new ClassEntry(type.substring(1, type.length() - 1)); - if (isSaneOuterClass(outerClassEntry, classEntry)) { - illegallySetClasses.add(outerClassEntry); - } - } - } - - // who calls this constructor? - Set callerClasses = Sets.newHashSet(); - for (EntryReference reference : getBehaviorReferences(constructorEntry)) { - - // make sure it's not a call to super - if (reference.entry instanceof ConstructorEntry && reference.context instanceof ConstructorEntry) { - - // is the entry a superclass of the context? - ClassEntry calledClassEntry = reference.entry.getClassEntry(); - ClassEntry superclassEntry = m_translationIndex.getSuperclass(reference.context.getClassEntry()); - if (superclassEntry != null && superclassEntry.equals(calledClassEntry)) { - // it's a super call, skip - continue; - } - } - - if (isSaneOuterClass(reference.context.getClassEntry(), classEntry)) { - callerClasses.add(reference.context.getClassEntry()); - } - } - - // do we have an answer yet? - if (callerClasses.isEmpty()) { - if (illegallySetClasses.size() == 1) { - return illegallySetClasses.iterator().next(); - } else { - System.out.println(String.format("WARNING: Unable to find outer class for %s. No caller and no illegally set field classes.", classEntry)); - } - } else { - if (callerClasses.size() == 1) { - return callerClasses.iterator().next(); - } else { - // multiple callers, do the illegally set classes narrow it down? - Set intersection = Sets.newHashSet(callerClasses); - intersection.retainAll(illegallySetClasses); - if (intersection.size() == 1) { - return intersection.iterator().next(); - } else { - System.out.println(String.format("WARNING: Unable to choose outer class for %s among options: %s", classEntry, callerClasses)); - } - } - } - } - - return null; - } - - private boolean isSaneOuterClass(ClassEntry outerClassEntry, ClassEntry innerClassEntry) { - - // clearly this would be silly - if (outerClassEntry.equals(innerClassEntry)) { - return false; - } - - // is the outer class in the jar? - if (!m_obfClassEntries.contains(outerClassEntry)) { - return false; - } - - return true; - } - - @SuppressWarnings("unchecked") - private boolean isIllegalConstructor(Set syntheticFieldTypes, CtConstructor constructor) { - - // illegal constructors only set synthetic member fields, then call super() - String className = constructor.getDeclaringClass().getName(); - - // collect all the field accesses, constructor calls, and method calls - final List illegalFieldWrites = Lists.newArrayList(); - final List constructorCalls = Lists.newArrayList(); - try { - constructor.instrument(new ExprEditor() { - @Override - public void edit(FieldAccess fieldAccess) { - if (fieldAccess.isWriter() && constructorCalls.isEmpty()) { - illegalFieldWrites.add(fieldAccess); - } - } - - @Override - public void edit(ConstructorCall constructorCall) { - constructorCalls.add(constructorCall); - } - }); - } catch (CannotCompileException ex) { - // we're not compiling anything... this is stupid - throw new Error(ex); - } - - // are there any illegal field writes? - if (illegalFieldWrites.isEmpty()) { - return false; - } - - // are all the writes to synthetic fields? - for (FieldAccess fieldWrite : illegalFieldWrites) { - - // all illegal writes have to be to the local class - if (!fieldWrite.getClassName().equals(className)) { - System.err.println(String.format("WARNING: illegal write to non-member field %s.%s", fieldWrite.getClassName(), fieldWrite.getFieldName())); - return false; - } - - // find the field - FieldInfo fieldInfo = null; - for (FieldInfo info : (List)constructor.getDeclaringClass().getClassFile().getFields()) { - if (info.getName().equals(fieldWrite.getFieldName()) && info.getDescriptor().equals(fieldWrite.getSignature())) { - fieldInfo = info; - break; - } - } - if (fieldInfo == null) { - // field is in a superclass or something, can't be a local synthetic member - return false; - } - - // is this field synthetic? - boolean isSynthetic = (fieldInfo.getAccessFlags() & AccessFlag.SYNTHETIC) != 0; - if (isSynthetic) { - syntheticFieldTypes.add(fieldInfo.getDescriptor()); - } else { - System.err.println(String.format("WARNING: illegal write to non synthetic field %s %s.%s", fieldInfo.getDescriptor(), className, fieldInfo.getName())); - return false; - } - } - - // we passed all the tests! - return true; - } - - private BehaviorEntry isAnonymousClass(CtClass c, ClassEntry outerClassEntry) { - - // is this class already marked anonymous? - EnclosingMethodAttribute enclosingMethodAttribute = (EnclosingMethodAttribute)c.getClassFile().getAttribute(EnclosingMethodAttribute.tag); - if (enclosingMethodAttribute != null) { - if (enclosingMethodAttribute.methodIndex() > 0) { - return EntryFactory.getBehaviorEntry( - Descriptor.toJvmName(enclosingMethodAttribute.className()), - enclosingMethodAttribute.methodName(), - enclosingMethodAttribute.methodDescriptor() - ); - } else { - // an attribute but no method? assume not anonymous - return null; - } - } - - // if there's an inner class attribute, but not an enclosing method attribute, then it's not anonymous - InnerClassesAttribute innerClassesAttribute = (InnerClassesAttribute)c.getClassFile().getAttribute(InnerClassesAttribute.tag); - if (innerClassesAttribute != null) { - return null; - } - - ClassEntry innerClassEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); - - // anonymous classes: - // can't be abstract - // have only one constructor - // it's called exactly once by the outer class - // the type the instance is assigned to can't be this type - - // is abstract? - if (Modifier.isAbstract(c.getModifiers())) { - return null; - } - - // is there exactly one constructor? - if (c.getDeclaredConstructors().length != 1) { - return null; - } - CtConstructor constructor = c.getDeclaredConstructors()[0]; - - // is this constructor called exactly once? - ConstructorEntry constructorEntry = EntryFactory.getConstructorEntry(constructor); - Collection> references = getBehaviorReferences(constructorEntry); - if (references.size() != 1) { - return null; - } - - // does the caller use this type? - BehaviorEntry caller = references.iterator().next().context; - for (FieldEntry fieldEntry : getReferencedFields(caller)) { - if (fieldEntry.getType().hasClass() && fieldEntry.getType().getClassEntry().equals(innerClassEntry)) { - // caller references this type, so it can't be anonymous - return null; - } - } - for (BehaviorEntry behaviorEntry : getReferencedBehaviors(caller)) { - if (behaviorEntry.getSignature().hasClass(innerClassEntry)) { - return null; - } - } - - return caller; - } - - public Set getObfClassEntries() { - return m_obfClassEntries; - } - - public Collection getObfFieldEntries() { - return m_fields.values(); - } - - public Collection getObfFieldEntries(ClassEntry classEntry) { - return m_fields.get(classEntry); - } - - public Collection getObfBehaviorEntries() { - return m_behaviors.values(); - } - - public Collection getObfBehaviorEntries(ClassEntry classEntry) { - return m_behaviors.get(classEntry); - } - - public TranslationIndex getTranslationIndex() { - return m_translationIndex; - } - - public Access getAccess(Entry entry) { - return m_access.get(entry); - } - - public ClassInheritanceTreeNode getClassInheritance(Translator deobfuscatingTranslator, ClassEntry obfClassEntry) { - - // get the root node - List ancestry = Lists.newArrayList(); - ancestry.add(obfClassEntry.getName()); - for (ClassEntry classEntry : m_translationIndex.getAncestry(obfClassEntry)) { - if (containsObfClass(classEntry)) { - ancestry.add(classEntry.getName()); - } - } - ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode( - deobfuscatingTranslator, - ancestry.get(ancestry.size() - 1) - ); - - // expand all children recursively - rootNode.load(m_translationIndex, true); - - return rootNode; - } - - public ClassImplementationsTreeNode getClassImplementations(Translator deobfuscatingTranslator, ClassEntry obfClassEntry) { - - // is this even an interface? - if (isInterface(obfClassEntry.getClassName())) { - ClassImplementationsTreeNode node = new ClassImplementationsTreeNode(deobfuscatingTranslator, obfClassEntry); - node.load(this); - return node; - } - return null; - } - - public MethodInheritanceTreeNode getMethodInheritance(Translator deobfuscatingTranslator, MethodEntry obfMethodEntry) { - - // travel to the ancestor implementation - ClassEntry baseImplementationClassEntry = obfMethodEntry.getClassEntry(); - for (ClassEntry ancestorClassEntry : m_translationIndex.getAncestry(obfMethodEntry.getClassEntry())) { - MethodEntry ancestorMethodEntry = new MethodEntry( - new ClassEntry(ancestorClassEntry), - obfMethodEntry.getName(), - obfMethodEntry.getSignature() - ); - if (containsObfBehavior(ancestorMethodEntry)) { - baseImplementationClassEntry = ancestorClassEntry; - } - } - - // make a root node at the base - MethodEntry methodEntry = new MethodEntry( - baseImplementationClassEntry, - obfMethodEntry.getName(), - obfMethodEntry.getSignature() - ); - MethodInheritanceTreeNode rootNode = new MethodInheritanceTreeNode( - deobfuscatingTranslator, - methodEntry, - containsObfBehavior(methodEntry) - ); - - // expand the full tree - rootNode.load(this, true); - - return rootNode; - } - - public List getMethodImplementations(Translator deobfuscatingTranslator, MethodEntry obfMethodEntry) { - - List interfaceMethodEntries = Lists.newArrayList(); - - // is this method on an interface? - if (isInterface(obfMethodEntry.getClassName())) { - interfaceMethodEntries.add(obfMethodEntry); - } else { - // get the interface class - for (ClassEntry interfaceEntry : getInterfaces(obfMethodEntry.getClassName())) { - - // is this method defined in this interface? - MethodEntry methodInterface = new MethodEntry( - interfaceEntry, - obfMethodEntry.getName(), - obfMethodEntry.getSignature() - ); - if (containsObfBehavior(methodInterface)) { - interfaceMethodEntries.add(methodInterface); - } - } - } - - List nodes = Lists.newArrayList(); - if (!interfaceMethodEntries.isEmpty()) { - for (MethodEntry interfaceMethodEntry : interfaceMethodEntries) { - MethodImplementationsTreeNode node = new MethodImplementationsTreeNode(deobfuscatingTranslator, interfaceMethodEntry); - node.load(this); - nodes.add(node); - } - } - return nodes; - } - - public Set getRelatedMethodImplementations(MethodEntry obfMethodEntry) { - Set methodEntries = Sets.newHashSet(); - getRelatedMethodImplementations(methodEntries, getMethodInheritance(null, obfMethodEntry)); - return methodEntries; - } - - private void getRelatedMethodImplementations(Set methodEntries, MethodInheritanceTreeNode node) { - MethodEntry methodEntry = node.getMethodEntry(); - if (containsObfBehavior(methodEntry)) { - // collect the entry - methodEntries.add(methodEntry); - } - - // look at interface methods too - for (MethodImplementationsTreeNode implementationsNode : getMethodImplementations(null, methodEntry)) { - getRelatedMethodImplementations(methodEntries, implementationsNode); - } - - // recurse - for (int i = 0; i < node.getChildCount(); i++) { - getRelatedMethodImplementations(methodEntries, (MethodInheritanceTreeNode)node.getChildAt(i)); - } - } - - private void getRelatedMethodImplementations(Set methodEntries, MethodImplementationsTreeNode node) { - MethodEntry methodEntry = node.getMethodEntry(); - if (containsObfBehavior(methodEntry)) { - // collect the entry - methodEntries.add(methodEntry); - } - - // recurse - for (int i = 0; i < node.getChildCount(); i++) { - getRelatedMethodImplementations(methodEntries, (MethodImplementationsTreeNode)node.getChildAt(i)); - } - } - - public Collection> getFieldReferences(FieldEntry fieldEntry) { - return m_fieldReferences.get(fieldEntry); - } - - public Collection getReferencedFields(BehaviorEntry behaviorEntry) { - // linear search is fast enough for now - Set fieldEntries = Sets.newHashSet(); - for (EntryReference reference : m_fieldReferences.values()) { - if (reference.context == behaviorEntry) { - fieldEntries.add(reference.entry); - } - } - return fieldEntries; - } - - public Collection> getBehaviorReferences(BehaviorEntry behaviorEntry) { - return m_behaviorReferences.get(behaviorEntry); - } - - public Collection getReferencedBehaviors(BehaviorEntry behaviorEntry) { - // linear search is fast enough for now - Set behaviorEntries = Sets.newHashSet(); - for (EntryReference reference : m_behaviorReferences.values()) { - if (reference.context == behaviorEntry) { - behaviorEntries.add(reference.entry); - } - } - return behaviorEntries; - } - - public Collection getInnerClasses(ClassEntry obfOuterClassEntry) { - return m_innerClassesByOuter.get(obfOuterClassEntry); - } - - public ClassEntry getOuterClass(ClassEntry obfInnerClassEntry) { - return m_outerClassesByInner.get(obfInnerClassEntry); - } - - public boolean isAnonymousClass(ClassEntry obfInnerClassEntry) { - return m_anonymousClasses.containsKey(obfInnerClassEntry); - } - - public BehaviorEntry getAnonymousClassCaller(ClassEntry obfInnerClassName) { - return m_anonymousClasses.get(obfInnerClassName); - } - - public Set getInterfaces(String className) { - ClassEntry classEntry = new ClassEntry(className); - Set interfaces = new HashSet(); - interfaces.addAll(m_translationIndex.getInterfaces(classEntry)); - for (ClassEntry ancestor : m_translationIndex.getAncestry(classEntry)) { - interfaces.addAll(m_translationIndex.getInterfaces(ancestor)); - } - return interfaces; - } - - public Set getImplementingClasses(String targetInterfaceName) { - - // linear search is fast enough for now - Set classNames = Sets.newHashSet(); - for (Map.Entry entry : m_translationIndex.getClassInterfaces()) { - ClassEntry classEntry = entry.getKey(); - ClassEntry interfaceEntry = entry.getValue(); - if (interfaceEntry.getName().equals(targetInterfaceName)) { - classNames.add(classEntry.getClassName()); - m_translationIndex.getSubclassNamesRecursively(classNames, classEntry); - } - } - return classNames; - } - - public boolean isInterface(String className) { - return m_translationIndex.isInterface(new ClassEntry(className)); - } - - public boolean containsObfClass(ClassEntry obfClassEntry) { - return m_obfClassEntries.contains(obfClassEntry); - } - - public boolean containsObfField(FieldEntry obfFieldEntry) { - return m_access.containsKey(obfFieldEntry); - } - - public boolean containsObfBehavior(BehaviorEntry obfBehaviorEntry) { - return m_access.containsKey(obfBehaviorEntry); - } - - public boolean containsObfArgument(ArgumentEntry obfArgumentEntry) { - // check the behavior - if (!containsObfBehavior(obfArgumentEntry.getBehaviorEntry())) { - return false; - } - - // check the argument - if (obfArgumentEntry.getIndex() >= obfArgumentEntry.getBehaviorEntry().getSignature().getArgumentTypes().size()) { - return false; - } - - return true; - } - - public boolean containsObfEntry(Entry obfEntry) { - if (obfEntry instanceof ClassEntry) { - return containsObfClass((ClassEntry)obfEntry); - } else if (obfEntry instanceof FieldEntry) { - return containsObfField((FieldEntry)obfEntry); - } else if (obfEntry instanceof BehaviorEntry) { - return containsObfBehavior((BehaviorEntry)obfEntry); - } else if (obfEntry instanceof ArgumentEntry) { - return containsObfArgument((ArgumentEntry)obfEntry); - } else { - throw new Error("Entry type not supported: " + obfEntry.getClass().getName()); - } - } - - public MethodEntry getBridgedMethod(MethodEntry bridgeMethodEntry) { - return m_bridgedMethods.get(bridgeMethodEntry); - } - - public List getObfClassChain(ClassEntry obfClassEntry) { - - // build class chain in inner-to-outer order - List obfClassChain = Lists.newArrayList(obfClassEntry); - ClassEntry checkClassEntry = obfClassEntry; - while (true) { - ClassEntry obfOuterClassEntry = getOuterClass(checkClassEntry); - if (obfOuterClassEntry != null) { - obfClassChain.add(obfOuterClassEntry); - checkClassEntry = obfOuterClassEntry; - } else { - break; - } - } - - // switch to outer-to-inner order - Collections.reverse(obfClassChain); - - return obfClassChain; - } -} diff --git a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java deleted file mode 100644 index aa0aeca6..00000000 --- a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java +++ /dev/null @@ -1,101 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import java.util.List; - -import javax.swing.tree.DefaultMutableTreeNode; - -import com.google.common.collect.Lists; - -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.MethodEntry; -import cuchaz.enigma.mapping.Translator; - -public class MethodImplementationsTreeNode extends DefaultMutableTreeNode { - - private static final long serialVersionUID = 3781080657461899915L; - - private Translator m_deobfuscatingTranslator; - private MethodEntry m_entry; - - public MethodImplementationsTreeNode(Translator deobfuscatingTranslator, MethodEntry entry) { - if (entry == null) { - throw new IllegalArgumentException("entry cannot be null!"); - } - - m_deobfuscatingTranslator = deobfuscatingTranslator; - m_entry = entry; - } - - public MethodEntry getMethodEntry() { - return m_entry; - } - - public String getDeobfClassName() { - return m_deobfuscatingTranslator.translateClass(m_entry.getClassName()); - } - - public String getDeobfMethodName() { - return m_deobfuscatingTranslator.translate(m_entry); - } - - @Override - public String toString() { - String className = getDeobfClassName(); - if (className == null) { - className = m_entry.getClassName(); - } - - String methodName = getDeobfMethodName(); - if (methodName == null) { - methodName = m_entry.getName(); - } - return className + "." + methodName + "()"; - } - - public void load(JarIndex index) { - - // get all method implementations - List nodes = Lists.newArrayList(); - for (String implementingClassName : index.getImplementingClasses(m_entry.getClassName())) { - MethodEntry methodEntry = new MethodEntry( - new ClassEntry(implementingClassName), - m_entry.getName(), - m_entry.getSignature() - ); - if (index.containsObfBehavior(methodEntry)) { - nodes.add(new MethodImplementationsTreeNode(m_deobfuscatingTranslator, methodEntry)); - } - } - - // add them to this node - for (MethodImplementationsTreeNode node : nodes) { - this.add(node); - } - } - - public static MethodImplementationsTreeNode findNode(MethodImplementationsTreeNode node, MethodEntry entry) { - // is this the node? - if (node.getMethodEntry().equals(entry)) { - return node; - } - - // recurse - for (int i = 0; i < node.getChildCount(); i++) { - MethodImplementationsTreeNode foundNode = findNode((MethodImplementationsTreeNode)node.getChildAt(i), entry); - if (foundNode != null) { - return foundNode; - } - } - return null; - } -} diff --git a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java b/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java deleted file mode 100644 index 0da3c8c9..00000000 --- a/src/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java +++ /dev/null @@ -1,114 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import java.util.List; - -import javax.swing.tree.DefaultMutableTreeNode; - -import com.google.common.collect.Lists; - -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.MethodEntry; -import cuchaz.enigma.mapping.Translator; - -public class MethodInheritanceTreeNode extends DefaultMutableTreeNode { - - private static final long serialVersionUID = 1096677030991810007L; - - private Translator m_deobfuscatingTranslator; - private MethodEntry m_entry; - private boolean m_isImplemented; - - public MethodInheritanceTreeNode(Translator deobfuscatingTranslator, MethodEntry entry, boolean isImplemented) { - m_deobfuscatingTranslator = deobfuscatingTranslator; - m_entry = entry; - m_isImplemented = isImplemented; - } - - public MethodEntry getMethodEntry() { - return m_entry; - } - - public String getDeobfClassName() { - return m_deobfuscatingTranslator.translateClass(m_entry.getClassName()); - } - - public String getDeobfMethodName() { - return m_deobfuscatingTranslator.translate(m_entry); - } - - public boolean isImplemented() { - return m_isImplemented; - } - - @Override - public String toString() { - String className = getDeobfClassName(); - if (className == null) { - className = m_entry.getClassName(); - } - - if (!m_isImplemented) { - return className; - } else { - String methodName = getDeobfMethodName(); - if (methodName == null) { - methodName = m_entry.getName(); - } - return className + "." + methodName + "()"; - } - } - - public void load(JarIndex index, boolean recurse) { - // get all the child nodes - List nodes = Lists.newArrayList(); - for (ClassEntry subclassEntry : index.getTranslationIndex().getSubclass(m_entry.getClassEntry())) { - MethodEntry methodEntry = new MethodEntry( - subclassEntry, - m_entry.getName(), - m_entry.getSignature() - ); - nodes.add(new MethodInheritanceTreeNode( - m_deobfuscatingTranslator, - methodEntry, - index.containsObfBehavior(methodEntry) - )); - } - - // add them to this node - for (MethodInheritanceTreeNode node : nodes) { - this.add(node); - } - - if (recurse) { - for (MethodInheritanceTreeNode node : nodes) { - node.load(index, true); - } - } - } - - public static MethodInheritanceTreeNode findNode(MethodInheritanceTreeNode node, MethodEntry entry) { - // is this the node? - if (node.getMethodEntry().equals(entry)) { - return node; - } - - // recurse - for (int i = 0; i < node.getChildCount(); i++) { - MethodInheritanceTreeNode foundNode = findNode((MethodInheritanceTreeNode)node.getChildAt(i), entry); - if (foundNode != null) { - return foundNode; - } - } - return null; - } -} diff --git a/src/cuchaz/enigma/analysis/ReferenceTreeNode.java b/src/cuchaz/enigma/analysis/ReferenceTreeNode.java deleted file mode 100644 index 4d81bf1c..00000000 --- a/src/cuchaz/enigma/analysis/ReferenceTreeNode.java +++ /dev/null @@ -1,18 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import cuchaz.enigma.mapping.Entry; - -public interface ReferenceTreeNode { - E getEntry(); - EntryReference getReference(); -} diff --git a/src/cuchaz/enigma/analysis/RelatedMethodChecker.java b/src/cuchaz/enigma/analysis/RelatedMethodChecker.java deleted file mode 100644 index e592a1c3..00000000 --- a/src/cuchaz/enigma/analysis/RelatedMethodChecker.java +++ /dev/null @@ -1,106 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import java.util.Map; -import java.util.Set; - -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; - -import cuchaz.enigma.mapping.BehaviorEntry; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.EntryFactory; -import cuchaz.enigma.mapping.MethodEntry; -import cuchaz.enigma.mapping.MethodMapping; - -public class RelatedMethodChecker { - - private JarIndex m_jarIndex; - private Map,String> m_deobfNamesByGroup; - private Map m_deobfNamesByObfMethod; - private Map> m_groupsByObfMethod; - private Set> m_inconsistentGroups; - - public RelatedMethodChecker(JarIndex jarIndex) { - m_jarIndex = jarIndex; - m_deobfNamesByGroup = Maps.newHashMap(); - m_deobfNamesByObfMethod = Maps.newHashMap(); - m_groupsByObfMethod = Maps.newHashMap(); - m_inconsistentGroups = Sets.newHashSet(); - } - - public void checkMethod(ClassEntry classEntry, MethodMapping methodMapping) { - - // TEMP: disable the expensive check for now, maybe we can optimize it later, or just use it for debugging - if (true) return; - - BehaviorEntry obfBehaviorEntry = EntryFactory.getObfBehaviorEntry(classEntry, methodMapping); - if (!(obfBehaviorEntry instanceof MethodEntry)) { - // only methods have related implementations - return; - } - MethodEntry obfMethodEntry = (MethodEntry)obfBehaviorEntry; - String deobfName = methodMapping.getDeobfName(); - m_deobfNamesByObfMethod.put(obfMethodEntry, deobfName); - - // have we seen this method's group before? - Set group = m_groupsByObfMethod.get(obfMethodEntry); - if (group == null) { - - // no, compute the group and save the name - group = m_jarIndex.getRelatedMethodImplementations(obfMethodEntry); - m_deobfNamesByGroup.put(group, deobfName); - - assert(group.contains(obfMethodEntry)); - for (MethodEntry relatedMethodEntry : group) { - m_groupsByObfMethod.put(relatedMethodEntry, group); - } - } - - // check the name - if (!sameName(m_deobfNamesByGroup.get(group), deobfName)) { - m_inconsistentGroups.add(group); - } - } - - private boolean sameName(String a, String b) { - if (a == null && b == null) { - return true; - } else if (a != null && b != null) { - return a.equals(b); - } - return false; - } - - public boolean hasProblems() { - return m_inconsistentGroups.size() > 0; - } - - public String getReport() { - StringBuilder buf = new StringBuilder(); - buf.append(m_inconsistentGroups.size()); - buf.append(" groups of methods related by inheritance and/or interfaces have different deobf names!\n"); - for (Set group : m_inconsistentGroups) { - buf.append("\tGroup with "); - buf.append(group.size()); - buf.append(" methods:\n"); - for (MethodEntry methodEntry : group) { - buf.append("\t\t"); - buf.append(methodEntry.toString()); - buf.append(" => "); - buf.append(m_deobfNamesByObfMethod.get(methodEntry)); - buf.append("\n"); - } - } - return buf.toString(); - } -} diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java deleted file mode 100644 index 3c4ac464..00000000 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ /dev/null @@ -1,184 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; -import com.strobel.decompiler.languages.Region; -import com.strobel.decompiler.languages.java.ast.AstNode; -import com.strobel.decompiler.languages.java.ast.Identifier; - -import cuchaz.enigma.mapping.Entry; - -public class SourceIndex { - - private String m_source; - private TreeMap> m_tokenToReference; - private Multimap,Token> m_referenceToTokens; - private Map m_declarationToToken; - private List m_lineOffsets; - private boolean m_ignoreBadTokens; - - public SourceIndex(String source) { - this(source, true); - } - - public SourceIndex(String source, boolean ignoreBadTokens) { - m_source = source; - m_ignoreBadTokens = ignoreBadTokens; - m_tokenToReference = Maps.newTreeMap(); - m_referenceToTokens = HashMultimap.create(); - m_declarationToToken = Maps.newHashMap(); - m_lineOffsets = Lists.newArrayList(); - - // count the lines - m_lineOffsets.add(0); - for (int i = 0; i < source.length(); i++) { - if (source.charAt(i) == '\n') { - m_lineOffsets.add(i + 1); - } - } - } - - public String getSource() { - return m_source; - } - - public Token getToken(AstNode node) { - - // get the text of the node - String name = ""; - if (node instanceof Identifier) { - name = ((Identifier)node).getName(); - } - - // get a token for this node's region - Region region = node.getRegion(); - if (region.getBeginLine() == 0 || region.getEndLine() == 0) { - // DEBUG - System.err.println(String.format("WARNING: %s \"%s\" has invalid region: %s", node.getNodeType(), name, region)); - return null; - } - Token token = new Token( - toPos(region.getBeginLine(), region.getBeginColumn()), - toPos(region.getEndLine(), region.getEndColumn()), - m_source - ); - if (token.start == 0) { - // DEBUG - System.err.println(String.format("WARNING: %s \"%s\" has invalid start: %s", node.getNodeType(), name, region)); - return null; - } - - // DEBUG - // System.out.println( String.format( "%s \"%s\" region: %s", node.getNodeType(), name, region ) ); - - // if the token has a $ in it, something's wrong. Ignore this token - if (name.lastIndexOf('$') >= 0 && m_ignoreBadTokens) { - // DEBUG - System.err.println(String.format("WARNING: %s \"%s\" is probably a bad token. It was ignored", node.getNodeType(), name)); - return null; - } - - return token; - } - - public void addReference(AstNode node, Entry deobfEntry, Entry deobfContext) { - Token token = getToken(node); - if (token != null) { - EntryReference deobfReference = new EntryReference(deobfEntry, token.text, deobfContext); - m_tokenToReference.put(token, deobfReference); - m_referenceToTokens.put(deobfReference, token); - } - } - - public void addDeclaration(AstNode node, Entry deobfEntry) { - Token token = getToken(node); - if (token != null) { - EntryReference reference = new EntryReference(deobfEntry, token.text); - m_tokenToReference.put(token, reference); - m_referenceToTokens.put(reference, token); - m_declarationToToken.put(deobfEntry, token); - } - } - - public Token getReferenceToken(int pos) { - Token token = m_tokenToReference.floorKey(new Token(pos, pos, null)); - if (token != null && token.contains(pos)) { - return token; - } - return null; - } - - public Collection getReferenceTokens(EntryReference deobfReference) { - return m_referenceToTokens.get(deobfReference); - } - - public EntryReference getDeobfReference(Token token) { - if (token == null) { - return null; - } - return m_tokenToReference.get(token); - } - - public void replaceDeobfReference(Token token, EntryReference newDeobfReference) { - EntryReference oldDeobfReference = m_tokenToReference.get(token); - m_tokenToReference.put(token, newDeobfReference); - Collection tokens = m_referenceToTokens.get(oldDeobfReference); - m_referenceToTokens.removeAll(oldDeobfReference); - m_referenceToTokens.putAll(newDeobfReference, tokens); - } - - public Iterable referenceTokens() { - return m_tokenToReference.keySet(); - } - - public Iterable declarationTokens() { - return m_declarationToToken.values(); - } - - public Iterable declarations() { - return m_declarationToToken.keySet(); - } - - public Token getDeclarationToken(Entry deobfEntry) { - return m_declarationToToken.get(deobfEntry); - } - - public int getLineNumber(int pos) { - // line number is 1-based - int line = 0; - for (Integer offset : m_lineOffsets) { - if (offset > pos) { - break; - } - line++; - } - return line; - } - - public int getColumnNumber(int pos) { - // column number is 1-based - return pos - m_lineOffsets.get(getLineNumber(pos) - 1) + 1; - } - - private int toPos(int line, int col) { - // line and col are 1-based - return m_lineOffsets.get(line - 1) + col - 1; - } -} diff --git a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java deleted file mode 100644 index a660a376..00000000 --- a/src/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java +++ /dev/null @@ -1,150 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import com.strobel.assembler.metadata.MemberReference; -import com.strobel.assembler.metadata.MethodDefinition; -import com.strobel.assembler.metadata.MethodReference; -import com.strobel.assembler.metadata.ParameterDefinition; -import com.strobel.assembler.metadata.TypeReference; -import com.strobel.decompiler.languages.TextLocation; -import com.strobel.decompiler.languages.java.ast.AstNode; -import com.strobel.decompiler.languages.java.ast.IdentifierExpression; -import com.strobel.decompiler.languages.java.ast.InvocationExpression; -import com.strobel.decompiler.languages.java.ast.Keys; -import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; -import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression; -import com.strobel.decompiler.languages.java.ast.ParameterDeclaration; -import com.strobel.decompiler.languages.java.ast.SimpleType; -import com.strobel.decompiler.languages.java.ast.SuperReferenceExpression; -import com.strobel.decompiler.languages.java.ast.ThisReferenceExpression; - -import cuchaz.enigma.mapping.ArgumentEntry; -import cuchaz.enigma.mapping.BehaviorEntry; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.ConstructorEntry; -import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.MethodEntry; -import cuchaz.enigma.mapping.ProcyonEntryFactory; -import cuchaz.enigma.mapping.Signature; -import cuchaz.enigma.mapping.Type; - -public class SourceIndexBehaviorVisitor extends SourceIndexVisitor { - - private BehaviorEntry m_behaviorEntry; - - public SourceIndexBehaviorVisitor(BehaviorEntry behaviorEntry) { - m_behaviorEntry = behaviorEntry; - } - - @Override - public Void visitInvocationExpression(InvocationExpression node, SourceIndex index) { - MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); - - // get the behavior entry - ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); - BehaviorEntry behaviorEntry = null; - if (ref instanceof MethodReference) { - MethodReference methodRef = (MethodReference)ref; - if (methodRef.isConstructor()) { - behaviorEntry = new ConstructorEntry(classEntry, new Signature(ref.getErasedSignature())); - } else if (methodRef.isTypeInitializer()) { - behaviorEntry = new ConstructorEntry(classEntry); - } else { - behaviorEntry = new MethodEntry(classEntry, ref.getName(), new Signature(ref.getErasedSignature())); - } - } - if (behaviorEntry != null) { - // get the node for the token - AstNode tokenNode = null; - if (node.getTarget() instanceof MemberReferenceExpression) { - tokenNode = ((MemberReferenceExpression)node.getTarget()).getMemberNameToken(); - } else if (node.getTarget() instanceof SuperReferenceExpression) { - tokenNode = node.getTarget(); - } else if (node.getTarget() instanceof ThisReferenceExpression) { - tokenNode = node.getTarget(); - } - if (tokenNode != null) { - index.addReference(tokenNode, behaviorEntry, m_behaviorEntry); - } - } - - return recurse(node, index); - } - - @Override - public Void visitMemberReferenceExpression(MemberReferenceExpression node, SourceIndex index) { - MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); - if (ref != null) { - // make sure this is actually a field - if (ref.getErasedSignature().indexOf('(') >= 0) { - throw new Error("Expected a field here! got " + ref); - } - - ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); - FieldEntry fieldEntry = new FieldEntry(classEntry, ref.getName(), new Type(ref.getErasedSignature())); - index.addReference(node.getMemberNameToken(), fieldEntry, m_behaviorEntry); - } - - return recurse(node, index); - } - - @Override - public Void visitSimpleType(SimpleType node, SourceIndex index) { - TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE); - if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) { - ClassEntry classEntry = new ClassEntry(ref.getInternalName()); - index.addReference(node.getIdentifierToken(), classEntry, m_behaviorEntry); - } - - return recurse(node, index); - } - - @Override - public Void visitParameterDeclaration(ParameterDeclaration node, SourceIndex index) { - ParameterDefinition def = node.getUserData(Keys.PARAMETER_DEFINITION); - if (def.getMethod() instanceof MethodDefinition) { - MethodDefinition methodDef = (MethodDefinition)def.getMethod(); - BehaviorEntry behaviorEntry = ProcyonEntryFactory.getBehaviorEntry(methodDef); - ArgumentEntry argumentEntry = new ArgumentEntry(behaviorEntry, def.getPosition(), node.getName()); - index.addDeclaration(node.getNameToken(), argumentEntry); - } - - return recurse(node, index); - } - - @Override - public Void visitIdentifierExpression(IdentifierExpression node, SourceIndex index) { - MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); - if (ref != null) { - ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); - FieldEntry fieldEntry = new FieldEntry(classEntry, ref.getName(), new Type(ref.getErasedSignature())); - index.addReference(node.getIdentifierToken(), fieldEntry, m_behaviorEntry); - } - - return recurse(node, index); - } - - @Override - public Void visitObjectCreationExpression(ObjectCreationExpression node, SourceIndex index) { - MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); - if (ref != null) { - ClassEntry classEntry = new ClassEntry(ref.getDeclaringType().getInternalName()); - ConstructorEntry constructorEntry = new ConstructorEntry(classEntry, new Signature(ref.getErasedSignature())); - if (node.getType() instanceof SimpleType) { - SimpleType simpleTypeNode = (SimpleType)node.getType(); - index.addReference(simpleTypeNode.getIdentifierToken(), constructorEntry, m_behaviorEntry); - } - } - - return recurse(node, index); - } -} diff --git a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java deleted file mode 100644 index db0bc0b7..00000000 --- a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java +++ /dev/null @@ -1,112 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import com.strobel.assembler.metadata.FieldDefinition; -import com.strobel.assembler.metadata.MethodDefinition; -import com.strobel.assembler.metadata.TypeDefinition; -import com.strobel.assembler.metadata.TypeReference; -import com.strobel.decompiler.languages.TextLocation; -import com.strobel.decompiler.languages.java.ast.AstNode; -import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration; -import com.strobel.decompiler.languages.java.ast.EnumValueDeclaration; -import com.strobel.decompiler.languages.java.ast.FieldDeclaration; -import com.strobel.decompiler.languages.java.ast.Keys; -import com.strobel.decompiler.languages.java.ast.MethodDeclaration; -import com.strobel.decompiler.languages.java.ast.SimpleType; -import com.strobel.decompiler.languages.java.ast.TypeDeclaration; -import com.strobel.decompiler.languages.java.ast.VariableInitializer; - -import cuchaz.enigma.mapping.BehaviorEntry; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.ConstructorEntry; -import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.ProcyonEntryFactory; - -public class SourceIndexClassVisitor extends SourceIndexVisitor { - - private ClassEntry m_classEntry; - - public SourceIndexClassVisitor(ClassEntry classEntry) { - m_classEntry = classEntry; - } - - @Override - public Void visitTypeDeclaration(TypeDeclaration node, SourceIndex index) { - // is this this class, or a subtype? - TypeDefinition def = node.getUserData(Keys.TYPE_DEFINITION); - ClassEntry classEntry = new ClassEntry(def.getInternalName()); - if (!classEntry.equals(m_classEntry)) { - // it's a sub-type, recurse - index.addDeclaration(node.getNameToken(), classEntry); - return node.acceptVisitor(new SourceIndexClassVisitor(classEntry), index); - } - - return recurse(node, index); - } - - @Override - public Void visitSimpleType(SimpleType node, SourceIndex index) { - TypeReference ref = node.getUserData(Keys.TYPE_REFERENCE); - if (node.getIdentifierToken().getStartLocation() != TextLocation.EMPTY) { - ClassEntry classEntry = new ClassEntry(ref.getInternalName()); - index.addReference(node.getIdentifierToken(), classEntry, m_classEntry); - } - - return recurse(node, index); - } - - @Override - public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) { - MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); - BehaviorEntry behaviorEntry = ProcyonEntryFactory.getBehaviorEntry(def); - AstNode tokenNode = node.getNameToken(); - - if (behaviorEntry instanceof ConstructorEntry) { - ConstructorEntry constructorEntry = (ConstructorEntry)behaviorEntry; - if (constructorEntry.isStatic()) { - // for static initializers, check elsewhere for the token node - tokenNode = node.getModifiers().firstOrNullObject(); - } - } - index.addDeclaration(tokenNode, behaviorEntry); - return node.acceptVisitor(new SourceIndexBehaviorVisitor(behaviorEntry), index); - } - - @Override - public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) { - MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); - ConstructorEntry constructorEntry = ProcyonEntryFactory.getConstructorEntry(def); - index.addDeclaration(node.getNameToken(), constructorEntry); - return node.acceptVisitor(new SourceIndexBehaviorVisitor(constructorEntry), index); - } - - @Override - public Void visitFieldDeclaration(FieldDeclaration node, SourceIndex index) { - FieldDefinition def = node.getUserData(Keys.FIELD_DEFINITION); - FieldEntry fieldEntry = ProcyonEntryFactory.getFieldEntry(def); - assert (node.getVariables().size() == 1); - VariableInitializer variable = node.getVariables().firstOrNullObject(); - index.addDeclaration(variable.getNameToken(), fieldEntry); - - return recurse(node, index); - } - - @Override - public Void visitEnumValueDeclaration(EnumValueDeclaration node, SourceIndex index) { - // treat enum declarations as field declarations - FieldDefinition def = node.getUserData(Keys.FIELD_DEFINITION); - FieldEntry fieldEntry = ProcyonEntryFactory.getFieldEntry(def); - index.addDeclaration(node.getNameToken(), fieldEntry); - - return recurse(node, index); - } -} diff --git a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java deleted file mode 100644 index 08698267..00000000 --- a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java +++ /dev/null @@ -1,452 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import com.strobel.assembler.metadata.TypeDefinition; -import com.strobel.decompiler.languages.java.ast.Annotation; -import com.strobel.decompiler.languages.java.ast.AnonymousObjectCreationExpression; -import com.strobel.decompiler.languages.java.ast.ArrayCreationExpression; -import com.strobel.decompiler.languages.java.ast.ArrayInitializerExpression; -import com.strobel.decompiler.languages.java.ast.ArraySpecifier; -import com.strobel.decompiler.languages.java.ast.AssertStatement; -import com.strobel.decompiler.languages.java.ast.AssignmentExpression; -import com.strobel.decompiler.languages.java.ast.AstNode; -import com.strobel.decompiler.languages.java.ast.BinaryOperatorExpression; -import com.strobel.decompiler.languages.java.ast.BlockStatement; -import com.strobel.decompiler.languages.java.ast.BreakStatement; -import com.strobel.decompiler.languages.java.ast.CaseLabel; -import com.strobel.decompiler.languages.java.ast.CastExpression; -import com.strobel.decompiler.languages.java.ast.CatchClause; -import com.strobel.decompiler.languages.java.ast.ClassOfExpression; -import com.strobel.decompiler.languages.java.ast.Comment; -import com.strobel.decompiler.languages.java.ast.CompilationUnit; -import com.strobel.decompiler.languages.java.ast.ComposedType; -import com.strobel.decompiler.languages.java.ast.ConditionalExpression; -import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration; -import com.strobel.decompiler.languages.java.ast.ContinueStatement; -import com.strobel.decompiler.languages.java.ast.DoWhileStatement; -import com.strobel.decompiler.languages.java.ast.EmptyStatement; -import com.strobel.decompiler.languages.java.ast.EnumValueDeclaration; -import com.strobel.decompiler.languages.java.ast.ExpressionStatement; -import com.strobel.decompiler.languages.java.ast.FieldDeclaration; -import com.strobel.decompiler.languages.java.ast.ForEachStatement; -import com.strobel.decompiler.languages.java.ast.ForStatement; -import com.strobel.decompiler.languages.java.ast.GotoStatement; -import com.strobel.decompiler.languages.java.ast.IAstVisitor; -import com.strobel.decompiler.languages.java.ast.Identifier; -import com.strobel.decompiler.languages.java.ast.IdentifierExpression; -import com.strobel.decompiler.languages.java.ast.IfElseStatement; -import com.strobel.decompiler.languages.java.ast.ImportDeclaration; -import com.strobel.decompiler.languages.java.ast.IndexerExpression; -import com.strobel.decompiler.languages.java.ast.InstanceInitializer; -import com.strobel.decompiler.languages.java.ast.InstanceOfExpression; -import com.strobel.decompiler.languages.java.ast.InvocationExpression; -import com.strobel.decompiler.languages.java.ast.JavaTokenNode; -import com.strobel.decompiler.languages.java.ast.Keys; -import com.strobel.decompiler.languages.java.ast.LabelStatement; -import com.strobel.decompiler.languages.java.ast.LabeledStatement; -import com.strobel.decompiler.languages.java.ast.LambdaExpression; -import com.strobel.decompiler.languages.java.ast.LocalTypeDeclarationStatement; -import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; -import com.strobel.decompiler.languages.java.ast.MethodDeclaration; -import com.strobel.decompiler.languages.java.ast.MethodGroupExpression; -import com.strobel.decompiler.languages.java.ast.NewLineNode; -import com.strobel.decompiler.languages.java.ast.NullReferenceExpression; -import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression; -import com.strobel.decompiler.languages.java.ast.PackageDeclaration; -import com.strobel.decompiler.languages.java.ast.ParameterDeclaration; -import com.strobel.decompiler.languages.java.ast.ParenthesizedExpression; -import com.strobel.decompiler.languages.java.ast.PrimitiveExpression; -import com.strobel.decompiler.languages.java.ast.ReturnStatement; -import com.strobel.decompiler.languages.java.ast.SimpleType; -import com.strobel.decompiler.languages.java.ast.SuperReferenceExpression; -import com.strobel.decompiler.languages.java.ast.SwitchSection; -import com.strobel.decompiler.languages.java.ast.SwitchStatement; -import com.strobel.decompiler.languages.java.ast.SynchronizedStatement; -import com.strobel.decompiler.languages.java.ast.TextNode; -import com.strobel.decompiler.languages.java.ast.ThisReferenceExpression; -import com.strobel.decompiler.languages.java.ast.ThrowStatement; -import com.strobel.decompiler.languages.java.ast.TryCatchStatement; -import com.strobel.decompiler.languages.java.ast.TypeDeclaration; -import com.strobel.decompiler.languages.java.ast.TypeParameterDeclaration; -import com.strobel.decompiler.languages.java.ast.TypeReferenceExpression; -import com.strobel.decompiler.languages.java.ast.UnaryOperatorExpression; -import com.strobel.decompiler.languages.java.ast.VariableDeclarationStatement; -import com.strobel.decompiler.languages.java.ast.VariableInitializer; -import com.strobel.decompiler.languages.java.ast.WhileStatement; -import com.strobel.decompiler.languages.java.ast.WildcardType; -import com.strobel.decompiler.patterns.Pattern; - -import cuchaz.enigma.mapping.ClassEntry; - -public class SourceIndexVisitor implements IAstVisitor { - - @Override - public Void visitTypeDeclaration(TypeDeclaration node, SourceIndex index) { - TypeDefinition def = node.getUserData(Keys.TYPE_DEFINITION); - ClassEntry classEntry = new ClassEntry(def.getInternalName()); - index.addDeclaration(node.getNameToken(), classEntry); - - return node.acceptVisitor(new SourceIndexClassVisitor(classEntry), index); - } - - protected Void recurse(AstNode node, SourceIndex index) { - for (final AstNode child : node.getChildren()) { - child.acceptVisitor(this, index); - } - return null; - } - - @Override - public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitFieldDeclaration(FieldDeclaration node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitEnumValueDeclaration(EnumValueDeclaration node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitParameterDeclaration(ParameterDeclaration node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitInvocationExpression(InvocationExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitMemberReferenceExpression(MemberReferenceExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitSimpleType(SimpleType node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitIdentifierExpression(IdentifierExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitComment(Comment node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitPatternPlaceholder(AstNode node, Pattern pattern, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitTypeReference(TypeReferenceExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitJavaTokenNode(JavaTokenNode node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitIdentifier(Identifier node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitNullReferenceExpression(NullReferenceExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitThisReferenceExpression(ThisReferenceExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitSuperReferenceExpression(SuperReferenceExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitClassOfExpression(ClassOfExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitBlockStatement(BlockStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitExpressionStatement(ExpressionStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitBreakStatement(BreakStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitContinueStatement(ContinueStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitDoWhileStatement(DoWhileStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitEmptyStatement(EmptyStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitIfElseStatement(IfElseStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitLabelStatement(LabelStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitLabeledStatement(LabeledStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitReturnStatement(ReturnStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitSwitchStatement(SwitchStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitSwitchSection(SwitchSection node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitCaseLabel(CaseLabel node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitThrowStatement(ThrowStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitCatchClause(CatchClause node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitAnnotation(Annotation node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitNewLine(NewLineNode node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitVariableDeclaration(VariableDeclarationStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitVariableInitializer(VariableInitializer node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitText(TextNode node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitImportDeclaration(ImportDeclaration node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitInitializerBlock(InstanceInitializer node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitTypeParameterDeclaration(TypeParameterDeclaration node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitCompilationUnit(CompilationUnit node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitPackageDeclaration(PackageDeclaration node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitArraySpecifier(ArraySpecifier node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitComposedType(ComposedType node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitWhileStatement(WhileStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitPrimitiveExpression(PrimitiveExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitCastExpression(CastExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitBinaryOperatorExpression(BinaryOperatorExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitInstanceOfExpression(InstanceOfExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitIndexerExpression(IndexerExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitUnaryOperatorExpression(UnaryOperatorExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitConditionalExpression(ConditionalExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitArrayInitializerExpression(ArrayInitializerExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitObjectCreationExpression(ObjectCreationExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitArrayCreationExpression(ArrayCreationExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitAssignmentExpression(AssignmentExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitForStatement(ForStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitForEachStatement(ForEachStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitTryCatchStatement(TryCatchStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitGotoStatement(GotoStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitParenthesizedExpression(ParenthesizedExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitSynchronizedStatement(SynchronizedStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitAnonymousObjectCreationExpression(AnonymousObjectCreationExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitWildcardType(WildcardType node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitMethodGroupExpression(MethodGroupExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitAssertStatement(AssertStatement node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitLambdaExpression(LambdaExpression node, SourceIndex index) { - return recurse(node, index); - } - - @Override - public Void visitLocalTypeDeclarationStatement(LocalTypeDeclarationStatement node, SourceIndex index) { - return recurse(node, index); - } -} diff --git a/src/cuchaz/enigma/analysis/Token.java b/src/cuchaz/enigma/analysis/Token.java deleted file mode 100644 index 76d63276..00000000 --- a/src/cuchaz/enigma/analysis/Token.java +++ /dev/null @@ -1,56 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -public class Token implements Comparable { - - public int start; - public int end; - public String text; - - public Token(int start, int end) { - this(start, end, null); - } - - public Token(int start, int end, String source) { - this.start = start; - this.end = end; - if (source != null) { - this.text = source.substring(start, end); - } - } - - public boolean contains(int pos) { - return pos >= start && pos <= end; - } - - @Override - public int compareTo(Token other) { - return start - other.start; - } - - @Override - public boolean equals(Object other) { - if (other instanceof Token) { - return equals((Token)other); - } - return false; - } - - public boolean equals(Token other) { - return start == other.start && end == other.end; - } - - @Override - public String toString() { - return String.format("[%d,%d]", start, end); - } -} diff --git a/src/cuchaz/enigma/analysis/TranslationIndex.java b/src/cuchaz/enigma/analysis/TranslationIndex.java deleted file mode 100644 index a491cfce..00000000 --- a/src/cuchaz/enigma/analysis/TranslationIndex.java +++ /dev/null @@ -1,298 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.OutputStream; -import java.io.Serializable; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; - -import javassist.CtBehavior; -import javassist.CtClass; -import javassist.CtField; -import javassist.bytecode.Descriptor; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; - -import cuchaz.enigma.mapping.ArgumentEntry; -import cuchaz.enigma.mapping.BehaviorEntry; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.Entry; -import cuchaz.enigma.mapping.EntryFactory; -import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.Translator; - -public class TranslationIndex implements Serializable { - - private static final long serialVersionUID = 738687982126844179L; - - private Map m_superclasses; - private Multimap m_fieldEntries; - private Multimap m_behaviorEntries; - private Multimap m_interfaces; - - public TranslationIndex() { - m_superclasses = Maps.newHashMap(); - m_fieldEntries = HashMultimap.create(); - m_behaviorEntries = HashMultimap.create(); - m_interfaces = HashMultimap.create(); - } - - public TranslationIndex(TranslationIndex other, Translator translator) { - - // translate the superclasses - m_superclasses = Maps.newHashMap(); - for (Map.Entry mapEntry : other.m_superclasses.entrySet()) { - m_superclasses.put( - translator.translateEntry(mapEntry.getKey()), - translator.translateEntry(mapEntry.getValue()) - ); - } - - // translate the interfaces - m_interfaces = HashMultimap.create(); - for (Map.Entry mapEntry : other.m_interfaces.entries()) { - m_interfaces.put( - translator.translateEntry(mapEntry.getKey()), - translator.translateEntry(mapEntry.getValue()) - ); - } - - // translate the fields - m_fieldEntries = HashMultimap.create(); - for (Map.Entry mapEntry : other.m_fieldEntries.entries()) { - m_fieldEntries.put( - translator.translateEntry(mapEntry.getKey()), - translator.translateEntry(mapEntry.getValue()) - ); - } - - m_behaviorEntries = HashMultimap.create(); - for (Map.Entry mapEntry : other.m_behaviorEntries.entries()) { - m_behaviorEntries.put( - translator.translateEntry(mapEntry.getKey()), - translator.translateEntry(mapEntry.getValue()) - ); - } - } - - public void indexClass(CtClass c) { - indexClass(c, true); - } - - public void indexClass(CtClass c, boolean indexMembers) { - - ClassEntry classEntry = EntryFactory.getClassEntry(c); - if (isJre(classEntry)) { - return; - } - - // add the superclass - ClassEntry superclassEntry = EntryFactory.getSuperclassEntry(c); - if (superclassEntry != null) { - m_superclasses.put(classEntry, superclassEntry); - } - - // add the interfaces - for (String interfaceClassName : c.getClassFile().getInterfaces()) { - ClassEntry interfaceClassEntry = new ClassEntry(Descriptor.toJvmName(interfaceClassName)); - if (!isJre(interfaceClassEntry)) { - m_interfaces.put(classEntry, interfaceClassEntry); - } - } - - if (indexMembers) { - // add fields - for (CtField field : c.getDeclaredFields()) { - FieldEntry fieldEntry = EntryFactory.getFieldEntry(field); - m_fieldEntries.put(fieldEntry.getClassEntry(), fieldEntry); - } - - // add behaviors - for (CtBehavior behavior : c.getDeclaredBehaviors()) { - BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); - m_behaviorEntries.put(behaviorEntry.getClassEntry(), behaviorEntry); - } - } - } - - public void renameClasses(Map renames) { - EntryRenamer.renameClassesInMap(renames, m_superclasses); - EntryRenamer.renameClassesInMultimap(renames, m_fieldEntries); - EntryRenamer.renameClassesInMultimap(renames, m_behaviorEntries); - } - - public ClassEntry getSuperclass(ClassEntry classEntry) { - return m_superclasses.get(classEntry); - } - - public List getAncestry(ClassEntry classEntry) { - List ancestors = Lists.newArrayList(); - while (classEntry != null) { - classEntry = getSuperclass(classEntry); - if (classEntry != null) { - ancestors.add(classEntry); - } - } - return ancestors; - } - - public List getSubclass(ClassEntry classEntry) { - - // linear search is fast enough for now - List subclasses = Lists.newArrayList(); - for (Map.Entry entry : m_superclasses.entrySet()) { - ClassEntry subclass = entry.getKey(); - ClassEntry superclass = entry.getValue(); - if (classEntry.equals(superclass)) { - subclasses.add(subclass); - } - } - return subclasses; - } - - public void getSubclassesRecursively(Set out, ClassEntry classEntry) { - for (ClassEntry subclassEntry : getSubclass(classEntry)) { - out.add(subclassEntry); - getSubclassesRecursively(out, subclassEntry); - } - } - - public void getSubclassNamesRecursively(Set out, ClassEntry classEntry) { - for (ClassEntry subclassEntry : getSubclass(classEntry)) { - out.add(subclassEntry.getName()); - getSubclassNamesRecursively(out, subclassEntry); - } - } - - public Collection> getClassInterfaces() { - return m_interfaces.entries(); - } - - public Collection getInterfaces(ClassEntry classEntry) { - return m_interfaces.get(classEntry); - } - - public boolean isInterface(ClassEntry classEntry) { - return m_interfaces.containsValue(classEntry); - } - - public boolean entryExists(Entry entry) { - if (entry instanceof FieldEntry) { - return fieldExists((FieldEntry)entry); - } else if (entry instanceof BehaviorEntry) { - return behaviorExists((BehaviorEntry)entry); - } else if (entry instanceof ArgumentEntry) { - return behaviorExists(((ArgumentEntry)entry).getBehaviorEntry()); - } - throw new IllegalArgumentException("Cannot check existence for " + entry.getClass()); - } - - public boolean fieldExists(FieldEntry fieldEntry) { - return m_fieldEntries.containsEntry(fieldEntry.getClassEntry(), fieldEntry); - } - - public boolean behaviorExists(BehaviorEntry behaviorEntry) { - return m_behaviorEntries.containsEntry(behaviorEntry.getClassEntry(), behaviorEntry); - } - - public ClassEntry resolveEntryClass(Entry entry) { - - if (entry instanceof ClassEntry) { - return (ClassEntry)entry; - } - - ClassEntry superclassEntry = resolveSuperclass(entry); - if (superclassEntry != null) { - return superclassEntry; - } - - ClassEntry interfaceEntry = resolveInterface(entry); - if (interfaceEntry != null) { - return interfaceEntry; - } - - return null; - } - - public ClassEntry resolveSuperclass(Entry entry) { - - // this entry could refer to a method on a class where the method is not actually implemented - // travel up the inheritance tree to find the closest implementation - while (!entryExists(entry)) { - - // is there a parent class? - ClassEntry superclassEntry = getSuperclass(entry.getClassEntry()); - if (superclassEntry == null) { - // this is probably a method from a class in a library - // we can't trace the implementation up any higher unless we index the library - return null; - } - - // move up to the parent class - entry = entry.cloneToNewClass(superclassEntry); - } - return entry.getClassEntry(); - } - - public ClassEntry resolveInterface(Entry entry) { - - // the interfaces for any class is a forest - // so let's look at all the trees - for (ClassEntry interfaceEntry : m_interfaces.get(entry.getClassEntry())) { - ClassEntry resolvedClassEntry = resolveSuperclass(entry.cloneToNewClass(interfaceEntry)); - if (resolvedClassEntry != null) { - return resolvedClassEntry; - } - } - return null; - } - - private boolean isJre(ClassEntry classEntry) { - String packageName = classEntry.getPackageName(); - return packageName != null && (packageName.startsWith("java") || packageName.startsWith("javax")); - } - - public void write(OutputStream out) - throws IOException { - GZIPOutputStream gzipout = new GZIPOutputStream(out); - ObjectOutputStream oout = new ObjectOutputStream(gzipout); - oout.writeObject(m_superclasses); - oout.writeObject(m_fieldEntries); - oout.writeObject(m_behaviorEntries); - gzipout.finish(); - } - - @SuppressWarnings("unchecked") - public void read(InputStream in) - throws IOException { - try { - ObjectInputStream oin = new ObjectInputStream(new GZIPInputStream(in)); - m_superclasses = (HashMap)oin.readObject(); - m_fieldEntries = (HashMultimap)oin.readObject(); - m_behaviorEntries = (HashMultimap)oin.readObject(); - } catch (ClassNotFoundException ex) { - throw new Error(ex); - } - } -} diff --git a/src/cuchaz/enigma/analysis/TreeDumpVisitor.java b/src/cuchaz/enigma/analysis/TreeDumpVisitor.java deleted file mode 100644 index 0a90bacc..00000000 --- a/src/cuchaz/enigma/analysis/TreeDumpVisitor.java +++ /dev/null @@ -1,512 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.Writer; - -import com.strobel.componentmodel.Key; -import com.strobel.decompiler.languages.java.ast.Annotation; -import com.strobel.decompiler.languages.java.ast.AnonymousObjectCreationExpression; -import com.strobel.decompiler.languages.java.ast.ArrayCreationExpression; -import com.strobel.decompiler.languages.java.ast.ArrayInitializerExpression; -import com.strobel.decompiler.languages.java.ast.ArraySpecifier; -import com.strobel.decompiler.languages.java.ast.AssertStatement; -import com.strobel.decompiler.languages.java.ast.AssignmentExpression; -import com.strobel.decompiler.languages.java.ast.AstNode; -import com.strobel.decompiler.languages.java.ast.BinaryOperatorExpression; -import com.strobel.decompiler.languages.java.ast.BlockStatement; -import com.strobel.decompiler.languages.java.ast.BreakStatement; -import com.strobel.decompiler.languages.java.ast.CaseLabel; -import com.strobel.decompiler.languages.java.ast.CastExpression; -import com.strobel.decompiler.languages.java.ast.CatchClause; -import com.strobel.decompiler.languages.java.ast.ClassOfExpression; -import com.strobel.decompiler.languages.java.ast.Comment; -import com.strobel.decompiler.languages.java.ast.CompilationUnit; -import com.strobel.decompiler.languages.java.ast.ComposedType; -import com.strobel.decompiler.languages.java.ast.ConditionalExpression; -import com.strobel.decompiler.languages.java.ast.ConstructorDeclaration; -import com.strobel.decompiler.languages.java.ast.ContinueStatement; -import com.strobel.decompiler.languages.java.ast.DoWhileStatement; -import com.strobel.decompiler.languages.java.ast.EmptyStatement; -import com.strobel.decompiler.languages.java.ast.EnumValueDeclaration; -import com.strobel.decompiler.languages.java.ast.ExpressionStatement; -import com.strobel.decompiler.languages.java.ast.FieldDeclaration; -import com.strobel.decompiler.languages.java.ast.ForEachStatement; -import com.strobel.decompiler.languages.java.ast.ForStatement; -import com.strobel.decompiler.languages.java.ast.GotoStatement; -import com.strobel.decompiler.languages.java.ast.IAstVisitor; -import com.strobel.decompiler.languages.java.ast.Identifier; -import com.strobel.decompiler.languages.java.ast.IdentifierExpression; -import com.strobel.decompiler.languages.java.ast.IfElseStatement; -import com.strobel.decompiler.languages.java.ast.ImportDeclaration; -import com.strobel.decompiler.languages.java.ast.IndexerExpression; -import com.strobel.decompiler.languages.java.ast.InstanceInitializer; -import com.strobel.decompiler.languages.java.ast.InstanceOfExpression; -import com.strobel.decompiler.languages.java.ast.InvocationExpression; -import com.strobel.decompiler.languages.java.ast.JavaTokenNode; -import com.strobel.decompiler.languages.java.ast.Keys; -import com.strobel.decompiler.languages.java.ast.LabelStatement; -import com.strobel.decompiler.languages.java.ast.LabeledStatement; -import com.strobel.decompiler.languages.java.ast.LambdaExpression; -import com.strobel.decompiler.languages.java.ast.LocalTypeDeclarationStatement; -import com.strobel.decompiler.languages.java.ast.MemberReferenceExpression; -import com.strobel.decompiler.languages.java.ast.MethodDeclaration; -import com.strobel.decompiler.languages.java.ast.MethodGroupExpression; -import com.strobel.decompiler.languages.java.ast.NewLineNode; -import com.strobel.decompiler.languages.java.ast.NullReferenceExpression; -import com.strobel.decompiler.languages.java.ast.ObjectCreationExpression; -import com.strobel.decompiler.languages.java.ast.PackageDeclaration; -import com.strobel.decompiler.languages.java.ast.ParameterDeclaration; -import com.strobel.decompiler.languages.java.ast.ParenthesizedExpression; -import com.strobel.decompiler.languages.java.ast.PrimitiveExpression; -import com.strobel.decompiler.languages.java.ast.ReturnStatement; -import com.strobel.decompiler.languages.java.ast.SimpleType; -import com.strobel.decompiler.languages.java.ast.SuperReferenceExpression; -import com.strobel.decompiler.languages.java.ast.SwitchSection; -import com.strobel.decompiler.languages.java.ast.SwitchStatement; -import com.strobel.decompiler.languages.java.ast.SynchronizedStatement; -import com.strobel.decompiler.languages.java.ast.TextNode; -import com.strobel.decompiler.languages.java.ast.ThisReferenceExpression; -import com.strobel.decompiler.languages.java.ast.ThrowStatement; -import com.strobel.decompiler.languages.java.ast.TryCatchStatement; -import com.strobel.decompiler.languages.java.ast.TypeDeclaration; -import com.strobel.decompiler.languages.java.ast.TypeParameterDeclaration; -import com.strobel.decompiler.languages.java.ast.TypeReferenceExpression; -import com.strobel.decompiler.languages.java.ast.UnaryOperatorExpression; -import com.strobel.decompiler.languages.java.ast.VariableDeclarationStatement; -import com.strobel.decompiler.languages.java.ast.VariableInitializer; -import com.strobel.decompiler.languages.java.ast.WhileStatement; -import com.strobel.decompiler.languages.java.ast.WildcardType; -import com.strobel.decompiler.patterns.Pattern; - -public class TreeDumpVisitor implements IAstVisitor { - - private File m_file; - private Writer m_out; - - public TreeDumpVisitor(File file) { - m_file = file; - m_out = null; - } - - @Override - public Void visitCompilationUnit(CompilationUnit node, Void ignored) { - try { - m_out = new FileWriter(m_file); - recurse(node, ignored); - m_out.close(); - return null; - } catch (IOException ex) { - throw new Error(ex); - } - } - - private Void recurse(AstNode node, Void ignored) { - // show the tree - try { - m_out.write(getIndent(node) + node.getClass().getSimpleName() + " " + getText(node) + " " + dumpUserData(node) + " " + node.getRegion() + "\n"); - } catch (IOException ex) { - throw new Error(ex); - } - - // recurse - for (final AstNode child : node.getChildren()) { - child.acceptVisitor(this, ignored); - } - return null; - } - - private String getText(AstNode node) { - if (node instanceof Identifier) { - return "\"" + ((Identifier)node).getName() + "\""; - } - return ""; - } - - private String dumpUserData(AstNode node) { - StringBuilder buf = new StringBuilder(); - for (Key key : Keys.ALL_KEYS) { - Object val = node.getUserData(key); - if (val != null) { - buf.append(String.format(" [%s=%s]", key, val)); - } - } - return buf.toString(); - } - - private String getIndent(AstNode node) { - StringBuilder buf = new StringBuilder(); - int depth = getDepth(node); - for (int i = 0; i < depth; i++) { - buf.append("\t"); - } - return buf.toString(); - } - - private int getDepth(AstNode node) { - int depth = -1; - while (node != null) { - depth++; - node = node.getParent(); - } - return depth; - } - - // OVERRIDES WE DON'T CARE ABOUT - - @Override - public Void visitInvocationExpression(InvocationExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitMemberReferenceExpression(MemberReferenceExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitSimpleType(SimpleType node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitMethodDeclaration(MethodDeclaration node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitConstructorDeclaration(ConstructorDeclaration node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitParameterDeclaration(ParameterDeclaration node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitFieldDeclaration(FieldDeclaration node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitTypeDeclaration(TypeDeclaration node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitComment(Comment node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitPatternPlaceholder(AstNode node, Pattern pattern, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitTypeReference(TypeReferenceExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitJavaTokenNode(JavaTokenNode node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitIdentifier(Identifier node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitNullReferenceExpression(NullReferenceExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitThisReferenceExpression(ThisReferenceExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitSuperReferenceExpression(SuperReferenceExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitClassOfExpression(ClassOfExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitBlockStatement(BlockStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitExpressionStatement(ExpressionStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitBreakStatement(BreakStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitContinueStatement(ContinueStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitDoWhileStatement(DoWhileStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitEmptyStatement(EmptyStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitIfElseStatement(IfElseStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitLabelStatement(LabelStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitLabeledStatement(LabeledStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitReturnStatement(ReturnStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitSwitchStatement(SwitchStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitSwitchSection(SwitchSection node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitCaseLabel(CaseLabel node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitThrowStatement(ThrowStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitCatchClause(CatchClause node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitAnnotation(Annotation node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitNewLine(NewLineNode node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitVariableDeclaration(VariableDeclarationStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitVariableInitializer(VariableInitializer node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitText(TextNode node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitImportDeclaration(ImportDeclaration node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitInitializerBlock(InstanceInitializer node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitTypeParameterDeclaration(TypeParameterDeclaration node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitPackageDeclaration(PackageDeclaration node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitArraySpecifier(ArraySpecifier node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitComposedType(ComposedType node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitWhileStatement(WhileStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitPrimitiveExpression(PrimitiveExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitCastExpression(CastExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitBinaryOperatorExpression(BinaryOperatorExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitInstanceOfExpression(InstanceOfExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitIndexerExpression(IndexerExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitIdentifierExpression(IdentifierExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitUnaryOperatorExpression(UnaryOperatorExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitConditionalExpression(ConditionalExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitArrayInitializerExpression(ArrayInitializerExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitObjectCreationExpression(ObjectCreationExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitArrayCreationExpression(ArrayCreationExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitAssignmentExpression(AssignmentExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitForStatement(ForStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitForEachStatement(ForEachStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitTryCatchStatement(TryCatchStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitGotoStatement(GotoStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitParenthesizedExpression(ParenthesizedExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitSynchronizedStatement(SynchronizedStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitAnonymousObjectCreationExpression(AnonymousObjectCreationExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitWildcardType(WildcardType node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitMethodGroupExpression(MethodGroupExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitEnumValueDeclaration(EnumValueDeclaration node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitAssertStatement(AssertStatement node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitLambdaExpression(LambdaExpression node, Void ignored) { - return recurse(node, ignored); - } - - @Override - public Void visitLocalTypeDeclarationStatement(LocalTypeDeclarationStatement node, Void ignored) { - return recurse(node, ignored); - } -} diff --git a/src/cuchaz/enigma/bytecode/CheckCastIterator.java b/src/cuchaz/enigma/bytecode/CheckCastIterator.java deleted file mode 100644 index 517b9d62..00000000 --- a/src/cuchaz/enigma/bytecode/CheckCastIterator.java +++ /dev/null @@ -1,127 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.bytecode; - -import java.util.Iterator; - -import javassist.bytecode.BadBytecode; -import javassist.bytecode.CodeAttribute; -import javassist.bytecode.CodeIterator; -import javassist.bytecode.ConstPool; -import javassist.bytecode.Descriptor; -import javassist.bytecode.Opcode; -import cuchaz.enigma.bytecode.CheckCastIterator.CheckCast; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.MethodEntry; -import cuchaz.enigma.mapping.Signature; - -public class CheckCastIterator implements Iterator { - - public static class CheckCast { - - public String className; - public MethodEntry prevMethodEntry; - - public CheckCast(String className, MethodEntry prevMethodEntry) { - this.className = className; - this.prevMethodEntry = prevMethodEntry; - } - } - - private ConstPool m_constants; - private CodeAttribute m_attribute; - private CodeIterator m_iter; - private CheckCast m_next; - - public CheckCastIterator(CodeAttribute codeAttribute) throws BadBytecode { - m_constants = codeAttribute.getConstPool(); - m_attribute = codeAttribute; - m_iter = m_attribute.iterator(); - - m_next = getNext(); - } - - @Override - public boolean hasNext() { - return m_next != null; - } - - @Override - public CheckCast next() { - CheckCast out = m_next; - try { - m_next = getNext(); - } catch (BadBytecode ex) { - throw new Error(ex); - } - return out; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - - private CheckCast getNext() throws BadBytecode { - int prevPos = 0; - while (m_iter.hasNext()) { - int pos = m_iter.next(); - int opcode = m_iter.byteAt(pos); - switch (opcode) { - case Opcode.CHECKCAST: - - // get the type of this op code (next two bytes are a classinfo index) - MethodEntry prevMethodEntry = getMethodEntry(prevPos); - if (prevMethodEntry != null) { - return new CheckCast(m_constants.getClassInfo(m_iter.s16bitAt(pos + 1)), prevMethodEntry); - } - break; - } - prevPos = pos; - } - return null; - } - - private MethodEntry getMethodEntry(int pos) { - switch (m_iter.byteAt(pos)) { - case Opcode.INVOKEVIRTUAL: - case Opcode.INVOKESTATIC: - case Opcode.INVOKEDYNAMIC: - case Opcode.INVOKESPECIAL: { - int index = m_iter.s16bitAt(pos + 1); - return new MethodEntry( - new ClassEntry(Descriptor.toJvmName(m_constants.getMethodrefClassName(index))), - m_constants.getMethodrefName(index), - new Signature(m_constants.getMethodrefType(index)) - ); - } - - case Opcode.INVOKEINTERFACE: { - int index = m_iter.s16bitAt(pos + 1); - return new MethodEntry( - new ClassEntry(Descriptor.toJvmName(m_constants.getInterfaceMethodrefClassName(index))), - m_constants.getInterfaceMethodrefName(index), - new Signature(m_constants.getInterfaceMethodrefType(index)) - ); - } - } - return null; - } - - public Iterable casts() { - return new Iterable() { - @Override - public Iterator iterator() { - return CheckCastIterator.this; - } - }; - } -} diff --git a/src/cuchaz/enigma/bytecode/ClassProtectifier.java b/src/cuchaz/enigma/bytecode/ClassProtectifier.java deleted file mode 100644 index f1ee4e77..00000000 --- a/src/cuchaz/enigma/bytecode/ClassProtectifier.java +++ /dev/null @@ -1,51 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.bytecode; - -import javassist.CtBehavior; -import javassist.CtClass; -import javassist.CtField; -import javassist.bytecode.AccessFlag; -import javassist.bytecode.InnerClassesAttribute; - - -public class ClassProtectifier { - - public static CtClass protectify(CtClass c) { - - // protectify all the fields - for (CtField field : c.getDeclaredFields()) { - field.setModifiers(protectify(field.getModifiers())); - } - - // protectify all the methods and constructors - for (CtBehavior behavior : c.getDeclaredBehaviors()) { - behavior.setModifiers(protectify(behavior.getModifiers())); - } - - // protectify all the inner classes - InnerClassesAttribute attr = (InnerClassesAttribute)c.getClassFile().getAttribute(InnerClassesAttribute.tag); - if (attr != null) { - for (int i=0; i { - - private static final long serialVersionUID = 317915213205066168L; - - private ClassNameReplacer m_replacer; - - public ReplacerClassMap(ClassNameReplacer replacer) { - m_replacer = replacer; - } - - @Override - public String get(Object obj) { - if (obj instanceof String) { - return get((String)obj); - } - return null; - } - - public String get(String className) { - return m_replacer.replace(className); - } - } - - public static void renameClasses(CtClass c, final Translator translator) { - renameClasses(c, new ClassNameReplacer() { - @Override - public String replace(String className) { - ClassEntry entry = translator.translateEntry(new ClassEntry(className)); - if (entry != null) { - return entry.getName(); - } - return null; - } - }); - } - - public static void moveAllClassesOutOfDefaultPackage(CtClass c, final String newPackageName) { - renameClasses(c, new ClassNameReplacer() { - @Override - public String replace(String className) { - ClassEntry entry = new ClassEntry(className); - if (entry.isInDefaultPackage()) { - return newPackageName + "/" + entry.getName(); - } - return null; - } - }); - } - - public static void moveAllClassesIntoDefaultPackage(CtClass c, final String oldPackageName) { - renameClasses(c, new ClassNameReplacer() { - @Override - public String replace(String className) { - ClassEntry entry = new ClassEntry(className); - if (entry.getPackageName().equals(oldPackageName)) { - return entry.getSimpleName(); - } - return null; - } - }); - } - - @SuppressWarnings("unchecked") - public static void renameClasses(CtClass c, ClassNameReplacer replacer) { - - // sadly, we can't use CtClass.renameClass() because SignatureAttribute.renameClass() is extremely buggy =( - - ReplacerClassMap map = new ReplacerClassMap(replacer); - ClassFile classFile = c.getClassFile(); - - // rename the constant pool (covers ClassInfo, MethodTypeInfo, and NameAndTypeInfo) - ConstPool constPool = c.getClassFile().getConstPool(); - constPool.renameClass(map); - - // rename class attributes - renameAttributes(classFile.getAttributes(), map, SignatureType.Class); - - // rename methods - for (MethodInfo methodInfo : (List)classFile.getMethods()) { - methodInfo.setDescriptor(Descriptor.rename(methodInfo.getDescriptor(), map)); - renameAttributes(methodInfo.getAttributes(), map, SignatureType.Method); - } - - // rename fields - for (FieldInfo fieldInfo : (List)classFile.getFields()) { - fieldInfo.setDescriptor(Descriptor.rename(fieldInfo.getDescriptor(), map)); - renameAttributes(fieldInfo.getAttributes(), map, SignatureType.Field); - } - - // rename the class name itself last - // NOTE: don't use the map here, because setName() calls the buggy SignatureAttribute.renameClass() - // we only want to replace exactly this class name - String newName = renameClassName(c.getName(), map); - if (newName != null) { - c.setName(newName); - } - - // replace simple names in the InnerClasses attribute too - InnerClassesAttribute attr = (InnerClassesAttribute)c.getClassFile().getAttribute(InnerClassesAttribute.tag); - if (attr != null) { - for (int i = 0; i < attr.tableLength(); i++) { - - // get the inner class full name (which has already been translated) - ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(attr.innerClass(i))); - - if (attr.innerNameIndex(i) != 0) { - // update the inner name - attr.setInnerNameIndex(i, constPool.addUtf8Info(classEntry.getInnermostClassName())); - } - - /* DEBUG - System.out.println(String.format("\tDEOBF: %s-> ATTR: %s,%s,%s", classEntry, attr.outerClass(i), attr.innerClass(i), attr.innerName(i))); - */ - } - } - } - - @SuppressWarnings("unchecked") - private static void renameAttributes(List attributes, ReplacerClassMap map, SignatureType type) { - try { - - // make the rename class method accessible - Method renameClassMethod = AttributeInfo.class.getDeclaredMethod("renameClass", Map.class); - renameClassMethod.setAccessible(true); - - for (AttributeInfo attribute : attributes) { - if (attribute instanceof SignatureAttribute) { - // this has to be handled specially because SignatureAttribute.renameClass() is buggy as hell - SignatureAttribute signatureAttribute = (SignatureAttribute)attribute; - String newSignature = type.rename(signatureAttribute.getSignature(), map); - if (newSignature != null) { - signatureAttribute.setSignature(newSignature); - } - } else if (attribute instanceof CodeAttribute) { - // code attributes have signature attributes too (indirectly) - CodeAttribute codeAttribute = (CodeAttribute)attribute; - renameAttributes(codeAttribute.getAttributes(), map, type); - } else if (attribute instanceof LocalVariableTypeAttribute) { - // lvt attributes have signature attributes too - LocalVariableTypeAttribute localVariableAttribute = (LocalVariableTypeAttribute)attribute; - renameLocalVariableTypeAttribute(localVariableAttribute, map); - } else { - renameClassMethod.invoke(attribute, map); - } - } - - } catch(NoSuchMethodException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { - throw new Error("Unable to call javassist methods by reflection!", ex); - } - } - - private static void renameLocalVariableTypeAttribute(LocalVariableTypeAttribute attribute, ReplacerClassMap map) { - - // adapted from LocalVariableAttribute.renameClass() - ConstPool cp = attribute.getConstPool(); - int n = attribute.tableLength(); - byte[] info = attribute.get(); - for (int i = 0; i < n; ++i) { - int pos = i * 10 + 2; - int index = ByteArray.readU16bit(info, pos + 6); - if (index != 0) { - String signature = cp.getUtf8Info(index); - String newSignature = renameLocalVariableSignature(signature, map); - if (newSignature != null) { - ByteArray.write16bit(cp.addUtf8Info(newSignature), info, pos + 6); - } - } - } - } - - private static String renameLocalVariableSignature(String signature, ReplacerClassMap map) { - - // for some reason, signatures with . in them don't count as field signatures - // looks like anonymous classes delimit with . in stead of $ - // convert the . to $, but keep track of how many we replace - // we need to put them back after we translate - int start = signature.lastIndexOf('$') + 1; - int numConverted = 0; - StringBuilder buf = new StringBuilder(signature); - for (int i=buf.length()-1; i>=start; i--) { - char c = buf.charAt(i); - if (c == '.') { - buf.setCharAt(i, '$'); - numConverted++; - } - } - signature = buf.toString(); - - // translate - String newSignature = renameFieldSignature(signature, map); - if (newSignature != null) { - - // put the delimiters back - buf = new StringBuilder(newSignature); - for (int i=buf.length()-1; i>=0 && numConverted > 0; i--) { - char c = buf.charAt(i); - if (c == '$') { - buf.setCharAt(i, '.'); - numConverted--; - } - } - assert(numConverted == 0); - newSignature = buf.toString(); - - return newSignature; - } - - return null; - } - - private static String renameClassSignature(String signature, ReplacerClassMap map) { - try { - ClassSignature type = renameType(SignatureAttribute.toClassSignature(signature), map); - if (type != null) { - return type.encode(); - } - return null; - } catch (BadBytecode ex) { - throw new Error("Can't parse field signature: " + signature); - } - } - - private static String renameFieldSignature(String signature, ReplacerClassMap map) { - try { - ObjectType type = renameType(SignatureAttribute.toFieldSignature(signature), map); - if (type != null) { - return type.encode(); - } - return null; - } catch (BadBytecode ex) { - throw new Error("Can't parse class signature: " + signature); - } - } - - private static String renameMethodSignature(String signature, ReplacerClassMap map) { - try { - MethodSignature type = renameType(SignatureAttribute.toMethodSignature(signature), map); - if (type != null) { - return type.encode(); - } - return null; - } catch (BadBytecode ex) { - throw new Error("Can't parse method signature: " + signature); - } - } - - private static ClassSignature renameType(ClassSignature type, ReplacerClassMap map) { - - TypeParameter[] typeParamTypes = type.getParameters(); - if (typeParamTypes != null) { - typeParamTypes = Arrays.copyOf(typeParamTypes, typeParamTypes.length); - for (int i=0; i m_constructorPool; - - static { - try { - m_getItem = ConstPool.class.getDeclaredMethod("getItem", int.class); - m_getItem.setAccessible(true); - - m_addItem = ConstPool.class.getDeclaredMethod("addItem", Class.forName("javassist.bytecode.ConstInfo")); - m_addItem.setAccessible(true); - - m_addItem0 = ConstPool.class.getDeclaredMethod("addItem0", Class.forName("javassist.bytecode.ConstInfo")); - m_addItem0.setAccessible(true); - - m_items = ConstPool.class.getDeclaredField("items"); - m_items.setAccessible(true); - - m_cache = ConstPool.class.getDeclaredField("itemsCache"); - m_cache.setAccessible(true); - - m_numItems = ConstPool.class.getDeclaredField("numOfItems"); - m_numItems.setAccessible(true); - - m_objects = Class.forName("javassist.bytecode.LongVector").getDeclaredField("objects"); - m_objects.setAccessible(true); - - m_elements = Class.forName("javassist.bytecode.LongVector").getDeclaredField("elements"); - m_elements.setAccessible(true); - - m_methodWritePool = ConstPool.class.getDeclaredMethod("write", DataOutputStream.class); - m_methodWritePool.setAccessible(true); - - m_constructorPool = ConstPool.class.getDeclaredConstructor(DataInputStream.class); - m_constructorPool.setAccessible(true); - } catch (Exception ex) { - throw new Error(ex); - } - } - - private ConstPool m_pool; - - public ConstPoolEditor(ConstPool pool) { - m_pool = pool; - } - - public void writePool(DataOutputStream out) { - try { - m_methodWritePool.invoke(m_pool, out); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public static ConstPool readPool(DataInputStream in) { - try { - return m_constructorPool.newInstance(in); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public String getMemberrefClassname(int memberrefIndex) { - return Descriptor.toJvmName(m_pool.getClassInfo(m_pool.getMemberClass(memberrefIndex))); - } - - public String getMemberrefName(int memberrefIndex) { - return m_pool.getUtf8Info(m_pool.getNameAndTypeName(m_pool.getMemberNameAndType(memberrefIndex))); - } - - public String getMemberrefType(int memberrefIndex) { - return m_pool.getUtf8Info(m_pool.getNameAndTypeDescriptor(m_pool.getMemberNameAndType(memberrefIndex))); - } - - public ConstInfoAccessor getItem(int index) { - try { - Object entry = m_getItem.invoke(m_pool, index); - if (entry == null) { - return null; - } - return new ConstInfoAccessor(entry); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public int addItem(Object item) { - try { - return (Integer)m_addItem.invoke(m_pool, item); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public int addItemForceNew(Object item) { - try { - return (Integer)m_addItem0.invoke(m_pool, item); - } catch (Exception ex) { - throw new Error(ex); - } - } - - @SuppressWarnings("rawtypes") - public void removeLastItem() { - try { - // remove the item from the cache - HashMap cache = getCache(); - if (cache != null) { - Object item = getItem(m_pool.getSize() - 1); - cache.remove(item); - } - - // remove the actual item - // based off of LongVector.addElement() - Object items = m_items.get(m_pool); - Object[][] objects = (Object[][])m_objects.get(items); - int numElements = (Integer)m_elements.get(items) - 1; - int nth = numElements >> 7; - int offset = numElements & (128 - 1); - objects[nth][offset] = null; - - // decrement the number of items - m_elements.set(items, numElements); - m_numItems.set(m_pool, (Integer)m_numItems.get(m_pool) - 1); - } catch (Exception ex) { - throw new Error(ex); - } - } - - @SuppressWarnings("rawtypes") - public HashMap getCache() { - try { - return (HashMap)m_cache.get(m_pool); - } catch (Exception ex) { - throw new Error(ex); - } - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - public void changeMemberrefNameAndType(int memberrefIndex, String newName, String newType) { - // NOTE: when changing values, we always need to copy-on-write - try { - // get the memberref item - Object item = getItem(memberrefIndex).getItem(); - - // update the cache - HashMap cache = getCache(); - if (cache != null) { - cache.remove(item); - } - - new MemberRefInfoAccessor(item).setNameAndTypeIndex(m_pool.addNameAndTypeInfo(newName, newType)); - - // update the cache - if (cache != null) { - cache.put(item, item); - } - } catch (Exception ex) { - throw new Error(ex); - } - - // make sure the change worked - assert (newName.equals(getMemberrefName(memberrefIndex))); - assert (newType.equals(getMemberrefType(memberrefIndex))); - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - public void changeClassName(int classNameIndex, String newName) { - // NOTE: when changing values, we always need to copy-on-write - try { - // get the class item - Object item = getItem(classNameIndex).getItem(); - - // update the cache - HashMap cache = getCache(); - if (cache != null) { - cache.remove(item); - } - - // add the new name and repoint the name-and-type to it - new ClassInfoAccessor(item).setNameIndex(m_pool.addUtf8Info(newName)); - - // update the cache - if (cache != null) { - cache.put(item, item); - } - } catch (Exception ex) { - throw new Error(ex); - } - } - - public static ConstPool newConstPool() { - // const pool expects the name of a class to initialize itself - // but we want an empty pool - // so give it a bogus name, and then clear the entries afterwards - ConstPool pool = new ConstPool("a"); - - ConstPoolEditor editor = new ConstPoolEditor(pool); - int size = pool.getSize(); - for (int i = 0; i < size - 1; i++) { - editor.removeLastItem(); - } - - // make sure the pool is actually empty - // although, in this case "empty" means one thing in it - // the JVM spec says index 0 should be reserved - assert (pool.getSize() == 1); - assert (editor.getItem(0) == null); - assert (editor.getItem(1) == null); - assert (editor.getItem(2) == null); - assert (editor.getItem(3) == null); - - // also, clear the cache - editor.getCache().clear(); - - return pool; - } - - public String dump() { - StringBuilder buf = new StringBuilder(); - for (int i = 1; i < m_pool.getSize(); i++) { - buf.append(String.format("%4d", i)); - buf.append(" "); - buf.append(getItem(i).toString()); - buf.append("\n"); - } - return buf.toString(); - } -} diff --git a/src/cuchaz/enigma/bytecode/InfoType.java b/src/cuchaz/enigma/bytecode/InfoType.java deleted file mode 100644 index 08f2b3e2..00000000 --- a/src/cuchaz/enigma/bytecode/InfoType.java +++ /dev/null @@ -1,317 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.bytecode; - -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - -import cuchaz.enigma.bytecode.accessors.ClassInfoAccessor; -import cuchaz.enigma.bytecode.accessors.ConstInfoAccessor; -import cuchaz.enigma.bytecode.accessors.InvokeDynamicInfoAccessor; -import cuchaz.enigma.bytecode.accessors.MemberRefInfoAccessor; -import cuchaz.enigma.bytecode.accessors.MethodHandleInfoAccessor; -import cuchaz.enigma.bytecode.accessors.MethodTypeInfoAccessor; -import cuchaz.enigma.bytecode.accessors.NameAndTypeInfoAccessor; -import cuchaz.enigma.bytecode.accessors.StringInfoAccessor; - -public enum InfoType { - - Utf8Info( 1, 0 ), - IntegerInfo( 3, 0 ), - FloatInfo( 4, 0 ), - LongInfo( 5, 0 ), - DoubleInfo( 6, 0 ), - ClassInfo( 7, 1 ) { - - @Override - public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { - ClassInfoAccessor accessor = new ClassInfoAccessor(entry.getItem()); - gatherIndexTree(indices, editor, accessor.getNameIndex()); - } - - @Override - public void remapIndices(Map map, ConstInfoAccessor entry) { - ClassInfoAccessor accessor = new ClassInfoAccessor(entry.getItem()); - accessor.setNameIndex(remapIndex(map, accessor.getNameIndex())); - } - - @Override - public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { - ClassInfoAccessor accessor = new ClassInfoAccessor(entry.getItem()); - ConstInfoAccessor nameEntry = pool.getItem(accessor.getNameIndex()); - return nameEntry != null && nameEntry.getTag() == Utf8Info.getTag(); - } - }, - StringInfo( 8, 1 ) { - - @Override - public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { - StringInfoAccessor accessor = new StringInfoAccessor(entry.getItem()); - gatherIndexTree(indices, editor, accessor.getStringIndex()); - } - - @Override - public void remapIndices(Map map, ConstInfoAccessor entry) { - StringInfoAccessor accessor = new StringInfoAccessor(entry.getItem()); - accessor.setStringIndex(remapIndex(map, accessor.getStringIndex())); - } - - @Override - public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { - StringInfoAccessor accessor = new StringInfoAccessor(entry.getItem()); - ConstInfoAccessor stringEntry = pool.getItem(accessor.getStringIndex()); - return stringEntry != null && stringEntry.getTag() == Utf8Info.getTag(); - } - }, - FieldRefInfo( 9, 2 ) { - - @Override - public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { - MemberRefInfoAccessor accessor = new MemberRefInfoAccessor(entry.getItem()); - gatherIndexTree(indices, editor, accessor.getClassIndex()); - gatherIndexTree(indices, editor, accessor.getNameAndTypeIndex()); - } - - @Override - public void remapIndices(Map map, ConstInfoAccessor entry) { - MemberRefInfoAccessor accessor = new MemberRefInfoAccessor(entry.getItem()); - accessor.setClassIndex(remapIndex(map, accessor.getClassIndex())); - accessor.setNameAndTypeIndex(remapIndex(map, accessor.getNameAndTypeIndex())); - } - - @Override - public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { - MemberRefInfoAccessor accessor = new MemberRefInfoAccessor(entry.getItem()); - ConstInfoAccessor classEntry = pool.getItem(accessor.getClassIndex()); - ConstInfoAccessor nameAndTypeEntry = pool.getItem(accessor.getNameAndTypeIndex()); - return classEntry != null && classEntry.getTag() == ClassInfo.getTag() && nameAndTypeEntry != null && nameAndTypeEntry.getTag() == NameAndTypeInfo.getTag(); - } - }, - // same as FieldRefInfo - MethodRefInfo( 10, 2 ) { - - @Override - public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { - FieldRefInfo.gatherIndexTree(indices, editor, entry); - } - - @Override - public void remapIndices(Map map, ConstInfoAccessor entry) { - FieldRefInfo.remapIndices(map, entry); - } - - @Override - public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { - return FieldRefInfo.subIndicesAreValid(entry, pool); - } - }, - // same as FieldRefInfo - InterfaceMethodRefInfo( 11, 2 ) { - - @Override - public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { - FieldRefInfo.gatherIndexTree(indices, editor, entry); - } - - @Override - public void remapIndices(Map map, ConstInfoAccessor entry) { - FieldRefInfo.remapIndices(map, entry); - } - - @Override - public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { - return FieldRefInfo.subIndicesAreValid(entry, pool); - } - }, - NameAndTypeInfo( 12, 1 ) { - - @Override - public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { - NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor(entry.getItem()); - gatherIndexTree(indices, editor, accessor.getNameIndex()); - gatherIndexTree(indices, editor, accessor.getTypeIndex()); - } - - @Override - public void remapIndices(Map map, ConstInfoAccessor entry) { - NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor(entry.getItem()); - accessor.setNameIndex(remapIndex(map, accessor.getNameIndex())); - accessor.setTypeIndex(remapIndex(map, accessor.getTypeIndex())); - } - - @Override - public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { - NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor(entry.getItem()); - ConstInfoAccessor nameEntry = pool.getItem(accessor.getNameIndex()); - ConstInfoAccessor typeEntry = pool.getItem(accessor.getTypeIndex()); - return nameEntry != null && nameEntry.getTag() == Utf8Info.getTag() && typeEntry != null && typeEntry.getTag() == Utf8Info.getTag(); - } - }, - MethodHandleInfo( 15, 3 ) { - - @Override - public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { - MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor(entry.getItem()); - gatherIndexTree(indices, editor, accessor.getTypeIndex()); - gatherIndexTree(indices, editor, accessor.getMethodRefIndex()); - } - - @Override - public void remapIndices(Map map, ConstInfoAccessor entry) { - MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor(entry.getItem()); - accessor.setTypeIndex(remapIndex(map, accessor.getTypeIndex())); - accessor.setMethodRefIndex(remapIndex(map, accessor.getMethodRefIndex())); - } - - @Override - public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { - MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor(entry.getItem()); - ConstInfoAccessor typeEntry = pool.getItem(accessor.getTypeIndex()); - ConstInfoAccessor methodRefEntry = pool.getItem(accessor.getMethodRefIndex()); - return typeEntry != null && typeEntry.getTag() == Utf8Info.getTag() && methodRefEntry != null && methodRefEntry.getTag() == MethodRefInfo.getTag(); - } - }, - MethodTypeInfo( 16, 1 ) { - - @Override - public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { - MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor(entry.getItem()); - gatherIndexTree(indices, editor, accessor.getTypeIndex()); - } - - @Override - public void remapIndices(Map map, ConstInfoAccessor entry) { - MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor(entry.getItem()); - accessor.setTypeIndex(remapIndex(map, accessor.getTypeIndex())); - } - - @Override - public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { - MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor(entry.getItem()); - ConstInfoAccessor typeEntry = pool.getItem(accessor.getTypeIndex()); - return typeEntry != null && typeEntry.getTag() == Utf8Info.getTag(); - } - }, - InvokeDynamicInfo( 18, 2 ) { - - @Override - public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { - InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor(entry.getItem()); - gatherIndexTree(indices, editor, accessor.getBootstrapIndex()); - gatherIndexTree(indices, editor, accessor.getNameAndTypeIndex()); - } - - @Override - public void remapIndices(Map map, ConstInfoAccessor entry) { - InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor(entry.getItem()); - accessor.setBootstrapIndex(remapIndex(map, accessor.getBootstrapIndex())); - accessor.setNameAndTypeIndex(remapIndex(map, accessor.getNameAndTypeIndex())); - } - - @Override - public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { - InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor(entry.getItem()); - ConstInfoAccessor bootstrapEntry = pool.getItem(accessor.getBootstrapIndex()); - ConstInfoAccessor nameAndTypeEntry = pool.getItem(accessor.getNameAndTypeIndex()); - return bootstrapEntry != null && bootstrapEntry.getTag() == Utf8Info.getTag() && nameAndTypeEntry != null && nameAndTypeEntry.getTag() == NameAndTypeInfo.getTag(); - } - }; - - private static Map m_types; - - static { - m_types = Maps.newTreeMap(); - for (InfoType type : values()) { - m_types.put(type.getTag(), type); - } - } - - private int m_tag; - private int m_level; - - private InfoType(int tag, int level) { - m_tag = tag; - m_level = level; - } - - public int getTag() { - return m_tag; - } - - public int getLevel() { - return m_level; - } - - public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { - // by default, do nothing - } - - public void remapIndices(Map map, ConstInfoAccessor entry) { - // by default, do nothing - } - - public boolean subIndicesAreValid(ConstInfoAccessor entry, ConstPoolEditor pool) { - // by default, everything is good - return true; - } - - public boolean selfIndexIsValid(ConstInfoAccessor entry, ConstPoolEditor pool) { - ConstInfoAccessor entryCheck = pool.getItem(entry.getIndex()); - if (entryCheck == null) { - return false; - } - return entryCheck.getItem().equals(entry.getItem()); - } - - public static InfoType getByTag(int tag) { - return m_types.get(tag); - } - - public static List getByLevel(int level) { - List types = Lists.newArrayList(); - for (InfoType type : values()) { - if (type.getLevel() == level) { - types.add(type); - } - } - return types; - } - - public static List getSortedByLevel() { - List types = Lists.newArrayList(); - types.addAll(getByLevel(0)); - types.addAll(getByLevel(1)); - types.addAll(getByLevel(2)); - types.addAll(getByLevel(3)); - return types; - } - - public static void gatherIndexTree(Collection indices, ConstPoolEditor editor, int index) { - // add own index - indices.add(index); - - // recurse - ConstInfoAccessor entry = editor.getItem(index); - entry.getType().gatherIndexTree(indices, editor, entry); - } - - private static int remapIndex(Map map, int index) { - Integer newIndex = map.get(index); - if (newIndex == null) { - newIndex = index; - } - return newIndex; - } -} diff --git a/src/cuchaz/enigma/bytecode/InnerClassWriter.java b/src/cuchaz/enigma/bytecode/InnerClassWriter.java deleted file mode 100644 index bdb1b5df..00000000 --- a/src/cuchaz/enigma/bytecode/InnerClassWriter.java +++ /dev/null @@ -1,132 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.bytecode; - -import java.util.Collection; -import java.util.List; - -import com.google.common.collect.Lists; - -import javassist.CtClass; -import javassist.bytecode.AccessFlag; -import javassist.bytecode.ConstPool; -import javassist.bytecode.EnclosingMethodAttribute; -import javassist.bytecode.InnerClassesAttribute; -import cuchaz.enigma.analysis.JarIndex; -import cuchaz.enigma.mapping.BehaviorEntry; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.EntryFactory; - -public class InnerClassWriter { - - private JarIndex m_index; - - public InnerClassWriter(JarIndex index) { - m_index = index; - } - - public void write(CtClass c) { - - // don't change anything if there's already an attribute there - InnerClassesAttribute oldAttr = (InnerClassesAttribute)c.getClassFile().getAttribute(InnerClassesAttribute.tag); - if (oldAttr != null) { - // bail! - return; - } - - ClassEntry obfClassEntry = EntryFactory.getClassEntry(c); - List obfClassChain = m_index.getObfClassChain(obfClassEntry); - - boolean isInnerClass = obfClassChain.size() > 1; - if (isInnerClass) { - - // it's an inner class, rename it to the fully qualified name - c.setName(obfClassEntry.buildClassEntry(obfClassChain).getName()); - - BehaviorEntry caller = m_index.getAnonymousClassCaller(obfClassEntry); - if (caller != null) { - - // write the enclosing method attribute - if (caller.getName().equals("")) { - c.getClassFile().addAttribute(new EnclosingMethodAttribute(c.getClassFile().getConstPool(), caller.getClassName())); - } else { - c.getClassFile().addAttribute(new EnclosingMethodAttribute(c.getClassFile().getConstPool(), caller.getClassName(), caller.getName(), caller.getSignature().toString())); - } - } - } - - // does this class have any inner classes? - Collection obfInnerClassEntries = m_index.getInnerClasses(obfClassEntry); - - if (isInnerClass || !obfInnerClassEntries.isEmpty()) { - - // create an inner class attribute - InnerClassesAttribute attr = new InnerClassesAttribute(c.getClassFile().getConstPool()); - c.getClassFile().addAttribute(attr); - - // write the ancestry, but not the outermost class - for (int i=1; i extendedObfClassChain = Lists.newArrayList(obfClassChain); - extendedObfClassChain.add(obfInnerClassEntry); - - writeInnerClass(attr, extendedObfClassChain, obfInnerClassEntry); - - // update references to use the fully qualified inner class name - c.replaceClassName(obfInnerClassEntry.getName(), obfInnerClassEntry.buildClassEntry(extendedObfClassChain).getName()); - } - } - } - - private void writeInnerClass(InnerClassesAttribute attr, List obfClassChain, ClassEntry obfClassEntry) { - - // get the new inner class name - ClassEntry obfInnerClassEntry = obfClassEntry.buildClassEntry(obfClassChain); - ClassEntry obfOuterClassEntry = obfInnerClassEntry.getOuterClassEntry(); - - // here's what the JVM spec says about the InnerClasses attribute - // append(inner, parent, 0 if anonymous else simple name, flags); - - // update the attribute with this inner class - ConstPool constPool = attr.getConstPool(); - int innerClassIndex = constPool.addClassInfo(obfInnerClassEntry.getName()); - int parentClassIndex = constPool.addClassInfo(obfOuterClassEntry.getName()); - int innerClassNameIndex = 0; - int accessFlags = AccessFlag.PUBLIC; - // TODO: need to figure out if we can put static or not - if (!m_index.isAnonymousClass(obfClassEntry)) { - innerClassNameIndex = constPool.addUtf8Info(obfInnerClassEntry.getInnermostClassName()); - } - - attr.append(innerClassIndex, parentClassIndex, innerClassNameIndex, accessFlags); - - /* DEBUG - System.out.println(String.format("\tOBF: %s -> ATTR: %s,%s,%s (replace %s with %s)", - obfClassEntry, - attr.innerClass(attr.tableLength() - 1), - attr.outerClass(attr.tableLength() - 1), - attr.innerName(attr.tableLength() - 1), - Constants.NonePackage + "/" + obfInnerClassName, - obfClassEntry.getName() - )); - */ - } -} diff --git a/src/cuchaz/enigma/bytecode/LocalVariableRenamer.java b/src/cuchaz/enigma/bytecode/LocalVariableRenamer.java deleted file mode 100644 index ae0455f9..00000000 --- a/src/cuchaz/enigma/bytecode/LocalVariableRenamer.java +++ /dev/null @@ -1,123 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.bytecode; - -import javassist.CtBehavior; -import javassist.CtClass; -import javassist.bytecode.ByteArray; -import javassist.bytecode.CodeAttribute; -import javassist.bytecode.ConstPool; -import javassist.bytecode.LocalVariableAttribute; -import javassist.bytecode.LocalVariableTypeAttribute; -import cuchaz.enigma.mapping.ArgumentEntry; -import cuchaz.enigma.mapping.BehaviorEntry; -import cuchaz.enigma.mapping.EntryFactory; -import cuchaz.enigma.mapping.Translator; - - -public class LocalVariableRenamer { - - private Translator m_translator; - - public LocalVariableRenamer(Translator translator) { - m_translator = translator; - } - - public void rename(CtClass c) { - for (CtBehavior behavior : c.getDeclaredBehaviors()) { - - // if there's a local variable table, just rename everything to v1, v2, v3, ... for now - CodeAttribute codeAttribute = behavior.getMethodInfo().getCodeAttribute(); - if (codeAttribute == null) { - continue; - } - - BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); - ConstPool constants = c.getClassFile().getConstPool(); - - LocalVariableAttribute table = (LocalVariableAttribute)codeAttribute.getAttribute(LocalVariableAttribute.tag); - if (table != null) { - renameLVT(behaviorEntry, constants, table); - } - - LocalVariableTypeAttribute typeTable = (LocalVariableTypeAttribute)codeAttribute.getAttribute(LocalVariableAttribute.typeTag); - if (typeTable != null) { - renameLVTT(typeTable, table); - } - } - } - - // DEBUG - @SuppressWarnings("unused") - private void dumpTable(LocalVariableAttribute table) { - for (int i=0; i names = new ArrayList(numParams); - for (int i = 0; i < numParams; i++) { - names.add(m_translator.translate(new ArgumentEntry(behaviorEntry, i, ""))); - } - - // save the mappings to the class - MethodParametersAttribute.updateClass(behavior.getMethodInfo(), names); - } - } -} diff --git a/src/cuchaz/enigma/bytecode/MethodParametersAttribute.java b/src/cuchaz/enigma/bytecode/MethodParametersAttribute.java deleted file mode 100644 index 512e65a0..00000000 --- a/src/cuchaz/enigma/bytecode/MethodParametersAttribute.java +++ /dev/null @@ -1,86 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.bytecode; - -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import javassist.bytecode.AttributeInfo; -import javassist.bytecode.ConstPool; -import javassist.bytecode.MethodInfo; - -public class MethodParametersAttribute extends AttributeInfo { - - private MethodParametersAttribute(ConstPool pool, List parameterNameIndices) { - super(pool, "MethodParameters", writeStruct(parameterNameIndices)); - } - - public static void updateClass(MethodInfo info, List names) { - - // add the names to the class const pool - ConstPool constPool = info.getConstPool(); - List parameterNameIndices = new ArrayList(); - for (String name : names) { - if (name != null) { - parameterNameIndices.add(constPool.addUtf8Info(name)); - } else { - parameterNameIndices.add(0); - } - } - - // add the attribute to the method - info.addAttribute(new MethodParametersAttribute(constPool, parameterNameIndices)); - } - - private static byte[] writeStruct(List parameterNameIndices) { - // JVM 8 Spec says the struct looks like this: - // http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.24 - // uint8 num_params - // for each param: - // uint16 name_index -> points to UTF8 entry in constant pool, or 0 for no entry - // uint16 access_flags -> don't care, just set to 0 - - ByteArrayOutputStream buf = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(buf); - - // NOTE: java hates unsigned integers, so we have to be careful here - // the writeShort(), writeByte() methods will read 16,8 low-order bits from the int argument - // as long as the int argument is in range of the unsigned short/byte type, it will be written as an unsigned short/byte - // if the int is out of range, the byte stream won't look the way we want and weird things will happen - final int SIZEOF_UINT8 = 1; - final int SIZEOF_UINT16 = 2; - final int MAX_UINT8 = (1 << 8) - 1; - final int MAX_UINT16 = (1 << 16) - 1; - - try { - assert (parameterNameIndices.size() >= 0 && parameterNameIndices.size() <= MAX_UINT8); - out.writeByte(parameterNameIndices.size()); - - for (Integer index : parameterNameIndices) { - assert (index >= 0 && index <= MAX_UINT16); - out.writeShort(index); - - // just write 0 for the access flags - out.writeShort(0); - } - - out.close(); - byte[] data = buf.toByteArray(); - assert (data.length == SIZEOF_UINT8 + parameterNameIndices.size() * (SIZEOF_UINT16 + SIZEOF_UINT16)); - return data; - } catch (IOException ex) { - throw new Error(ex); - } - } -} diff --git a/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java deleted file mode 100644 index 9072c29a..00000000 --- a/src/cuchaz/enigma/bytecode/accessors/ClassInfoAccessor.java +++ /dev/null @@ -1,55 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.bytecode.accessors; - -import java.lang.reflect.Field; - -public class ClassInfoAccessor { - - private static Class m_class; - private static Field m_nameIndex; - - static { - try { - m_class = Class.forName("javassist.bytecode.ClassInfo"); - m_nameIndex = m_class.getDeclaredField("name"); - m_nameIndex.setAccessible(true); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public static boolean isType(ConstInfoAccessor accessor) { - return m_class.isAssignableFrom(accessor.getItem().getClass()); - } - - private Object m_item; - - public ClassInfoAccessor(Object item) { - m_item = item; - } - - public int getNameIndex() { - try { - return (Integer)m_nameIndex.get(m_item); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public void setNameIndex(int val) { - try { - m_nameIndex.set(m_item, val); - } catch (Exception ex) { - throw new Error(ex); - } - } -} diff --git a/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java deleted file mode 100644 index ede04738..00000000 --- a/src/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java +++ /dev/null @@ -1,156 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.bytecode.accessors; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.PrintWriter; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; - -import cuchaz.enigma.bytecode.InfoType; - -public class ConstInfoAccessor { - - private static Class m_class; - private static Field m_index; - private static Method m_getTag; - - static { - try { - m_class = Class.forName("javassist.bytecode.ConstInfo"); - m_index = m_class.getDeclaredField("index"); - m_index.setAccessible(true); - m_getTag = m_class.getMethod("getTag"); - m_getTag.setAccessible(true); - } catch (Exception ex) { - throw new Error(ex); - } - } - - private Object m_item; - - public ConstInfoAccessor(Object item) { - if (item == null) { - throw new IllegalArgumentException("item cannot be null!"); - } - m_item = item; - } - - public ConstInfoAccessor(DataInputStream in) throws IOException { - try { - // read the entry - String className = in.readUTF(); - int oldIndex = in.readInt(); - - // NOTE: ConstInfo instances write a type id (a "tag"), but they don't read it back - // so we have to read it here - in.readByte(); - - Constructor constructor = Class.forName(className).getConstructor(DataInputStream.class, int.class); - constructor.setAccessible(true); - m_item = constructor.newInstance(in, oldIndex); - } catch (IOException ex) { - throw ex; - } catch (Exception ex) { - throw new Error(ex); - } - } - - public Object getItem() { - return m_item; - } - - public int getIndex() { - try { - return (Integer)m_index.get(m_item); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public void setIndex(int val) { - try { - m_index.set(m_item, val); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public int getTag() { - try { - return (Integer)m_getTag.invoke(m_item); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public ConstInfoAccessor copy() { - return new ConstInfoAccessor(copyItem()); - } - - public Object copyItem() { - // I don't know of a simpler way to copy one of these silly things... - try { - // serialize the item - ByteArrayOutputStream buf = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(buf); - write(out); - - // deserialize the item - DataInputStream in = new DataInputStream(new ByteArrayInputStream(buf.toByteArray())); - Object item = new ConstInfoAccessor(in).getItem(); - in.close(); - - return item; - } catch (Exception ex) { - throw new Error(ex); - } - } - - public void write(DataOutputStream out) throws IOException { - try { - out.writeUTF(m_item.getClass().getName()); - out.writeInt(getIndex()); - - Method method = m_item.getClass().getMethod("write", DataOutputStream.class); - method.setAccessible(true); - method.invoke(m_item, out); - } catch (IOException ex) { - throw ex; - } catch (Exception ex) { - throw new Error(ex); - } - } - - @Override - public String toString() { - try { - ByteArrayOutputStream buf = new ByteArrayOutputStream(); - PrintWriter out = new PrintWriter(buf); - Method print = m_item.getClass().getMethod("print", PrintWriter.class); - print.setAccessible(true); - print.invoke(m_item, out); - out.close(); - return buf.toString().replace("\n", ""); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public InfoType getType() { - return InfoType.getByTag(getTag()); - } -} diff --git a/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java deleted file mode 100644 index 82af0b99..00000000 --- a/src/cuchaz/enigma/bytecode/accessors/InvokeDynamicInfoAccessor.java +++ /dev/null @@ -1,74 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.bytecode.accessors; - -import java.lang.reflect.Field; - -public class InvokeDynamicInfoAccessor { - - private static Class m_class; - private static Field m_bootstrapIndex; - private static Field m_nameAndTypeIndex; - - static { - try { - m_class = Class.forName("javassist.bytecode.InvokeDynamicInfo"); - m_bootstrapIndex = m_class.getDeclaredField("bootstrap"); - m_bootstrapIndex.setAccessible(true); - m_nameAndTypeIndex = m_class.getDeclaredField("nameAndType"); - m_nameAndTypeIndex.setAccessible(true); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public static boolean isType(ConstInfoAccessor accessor) { - return m_class.isAssignableFrom(accessor.getItem().getClass()); - } - - private Object m_item; - - public InvokeDynamicInfoAccessor(Object item) { - m_item = item; - } - - public int getBootstrapIndex() { - try { - return (Integer)m_bootstrapIndex.get(m_item); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public void setBootstrapIndex(int val) { - try { - m_bootstrapIndex.set(m_item, val); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public int getNameAndTypeIndex() { - try { - return (Integer)m_nameAndTypeIndex.get(m_item); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public void setNameAndTypeIndex(int val) { - try { - m_nameAndTypeIndex.set(m_item, val); - } catch (Exception ex) { - throw new Error(ex); - } - } -} diff --git a/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java deleted file mode 100644 index 71ee5b73..00000000 --- a/src/cuchaz/enigma/bytecode/accessors/MemberRefInfoAccessor.java +++ /dev/null @@ -1,74 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.bytecode.accessors; - -import java.lang.reflect.Field; - -public class MemberRefInfoAccessor { - - private static Class m_class; - private static Field m_classIndex; - private static Field m_nameAndTypeIndex; - - static { - try { - m_class = Class.forName("javassist.bytecode.MemberrefInfo"); - m_classIndex = m_class.getDeclaredField("classIndex"); - m_classIndex.setAccessible(true); - m_nameAndTypeIndex = m_class.getDeclaredField("nameAndTypeIndex"); - m_nameAndTypeIndex.setAccessible(true); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public static boolean isType(ConstInfoAccessor accessor) { - return m_class.isAssignableFrom(accessor.getItem().getClass()); - } - - private Object m_item; - - public MemberRefInfoAccessor(Object item) { - m_item = item; - } - - public int getClassIndex() { - try { - return (Integer)m_classIndex.get(m_item); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public void setClassIndex(int val) { - try { - m_classIndex.set(m_item, val); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public int getNameAndTypeIndex() { - try { - return (Integer)m_nameAndTypeIndex.get(m_item); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public void setNameAndTypeIndex(int val) { - try { - m_nameAndTypeIndex.set(m_item, val); - } catch (Exception ex) { - throw new Error(ex); - } - } -} diff --git a/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java deleted file mode 100644 index 172b0c51..00000000 --- a/src/cuchaz/enigma/bytecode/accessors/MethodHandleInfoAccessor.java +++ /dev/null @@ -1,74 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.bytecode.accessors; - -import java.lang.reflect.Field; - -public class MethodHandleInfoAccessor { - - private static Class m_class; - private static Field m_kindIndex; - private static Field m_indexIndex; - - static { - try { - m_class = Class.forName("javassist.bytecode.MethodHandleInfo"); - m_kindIndex = m_class.getDeclaredField("refKind"); - m_kindIndex.setAccessible(true); - m_indexIndex = m_class.getDeclaredField("refIndex"); - m_indexIndex.setAccessible(true); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public static boolean isType(ConstInfoAccessor accessor) { - return m_class.isAssignableFrom(accessor.getItem().getClass()); - } - - private Object m_item; - - public MethodHandleInfoAccessor(Object item) { - m_item = item; - } - - public int getTypeIndex() { - try { - return (Integer)m_kindIndex.get(m_item); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public void setTypeIndex(int val) { - try { - m_kindIndex.set(m_item, val); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public int getMethodRefIndex() { - try { - return (Integer)m_indexIndex.get(m_item); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public void setMethodRefIndex(int val) { - try { - m_indexIndex.set(m_item, val); - } catch (Exception ex) { - throw new Error(ex); - } - } -} diff --git a/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java deleted file mode 100644 index 0099a843..00000000 --- a/src/cuchaz/enigma/bytecode/accessors/MethodTypeInfoAccessor.java +++ /dev/null @@ -1,55 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.bytecode.accessors; - -import java.lang.reflect.Field; - -public class MethodTypeInfoAccessor { - - private static Class m_class; - private static Field m_descriptorIndex; - - static { - try { - m_class = Class.forName("javassist.bytecode.MethodTypeInfo"); - m_descriptorIndex = m_class.getDeclaredField("descriptor"); - m_descriptorIndex.setAccessible(true); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public static boolean isType(ConstInfoAccessor accessor) { - return m_class.isAssignableFrom(accessor.getItem().getClass()); - } - - private Object m_item; - - public MethodTypeInfoAccessor(Object item) { - m_item = item; - } - - public int getTypeIndex() { - try { - return (Integer)m_descriptorIndex.get(m_item); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public void setTypeIndex(int val) { - try { - m_descriptorIndex.set(m_item, val); - } catch (Exception ex) { - throw new Error(ex); - } - } -} diff --git a/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java deleted file mode 100644 index 3ecc1297..00000000 --- a/src/cuchaz/enigma/bytecode/accessors/NameAndTypeInfoAccessor.java +++ /dev/null @@ -1,74 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.bytecode.accessors; - -import java.lang.reflect.Field; - -public class NameAndTypeInfoAccessor { - - private static Class m_class; - private static Field m_nameIndex; - private static Field m_typeIndex; - - static { - try { - m_class = Class.forName("javassist.bytecode.NameAndTypeInfo"); - m_nameIndex = m_class.getDeclaredField("memberName"); - m_nameIndex.setAccessible(true); - m_typeIndex = m_class.getDeclaredField("typeDescriptor"); - m_typeIndex.setAccessible(true); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public static boolean isType(ConstInfoAccessor accessor) { - return m_class.isAssignableFrom(accessor.getItem().getClass()); - } - - private Object m_item; - - public NameAndTypeInfoAccessor(Object item) { - m_item = item; - } - - public int getNameIndex() { - try { - return (Integer)m_nameIndex.get(m_item); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public void setNameIndex(int val) { - try { - m_nameIndex.set(m_item, val); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public int getTypeIndex() { - try { - return (Integer)m_typeIndex.get(m_item); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public void setTypeIndex(int val) { - try { - m_typeIndex.set(m_item, val); - } catch (Exception ex) { - throw new Error(ex); - } - } -} diff --git a/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java deleted file mode 100644 index f150612e..00000000 --- a/src/cuchaz/enigma/bytecode/accessors/StringInfoAccessor.java +++ /dev/null @@ -1,55 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.bytecode.accessors; - -import java.lang.reflect.Field; - -public class StringInfoAccessor { - - private static Class m_class; - private static Field m_stringIndex; - - static { - try { - m_class = Class.forName("javassist.bytecode.StringInfo"); - m_stringIndex = m_class.getDeclaredField("string"); - m_stringIndex.setAccessible(true); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public static boolean isType(ConstInfoAccessor accessor) { - return m_class.isAssignableFrom(accessor.getItem().getClass()); - } - - private Object m_item; - - public StringInfoAccessor(Object item) { - m_item = item; - } - - public int getStringIndex() { - try { - return (Integer)m_stringIndex.get(m_item); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public void setStringIndex(int val) { - try { - m_stringIndex.set(m_item, val); - } catch (Exception ex) { - throw new Error(ex); - } - } -} diff --git a/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java b/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java deleted file mode 100644 index 38e8ff99..00000000 --- a/src/cuchaz/enigma/bytecode/accessors/Utf8InfoAccessor.java +++ /dev/null @@ -1,28 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.bytecode.accessors; - -public class Utf8InfoAccessor { - - private static Class m_class; - - static { - try { - m_class = Class.forName("javassist.bytecode.Utf8Info"); - } catch (Exception ex) { - throw new Error(ex); - } - } - - public static boolean isType(ConstInfoAccessor accessor) { - return m_class.isAssignableFrom(accessor.getItem().getClass()); - } -} diff --git a/src/cuchaz/enigma/convert/ClassForest.java b/src/cuchaz/enigma/convert/ClassForest.java deleted file mode 100644 index 0407730e..00000000 --- a/src/cuchaz/enigma/convert/ClassForest.java +++ /dev/null @@ -1,60 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.convert; - -import java.util.Collection; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; - -import cuchaz.enigma.mapping.ClassEntry; - - -public class ClassForest { - - private ClassIdentifier m_identifier; - private Multimap m_forest; - - public ClassForest(ClassIdentifier identifier) { - m_identifier = identifier; - m_forest = HashMultimap.create(); - } - - public void addAll(Iterable entries) { - for (ClassEntry entry : entries) { - add(entry); - } - } - - public void add(ClassEntry entry) { - try { - m_forest.put(m_identifier.identify(entry), entry); - } catch (ClassNotFoundException ex) { - throw new Error("Unable to find class " + entry.getName()); - } - } - - public Collection identities() { - return m_forest.keySet(); - } - - public Collection classes() { - return m_forest.values(); - } - - public Collection getClasses(ClassIdentity identity) { - return m_forest.get(identity); - } - - public boolean containsIdentity(ClassIdentity identity) { - return m_forest.containsKey(identity); - } -} diff --git a/src/cuchaz/enigma/convert/ClassIdentifier.java b/src/cuchaz/enigma/convert/ClassIdentifier.java deleted file mode 100644 index ee5e9033..00000000 --- a/src/cuchaz/enigma/convert/ClassIdentifier.java +++ /dev/null @@ -1,54 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.convert; - -import java.util.Map; -import java.util.jar.JarFile; - -import com.google.common.collect.Maps; - -import javassist.CtClass; -import cuchaz.enigma.TranslatingTypeLoader; -import cuchaz.enigma.analysis.JarIndex; -import cuchaz.enigma.convert.ClassNamer.SidedClassNamer; -import cuchaz.enigma.mapping.ClassEntry; - - -public class ClassIdentifier { - - private JarIndex m_index; - private SidedClassNamer m_namer; - private boolean m_useReferences; - private TranslatingTypeLoader m_loader; - private Map m_cache; - - public ClassIdentifier(JarFile jar, JarIndex index, SidedClassNamer namer, boolean useReferences) { - m_index = index; - m_namer = namer; - m_useReferences = useReferences; - m_loader = new TranslatingTypeLoader(jar, index); - m_cache = Maps.newHashMap(); - } - - public ClassIdentity identify(ClassEntry classEntry) - throws ClassNotFoundException { - ClassIdentity identity = m_cache.get(classEntry); - if (identity == null) { - CtClass c = m_loader.loadClass(classEntry.getName()); - if (c == null) { - throw new ClassNotFoundException(classEntry.getName()); - } - identity = new ClassIdentity(c, m_namer, m_index, m_useReferences); - m_cache.put(classEntry, identity); - } - return identity; - } -} diff --git a/src/cuchaz/enigma/convert/ClassIdentity.java b/src/cuchaz/enigma/convert/ClassIdentity.java deleted file mode 100644 index d9ed08ea..00000000 --- a/src/cuchaz/enigma/convert/ClassIdentity.java +++ /dev/null @@ -1,473 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.convert; - -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Enumeration; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javassist.CannotCompileException; -import javassist.CtBehavior; -import javassist.CtClass; -import javassist.CtConstructor; -import javassist.CtField; -import javassist.CtMethod; -import javassist.bytecode.BadBytecode; -import javassist.bytecode.CodeIterator; -import javassist.bytecode.ConstPool; -import javassist.bytecode.Descriptor; -import javassist.bytecode.Opcode; -import javassist.expr.ConstructorCall; -import javassist.expr.ExprEditor; -import javassist.expr.FieldAccess; -import javassist.expr.MethodCall; -import javassist.expr.NewExpr; - -import com.google.common.collect.HashMultiset; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Multiset; -import com.google.common.collect.Sets; - -import cuchaz.enigma.Constants; -import cuchaz.enigma.Util; -import cuchaz.enigma.analysis.ClassImplementationsTreeNode; -import cuchaz.enigma.analysis.EntryReference; -import cuchaz.enigma.analysis.JarIndex; -import cuchaz.enigma.bytecode.ConstPoolEditor; -import cuchaz.enigma.bytecode.InfoType; -import cuchaz.enigma.bytecode.accessors.ConstInfoAccessor; -import cuchaz.enigma.convert.ClassNamer.SidedClassNamer; -import cuchaz.enigma.mapping.BehaviorEntry; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.ClassNameReplacer; -import cuchaz.enigma.mapping.Entry; -import cuchaz.enigma.mapping.EntryFactory; -import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.Signature; -import cuchaz.enigma.mapping.Type; - -public class ClassIdentity { - - private ClassEntry m_classEntry; - private SidedClassNamer m_namer; - private Multiset m_fields; - private Multiset m_methods; - private Multiset m_constructors; - private String m_staticInitializer; - private String m_extends; - private Multiset m_implements; - private Set m_stringLiterals; - private Multiset m_implementations; - private Multiset m_references; - private String m_outer; - - private final ClassNameReplacer m_classNameReplacer = new ClassNameReplacer() { - - private Map m_classNames = Maps.newHashMap(); - - @Override - public String replace(String className) { - - // classes not in the none package can be passed through - ClassEntry classEntry = new ClassEntry(className); - if (!classEntry.getPackageName().equals(Constants.NonePackage)) { - return className; - } - - // is this class ourself? - if (className.equals(m_classEntry.getName())) { - return "CSelf"; - } - - // try the namer - if (m_namer != null) { - String newName = m_namer.getName(className); - if (newName != null) { - return newName; - } - } - - // otherwise, use local naming - if (!m_classNames.containsKey(className)) { - m_classNames.put(className, getNewClassName()); - } - return m_classNames.get(className); - } - - private String getNewClassName() { - return String.format("C%03d", m_classNames.size()); - } - }; - - public ClassIdentity(CtClass c, SidedClassNamer namer, JarIndex index, boolean useReferences) { - m_namer = namer; - - // stuff from the bytecode - - m_classEntry = EntryFactory.getClassEntry(c); - m_fields = HashMultiset.create(); - for (CtField field : c.getDeclaredFields()) { - m_fields.add(scrubType(field.getSignature())); - } - m_methods = HashMultiset.create(); - for (CtMethod method : c.getDeclaredMethods()) { - m_methods.add(scrubSignature(method.getSignature()) + "0x" + getBehaviorSignature(method)); - } - m_constructors = HashMultiset.create(); - for (CtConstructor constructor : c.getDeclaredConstructors()) { - m_constructors.add(scrubSignature(constructor.getSignature()) + "0x" + getBehaviorSignature(constructor)); - } - m_staticInitializer = ""; - if (c.getClassInitializer() != null) { - m_staticInitializer = getBehaviorSignature(c.getClassInitializer()); - } - m_extends = ""; - if (c.getClassFile().getSuperclass() != null) { - m_extends = scrubClassName(Descriptor.toJvmName(c.getClassFile().getSuperclass())); - } - m_implements = HashMultiset.create(); - for (String interfaceName : c.getClassFile().getInterfaces()) { - m_implements.add(scrubClassName(Descriptor.toJvmName(interfaceName))); - } - - m_stringLiterals = Sets.newHashSet(); - ConstPool constants = c.getClassFile().getConstPool(); - for (int i=1; i implementations = implementationsNode.children(); - while (implementations.hasMoreElements()) { - ClassImplementationsTreeNode node = implementations.nextElement(); - m_implementations.add(scrubClassName(node.getClassEntry().getName())); - } - } - - m_references = HashMultiset.create(); - if (useReferences) { - for (CtField field : c.getDeclaredFields()) { - FieldEntry fieldEntry = EntryFactory.getFieldEntry(field); - for (EntryReference reference : index.getFieldReferences(fieldEntry)) { - addReference(reference); - } - } - for (CtBehavior behavior : c.getDeclaredBehaviors()) { - BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); - for (EntryReference reference : index.getBehaviorReferences(behaviorEntry)) { - addReference(reference); - } - } - } - - m_outer = null; - if (m_classEntry.isInnerClass()) { - m_outer = m_classEntry.getOuterClassName(); - } - } - - private void addReference(EntryReference reference) { - if (reference.context.getSignature() != null) { - m_references.add(String.format("%s_%s", - scrubClassName(reference.context.getClassName()), - scrubSignature(reference.context.getSignature()) - )); - } else { - m_references.add(String.format("%s_", - scrubClassName(reference.context.getClassName()) - )); - } - } - - public ClassEntry getClassEntry() { - return m_classEntry; - } - - @Override - public String toString() { - StringBuilder buf = new StringBuilder(); - buf.append("class: "); - buf.append(m_classEntry.getName()); - buf.append(" "); - buf.append(hashCode()); - buf.append("\n"); - for (String field : m_fields) { - buf.append("\tfield "); - buf.append(field); - buf.append("\n"); - } - for (String method : m_methods) { - buf.append("\tmethod "); - buf.append(method); - buf.append("\n"); - } - for (String constructor : m_constructors) { - buf.append("\tconstructor "); - buf.append(constructor); - buf.append("\n"); - } - if (m_staticInitializer.length() > 0) { - buf.append("\tinitializer "); - buf.append(m_staticInitializer); - buf.append("\n"); - } - if (m_extends.length() > 0) { - buf.append("\textends "); - buf.append(m_extends); - buf.append("\n"); - } - for (String interfaceName : m_implements) { - buf.append("\timplements "); - buf.append(interfaceName); - buf.append("\n"); - } - for (String implementation : m_implementations) { - buf.append("\timplemented by "); - buf.append(implementation); - buf.append("\n"); - } - for (String reference : m_references) { - buf.append("\treference "); - buf.append(reference); - buf.append("\n"); - } - buf.append("\touter "); - buf.append(m_outer); - buf.append("\n"); - return buf.toString(); - } - - private String scrubClassName(String className) { - return m_classNameReplacer.replace(className); - } - - private String scrubType(String typeName) { - return scrubType(new Type(typeName)).toString(); - } - - private Type scrubType(Type type) { - if (type.hasClass()) { - return new Type(type, m_classNameReplacer); - } else { - return type; - } - } - - private String scrubSignature(String signature) { - return scrubSignature(new Signature(signature)).toString(); - } - - private Signature scrubSignature(Signature signature) { - return new Signature(signature, m_classNameReplacer); - } - - private boolean isClassMatchedUniquely(String className) { - return m_namer != null && m_namer.getName(Descriptor.toJvmName(className)) != null; - } - - private String getBehaviorSignature(CtBehavior behavior) { - try { - // does this method have an implementation? - if (behavior.getMethodInfo().getCodeAttribute() == null) { - return "(none)"; - } - - // compute the hash from the opcodes - ConstPool constants = behavior.getMethodInfo().getConstPool(); - final MessageDigest digest = MessageDigest.getInstance("MD5"); - CodeIterator iter = behavior.getMethodInfo().getCodeAttribute().iterator(); - while (iter.hasNext()) { - int pos = iter.next(); - - // update the hash with the opcode - int opcode = iter.byteAt(pos); - digest.update((byte)opcode); - - switch (opcode) { - case Opcode.LDC: { - int constIndex = iter.byteAt(pos + 1); - updateHashWithConstant(digest, constants, constIndex); - } - break; - - case Opcode.LDC_W: - case Opcode.LDC2_W: { - int constIndex = (iter.byteAt(pos + 1) << 8) | iter.byteAt(pos + 2); - updateHashWithConstant(digest, constants, constIndex); - } - break; - } - } - - // update hash with method and field accesses - behavior.instrument(new ExprEditor() { - @Override - public void edit(MethodCall call) { - updateHashWithString(digest, scrubClassName(Descriptor.toJvmName(call.getClassName()))); - updateHashWithString(digest, scrubSignature(call.getSignature())); - if (isClassMatchedUniquely(call.getClassName())) { - updateHashWithString(digest, call.getMethodName()); - } - } - - @Override - public void edit(FieldAccess access) { - updateHashWithString(digest, scrubClassName(Descriptor.toJvmName(access.getClassName()))); - updateHashWithString(digest, scrubType(access.getSignature())); - if (isClassMatchedUniquely(access.getClassName())) { - updateHashWithString(digest, access.getFieldName()); - } - } - - @Override - public void edit(ConstructorCall call) { - updateHashWithString(digest, scrubClassName(Descriptor.toJvmName(call.getClassName()))); - updateHashWithString(digest, scrubSignature(call.getSignature())); - } - - @Override - public void edit(NewExpr expr) { - updateHashWithString(digest, scrubClassName(Descriptor.toJvmName(expr.getClassName()))); - } - }); - - // convert the hash to a hex string - return toHex(digest.digest()); - } catch (BadBytecode | NoSuchAlgorithmException | CannotCompileException ex) { - throw new Error(ex); - } - } - - private void updateHashWithConstant(MessageDigest digest, ConstPool constants, int index) { - ConstPoolEditor editor = new ConstPoolEditor(constants); - ConstInfoAccessor item = editor.getItem(index); - if (item.getType() == InfoType.StringInfo) { - updateHashWithString(digest, constants.getStringInfo(index)); - } - // TODO: other constants - } - - private void updateHashWithString(MessageDigest digest, String val) { - try { - digest.update(val.getBytes("UTF8")); - } catch (UnsupportedEncodingException ex) { - throw new Error(ex); - } - } - - private String toHex(byte[] bytes) { - // function taken from: - // http://stackoverflow.com/questions/9655181/convert-from-byte-array-to-hex-string-in-java - final char[] hexArray = "0123456789ABCDEF".toCharArray(); - char[] hexChars = new char[bytes.length * 2]; - for (int j = 0; j < bytes.length; j++) { - int v = bytes[j] & 0xFF; - hexChars[j * 2] = hexArray[v >>> 4]; - hexChars[j * 2 + 1] = hexArray[v & 0x0F]; - } - return new String(hexChars); - } - - @Override - public boolean equals(Object other) { - if (other instanceof ClassIdentity) { - return equals((ClassIdentity)other); - } - return false; - } - - public boolean equals(ClassIdentity other) { - return m_fields.equals(other.m_fields) - && m_methods.equals(other.m_methods) - && m_constructors.equals(other.m_constructors) - && m_staticInitializer.equals(other.m_staticInitializer) - && m_extends.equals(other.m_extends) - && m_implements.equals(other.m_implements) - && m_implementations.equals(other.m_implementations) - && m_references.equals(other.m_references); - } - - @Override - public int hashCode() { - List objs = Lists.newArrayList(); - objs.addAll(m_fields); - objs.addAll(m_methods); - objs.addAll(m_constructors); - objs.add(m_staticInitializer); - objs.add(m_extends); - objs.addAll(m_implements); - objs.addAll(m_implementations); - objs.addAll(m_references); - return Util.combineHashesOrdered(objs); - } - - public int getMatchScore(ClassIdentity other) { - return 2*getNumMatches(m_extends, other.m_extends) - + 2*getNumMatches(m_outer, other.m_outer) - + 2*getNumMatches(m_implements, other.m_implements) - + getNumMatches(m_stringLiterals, other.m_stringLiterals) - + getNumMatches(m_fields, other.m_fields) - + getNumMatches(m_methods, other.m_methods) - + getNumMatches(m_constructors, other.m_constructors); - } - - public int getMaxMatchScore() { - return 2 + 2 + 2*m_implements.size() + m_stringLiterals.size() + m_fields.size() + m_methods.size() + m_constructors.size(); - } - - public boolean matches(CtClass c) { - // just compare declaration counts - return m_fields.size() == c.getDeclaredFields().length - && m_methods.size() == c.getDeclaredMethods().length - && m_constructors.size() == c.getDeclaredConstructors().length; - } - - private int getNumMatches(Set a, Set b) { - int numMatches = 0; - for (String val : a) { - if (b.contains(val)) { - numMatches++; - } - } - return numMatches; - } - - private int getNumMatches(Multiset a, Multiset b) { - int numMatches = 0; - for (String val : a) { - if (b.contains(val)) { - numMatches++; - } - } - return numMatches; - } - - private int getNumMatches(String a, String b) { - if (a == null && b == null) { - return 1; - } else if (a != null && b != null && a.equals(b)) { - return 1; - } - return 0; - } -} diff --git a/src/cuchaz/enigma/convert/ClassMatch.java b/src/cuchaz/enigma/convert/ClassMatch.java deleted file mode 100644 index 8c50a624..00000000 --- a/src/cuchaz/enigma/convert/ClassMatch.java +++ /dev/null @@ -1,88 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.convert; - -import java.util.Collection; -import java.util.Set; - -import com.google.common.collect.Sets; - -import cuchaz.enigma.Util; -import cuchaz.enigma.mapping.ClassEntry; - - -public class ClassMatch { - - public Set sourceClasses; - public Set destClasses; - - public ClassMatch(Collection sourceClasses, Collection destClasses) { - this.sourceClasses = Sets.newHashSet(sourceClasses); - this.destClasses = Sets.newHashSet(destClasses); - } - - public ClassMatch(ClassEntry sourceClass, ClassEntry destClass) { - sourceClasses = Sets.newHashSet(); - if (sourceClass != null) { - sourceClasses.add(sourceClass); - } - destClasses = Sets.newHashSet(); - if (destClass != null) { - destClasses.add(destClass); - } - } - - public boolean isMatched() { - return sourceClasses.size() > 0 && destClasses.size() > 0; - } - - public boolean isAmbiguous() { - return sourceClasses.size() > 1 || destClasses.size() > 1; - } - - public ClassEntry getUniqueSource() { - if (sourceClasses.size() != 1) { - throw new IllegalStateException("Match has ambiguous source!"); - } - return sourceClasses.iterator().next(); - } - - public ClassEntry getUniqueDest() { - if (destClasses.size() != 1) { - throw new IllegalStateException("Match has ambiguous source!"); - } - return destClasses.iterator().next(); - } - - public Set intersectSourceClasses(Set classes) { - Set intersection = Sets.newHashSet(sourceClasses); - intersection.retainAll(classes); - return intersection; - } - - @Override - public int hashCode() { - return Util.combineHashesOrdered(sourceClasses, destClasses); - } - - @Override - public boolean equals(Object other) { - if (other instanceof ClassMatch) { - return equals((ClassMatch)other); - } - return false; - } - - public boolean equals(ClassMatch other) { - return this.sourceClasses.equals(other.sourceClasses) - && this.destClasses.equals(other.destClasses); - } -} diff --git a/src/cuchaz/enigma/convert/ClassMatches.java b/src/cuchaz/enigma/convert/ClassMatches.java deleted file mode 100644 index f70c1805..00000000 --- a/src/cuchaz/enigma/convert/ClassMatches.java +++ /dev/null @@ -1,163 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.convert; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; - -import cuchaz.enigma.mapping.ClassEntry; - - -public class ClassMatches implements Iterable { - - Collection m_matches; - Map m_matchesBySource; - Map m_matchesByDest; - BiMap m_uniqueMatches; - Map m_ambiguousMatchesBySource; - Map m_ambiguousMatchesByDest; - Set m_unmatchedSourceClasses; - Set m_unmatchedDestClasses; - - public ClassMatches() { - this(new ArrayList()); - } - - public ClassMatches(Collection matches) { - m_matches = matches; - m_matchesBySource = Maps.newHashMap(); - m_matchesByDest = Maps.newHashMap(); - m_uniqueMatches = HashBiMap.create(); - m_ambiguousMatchesBySource = Maps.newHashMap(); - m_ambiguousMatchesByDest = Maps.newHashMap(); - m_unmatchedSourceClasses = Sets.newHashSet(); - m_unmatchedDestClasses = Sets.newHashSet(); - - for (ClassMatch match : matches) { - indexMatch(match); - } - } - - public void add(ClassMatch match) { - m_matches.add(match); - indexMatch(match); - } - - public void remove(ClassMatch match) { - for (ClassEntry sourceClass : match.sourceClasses) { - m_matchesBySource.remove(sourceClass); - m_uniqueMatches.remove(sourceClass); - m_ambiguousMatchesBySource.remove(sourceClass); - m_unmatchedSourceClasses.remove(sourceClass); - } - for (ClassEntry destClass : match.destClasses) { - m_matchesByDest.remove(destClass); - m_uniqueMatches.inverse().remove(destClass); - m_ambiguousMatchesByDest.remove(destClass); - m_unmatchedDestClasses.remove(destClass); - } - m_matches.remove(match); - } - - public int size() { - return m_matches.size(); - } - - @Override - public Iterator iterator() { - return m_matches.iterator(); - } - - private void indexMatch(ClassMatch match) { - if (!match.isMatched()) { - // unmatched - m_unmatchedSourceClasses.addAll(match.sourceClasses); - m_unmatchedDestClasses.addAll(match.destClasses); - } else { - if (match.isAmbiguous()) { - // ambiguously matched - for (ClassEntry entry : match.sourceClasses) { - m_ambiguousMatchesBySource.put(entry, match); - } - for (ClassEntry entry : match.destClasses) { - m_ambiguousMatchesByDest.put(entry, match); - } - } else { - // uniquely matched - m_uniqueMatches.put(match.getUniqueSource(), match.getUniqueDest()); - } - } - for (ClassEntry entry : match.sourceClasses) { - m_matchesBySource.put(entry, match); - } - for (ClassEntry entry : match.destClasses) { - m_matchesByDest.put(entry, match); - } - } - - public BiMap getUniqueMatches() { - return m_uniqueMatches; - } - - public Set getUnmatchedSourceClasses() { - return m_unmatchedSourceClasses; - } - - public Set getUnmatchedDestClasses() { - return m_unmatchedDestClasses; - } - - public Set getAmbiguouslyMatchedSourceClasses() { - return m_ambiguousMatchesBySource.keySet(); - } - - public ClassMatch getAmbiguousMatchBySource(ClassEntry sourceClass) { - return m_ambiguousMatchesBySource.get(sourceClass); - } - - public ClassMatch getMatchBySource(ClassEntry sourceClass) { - return m_matchesBySource.get(sourceClass); - } - - public ClassMatch getMatchByDest(ClassEntry destClass) { - return m_matchesByDest.get(destClass); - } - - public void removeSource(ClassEntry sourceClass) { - ClassMatch match = m_matchesBySource.get(sourceClass); - if (match != null) { - remove(match); - match.sourceClasses.remove(sourceClass); - if (!match.sourceClasses.isEmpty() || !match.destClasses.isEmpty()) { - add(match); - } - } - } - - public void removeDest(ClassEntry destClass) { - ClassMatch match = m_matchesByDest.get(destClass); - if (match != null) { - remove(match); - match.destClasses.remove(destClass); - if (!match.sourceClasses.isEmpty() || !match.destClasses.isEmpty()) { - add(match); - } - } - } -} diff --git a/src/cuchaz/enigma/convert/ClassMatching.java b/src/cuchaz/enigma/convert/ClassMatching.java deleted file mode 100644 index 633d1ac7..00000000 --- a/src/cuchaz/enigma/convert/ClassMatching.java +++ /dev/null @@ -1,155 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.convert; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map.Entry; -import java.util.Set; - -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; - -import cuchaz.enigma.mapping.ClassEntry; - -public class ClassMatching { - - private ClassForest m_sourceClasses; - private ClassForest m_destClasses; - private BiMap m_knownMatches; - - public ClassMatching(ClassIdentifier sourceIdentifier, ClassIdentifier destIdentifier) { - m_sourceClasses = new ClassForest(sourceIdentifier); - m_destClasses = new ClassForest(destIdentifier); - m_knownMatches = HashBiMap.create(); - } - - public void addKnownMatches(BiMap knownMatches) { - m_knownMatches.putAll(knownMatches); - } - - public void match(Iterable sourceClasses, Iterable destClasses) { - for (ClassEntry sourceClass : sourceClasses) { - if (!m_knownMatches.containsKey(sourceClass)) { - m_sourceClasses.add(sourceClass); - } - } - for (ClassEntry destClass : destClasses) { - if (!m_knownMatches.containsValue(destClass)) { - m_destClasses.add(destClass); - } - } - } - - public Collection matches() { - List matches = Lists.newArrayList(); - for (Entry entry : m_knownMatches.entrySet()) { - matches.add(new ClassMatch( - entry.getKey(), - entry.getValue() - )); - } - for (ClassIdentity identity : m_sourceClasses.identities()) { - matches.add(new ClassMatch( - m_sourceClasses.getClasses(identity), - m_destClasses.getClasses(identity) - )); - } - for (ClassIdentity identity : m_destClasses.identities()) { - if (!m_sourceClasses.containsIdentity(identity)) { - matches.add(new ClassMatch( - new ArrayList(), - m_destClasses.getClasses(identity) - )); - } - } - return matches; - } - - public Collection sourceClasses() { - Set classes = Sets.newHashSet(); - for (ClassMatch match : matches()) { - classes.addAll(match.sourceClasses); - } - return classes; - } - - public Collection destClasses() { - Set classes = Sets.newHashSet(); - for (ClassMatch match : matches()) { - classes.addAll(match.destClasses); - } - return classes; - } - - public BiMap uniqueMatches() { - BiMap uniqueMatches = HashBiMap.create(); - for (ClassMatch match : matches()) { - if (match.isMatched() && !match.isAmbiguous()) { - uniqueMatches.put(match.getUniqueSource(), match.getUniqueDest()); - } - } - return uniqueMatches; - } - - public Collection ambiguousMatches() { - List ambiguousMatches = Lists.newArrayList(); - for (ClassMatch match : matches()) { - if (match.isMatched() && match.isAmbiguous()) { - ambiguousMatches.add(match); - } - } - return ambiguousMatches; - } - - public Collection unmatchedSourceClasses() { - List classes = Lists.newArrayList(); - for (ClassMatch match : matches()) { - if (!match.isMatched() && !match.sourceClasses.isEmpty()) { - classes.addAll(match.sourceClasses); - } - } - return classes; - } - - public Collection unmatchedDestClasses() { - List classes = Lists.newArrayList(); - for (ClassMatch match : matches()) { - if (!match.isMatched() && !match.destClasses.isEmpty()) { - classes.addAll(match.destClasses); - } - } - return classes; - } - - @Override - public String toString() { - - // count the ambiguous classes - int numAmbiguousSource = 0; - int numAmbiguousDest = 0; - for (ClassMatch match : ambiguousMatches()) { - numAmbiguousSource += match.sourceClasses.size(); - numAmbiguousDest += match.destClasses.size(); - } - - StringBuilder buf = new StringBuilder(); - buf.append(String.format("%20s%8s%8s\n", "", "Source", "Dest")); - buf.append(String.format("%20s%8d%8d\n", "Classes", sourceClasses().size(), destClasses().size())); - buf.append(String.format("%20s%8d%8d\n", "Uniquely matched", uniqueMatches().size(), uniqueMatches().size())); - buf.append(String.format("%20s%8d%8d\n", "Ambiguously matched", numAmbiguousSource, numAmbiguousDest)); - buf.append(String.format("%20s%8d%8d\n", "Unmatched", unmatchedSourceClasses().size(), unmatchedDestClasses().size())); - return buf.toString(); - } -} diff --git a/src/cuchaz/enigma/convert/ClassNamer.java b/src/cuchaz/enigma/convert/ClassNamer.java deleted file mode 100644 index e8fa7303..00000000 --- a/src/cuchaz/enigma/convert/ClassNamer.java +++ /dev/null @@ -1,66 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.convert; - -import java.util.Map; - -import com.google.common.collect.BiMap; -import com.google.common.collect.Maps; - -import cuchaz.enigma.mapping.ClassEntry; - -public class ClassNamer { - - public interface SidedClassNamer { - String getName(String name); - } - - private Map m_sourceNames; - private Map m_destNames; - - public ClassNamer(BiMap mappings) { - // convert the identity mappings to name maps - m_sourceNames = Maps.newHashMap(); - m_destNames = Maps.newHashMap(); - int i = 0; - for (Map.Entry entry : mappings.entrySet()) { - String name = String.format("M%04d", i++); - m_sourceNames.put(entry.getKey().getName(), name); - m_destNames.put(entry.getValue().getName(), name); - } - } - - public String getSourceName(String name) { - return m_sourceNames.get(name); - } - - public String getDestName(String name) { - return m_destNames.get(name); - } - - public SidedClassNamer getSourceNamer() { - return new SidedClassNamer() { - @Override - public String getName(String name) { - return getSourceName(name); - } - }; - } - - public SidedClassNamer getDestNamer() { - return new SidedClassNamer() { - @Override - public String getName(String name) { - return getDestName(name); - } - }; - } -} diff --git a/src/cuchaz/enigma/convert/FieldMatches.java b/src/cuchaz/enigma/convert/FieldMatches.java deleted file mode 100644 index 8439a84c..00000000 --- a/src/cuchaz/enigma/convert/FieldMatches.java +++ /dev/null @@ -1,155 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.convert; - -import java.util.Collection; -import java.util.Set; - -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; - -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.FieldEntry; - - -public class FieldMatches { - - private BiMap m_matches; - private Multimap m_matchedSourceFields; - private Multimap m_unmatchedSourceFields; - private Multimap m_unmatchedDestFields; - private Multimap m_unmatchableSourceFields; - - public FieldMatches() { - m_matches = HashBiMap.create(); - m_matchedSourceFields = HashMultimap.create(); - m_unmatchedSourceFields = HashMultimap.create(); - m_unmatchedDestFields = HashMultimap.create(); - m_unmatchableSourceFields = HashMultimap.create(); - } - - public void addMatch(FieldEntry srcField, FieldEntry destField) { - boolean wasAdded = m_matches.put(srcField, destField) == null; - assert (wasAdded); - wasAdded = m_matchedSourceFields.put(srcField.getClassEntry(), srcField); - assert (wasAdded); - } - - public void addUnmatchedSourceField(FieldEntry fieldEntry) { - boolean wasAdded = m_unmatchedSourceFields.put(fieldEntry.getClassEntry(), fieldEntry); - assert (wasAdded); - } - - public void addUnmatchedSourceFields(Iterable fieldEntries) { - for (FieldEntry fieldEntry : fieldEntries) { - addUnmatchedSourceField(fieldEntry); - } - } - - public void addUnmatchedDestField(FieldEntry fieldEntry) { - boolean wasAdded = m_unmatchedDestFields.put(fieldEntry.getClassEntry(), fieldEntry); - assert (wasAdded); - } - - public void addUnmatchedDestFields(Iterable fieldEntries) { - for (FieldEntry fieldEntry : fieldEntries) { - addUnmatchedDestField(fieldEntry); - } - } - - public void addUnmatchableSourceField(FieldEntry sourceField) { - boolean wasAdded = m_unmatchableSourceFields.put(sourceField.getClassEntry(), sourceField); - assert (wasAdded); - } - - public Set getSourceClassesWithUnmatchedFields() { - return m_unmatchedSourceFields.keySet(); - } - - public Collection getSourceClassesWithoutUnmatchedFields() { - Set out = Sets.newHashSet(); - out.addAll(m_matchedSourceFields.keySet()); - out.removeAll(m_unmatchedSourceFields.keySet()); - return out; - } - - public Collection getUnmatchedSourceFields() { - return m_unmatchedSourceFields.values(); - } - - public Collection getUnmatchedSourceFields(ClassEntry sourceClass) { - return m_unmatchedSourceFields.get(sourceClass); - } - - public Collection getUnmatchedDestFields() { - return m_unmatchedDestFields.values(); - } - - public Collection getUnmatchedDestFields(ClassEntry destClass) { - return m_unmatchedDestFields.get(destClass); - } - - public Collection getUnmatchableSourceFields() { - return m_unmatchableSourceFields.values(); - } - - public boolean hasSource(FieldEntry fieldEntry) { - return m_matches.containsKey(fieldEntry) || m_unmatchedSourceFields.containsValue(fieldEntry); - } - - public boolean hasDest(FieldEntry fieldEntry) { - return m_matches.containsValue(fieldEntry) || m_unmatchedDestFields.containsValue(fieldEntry); - } - - public BiMap matches() { - return m_matches; - } - - public boolean isMatchedSourceField(FieldEntry sourceField) { - return m_matches.containsKey(sourceField); - } - - public boolean isMatchedDestField(FieldEntry destField) { - return m_matches.containsValue(destField); - } - - public void makeMatch(FieldEntry sourceField, FieldEntry destField) { - boolean wasRemoved = m_unmatchedSourceFields.remove(sourceField.getClassEntry(), sourceField); - assert (wasRemoved); - wasRemoved = m_unmatchedDestFields.remove(destField.getClassEntry(), destField); - assert (wasRemoved); - addMatch(sourceField, destField); - } - - public boolean isMatched(FieldEntry sourceField, FieldEntry destField) { - FieldEntry match = m_matches.get(sourceField); - return match != null && match.equals(destField); - } - - public void unmakeMatch(FieldEntry sourceField, FieldEntry destField) { - boolean wasRemoved = m_matches.remove(sourceField) != null; - assert (wasRemoved); - wasRemoved = m_matchedSourceFields.remove(sourceField.getClassEntry(), sourceField); - assert (wasRemoved); - addUnmatchedSourceField(sourceField); - addUnmatchedDestField(destField); - } - - public void makeSourceUnmatchable(FieldEntry sourceField) { - assert(!isMatchedSourceField(sourceField)); - boolean wasRemoved = m_unmatchedSourceFields.remove(sourceField.getClassEntry(), sourceField); - assert (wasRemoved); - addUnmatchableSourceField(sourceField); - } -} diff --git a/src/cuchaz/enigma/convert/MappingsConverter.java b/src/cuchaz/enigma/convert/MappingsConverter.java deleted file mode 100644 index 958a17cf..00000000 --- a/src/cuchaz/enigma/convert/MappingsConverter.java +++ /dev/null @@ -1,602 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.convert; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.jar.JarFile; - -import com.google.common.collect.BiMap; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; - -import cuchaz.enigma.Constants; -import cuchaz.enigma.Deobfuscator; -import cuchaz.enigma.analysis.JarIndex; -import cuchaz.enigma.convert.ClassNamer.SidedClassNamer; -import cuchaz.enigma.mapping.BehaviorEntry; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.ClassMapping; -import cuchaz.enigma.mapping.ClassNameReplacer; -import cuchaz.enigma.mapping.ConstructorEntry; -import cuchaz.enigma.mapping.Entry; -import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.FieldMapping; -import cuchaz.enigma.mapping.Mappings; -import cuchaz.enigma.mapping.MappingsChecker; -import cuchaz.enigma.mapping.MemberMapping; -import cuchaz.enigma.mapping.MethodEntry; -import cuchaz.enigma.mapping.MethodMapping; -import cuchaz.enigma.mapping.Signature; -import cuchaz.enigma.mapping.Type; - -public class MappingsConverter { - - public static ClassMatches computeClassMatches(JarFile sourceJar, JarFile destJar, Mappings mappings) { - - // index jars - System.out.println("Indexing source jar..."); - JarIndex sourceIndex = new JarIndex(); - sourceIndex.indexJar(sourceJar, false); - System.out.println("Indexing dest jar..."); - JarIndex destIndex = new JarIndex(); - destIndex.indexJar(destJar, false); - - // compute the matching - ClassMatching matching = computeMatching(sourceJar, sourceIndex, destJar, destIndex, null); - return new ClassMatches(matching.matches()); - } - - public static ClassMatching computeMatching(JarFile sourceJar, JarIndex sourceIndex, JarFile destJar, JarIndex destIndex, BiMap knownMatches) { - - System.out.println("Iteratively matching classes"); - - ClassMatching lastMatching = null; - int round = 0; - SidedClassNamer sourceNamer = null; - SidedClassNamer destNamer = null; - for (boolean useReferences : Arrays.asList(false, true)) { - - int numUniqueMatchesLastTime = 0; - if (lastMatching != null) { - numUniqueMatchesLastTime = lastMatching.uniqueMatches().size(); - } - - while (true) { - - System.out.println("Round " + (++round) + "..."); - - // init the matching with identity settings - ClassMatching matching = new ClassMatching( - new ClassIdentifier(sourceJar, sourceIndex, sourceNamer, useReferences), - new ClassIdentifier(destJar, destIndex, destNamer, useReferences) - ); - - if (knownMatches != null) { - matching.addKnownMatches(knownMatches); - } - - if (lastMatching == null) { - // search all classes - matching.match(sourceIndex.getObfClassEntries(), destIndex.getObfClassEntries()); - } else { - // we already know about these matches from last time - matching.addKnownMatches(lastMatching.uniqueMatches()); - - // search unmatched and ambiguously-matched classes - matching.match(lastMatching.unmatchedSourceClasses(), lastMatching.unmatchedDestClasses()); - for (ClassMatch match : lastMatching.ambiguousMatches()) { - matching.match(match.sourceClasses, match.destClasses); - } - } - System.out.println(matching); - BiMap uniqueMatches = matching.uniqueMatches(); - - // did we match anything new this time? - if (uniqueMatches.size() > numUniqueMatchesLastTime) { - numUniqueMatchesLastTime = uniqueMatches.size(); - lastMatching = matching; - } else { - break; - } - - // update the namers - ClassNamer namer = new ClassNamer(uniqueMatches); - sourceNamer = namer.getSourceNamer(); - destNamer = namer.getDestNamer(); - } - } - - return lastMatching; - } - - public static Mappings newMappings(ClassMatches matches, Mappings oldMappings, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) { - - // sort the unique matches by size of inner class chain - Multimap> matchesByDestChainSize = HashMultimap.create(); - for (java.util.Map.Entry match : matches.getUniqueMatches().entrySet()) { - int chainSize = destDeobfuscator.getJarIndex().getObfClassChain(match.getValue()).size(); - matchesByDestChainSize.put(chainSize, match); - } - - // build the mappings (in order of small-to-large inner chains) - Mappings newMappings = new Mappings(); - List chainSizes = Lists.newArrayList(matchesByDestChainSize.keySet()); - Collections.sort(chainSizes); - for (int chainSize : chainSizes) { - for (java.util.Map.Entry match : matchesByDestChainSize.get(chainSize)) { - - // get class info - ClassEntry obfSourceClassEntry = match.getKey(); - ClassEntry obfDestClassEntry = match.getValue(); - List destClassChain = destDeobfuscator.getJarIndex().getObfClassChain(obfDestClassEntry); - - ClassMapping sourceMapping = sourceDeobfuscator.getMappings().getClassByObf(obfSourceClassEntry); - if (sourceMapping == null) { - // if this class was never deobfuscated, don't try to match it - continue; - } - - // find out where to make the dest class mapping - if (destClassChain.size() == 1) { - // not an inner class, add directly to mappings - newMappings.addClassMapping(migrateClassMapping(obfDestClassEntry, sourceMapping, matches, false)); - } else { - // inner class, find the outer class mapping - ClassMapping destMapping = null; - for (int i=0; i changes) { - - // sort the changes so classes are renamed in the correct order - // ie. if we have the mappings a->b, b->c, we have to apply b->c before a->b - LinkedHashMap sortedChanges = Maps.newLinkedHashMap(); - int numChangesLeft = changes.size(); - while (!changes.isEmpty()) { - Iterator> iter = changes.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry change = iter.next(); - if (changes.containsKey(change.getValue())) { - sortedChanges.put(change.getKey(), change.getValue()); - iter.remove(); - } - } - - // did we remove any changes? - if (numChangesLeft - changes.size() > 0) { - // keep going - numChangesLeft = changes.size(); - } else { - // can't sort anymore. There must be a loop - break; - } - } - if (!changes.isEmpty()) { - throw new Error("Unable to sort class changes! There must be a cycle."); - } - - // convert the mappings in the correct class order - for (Map.Entry entry : sortedChanges.entrySet()) { - mappings.renameObfClass(entry.getKey().getName(), entry.getValue().getName()); - } - } - - public static interface Doer { - Collection getDroppedEntries(MappingsChecker checker); - Collection getObfEntries(JarIndex jarIndex); - Collection> getMappings(ClassMapping destClassMapping); - Set filterEntries(Collection obfEntries, T obfSourceEntry, ClassMatches classMatches); - void setUpdateObfMember(ClassMapping classMapping, MemberMapping memberMapping, T newEntry); - boolean hasObfMember(ClassMapping classMapping, T obfEntry); - void removeMemberByObf(ClassMapping classMapping, T obfEntry); - } - - public static Doer getFieldDoer() { - return new Doer() { - - @Override - public Collection getDroppedEntries(MappingsChecker checker) { - return checker.getDroppedFieldMappings().keySet(); - } - - @Override - public Collection getObfEntries(JarIndex jarIndex) { - return jarIndex.getObfFieldEntries(); - } - - @Override - public Collection> getMappings(ClassMapping destClassMapping) { - return (Collection>)destClassMapping.fields(); - } - - @Override - public Set filterEntries(Collection obfDestFields, FieldEntry obfSourceField, ClassMatches classMatches) { - Set out = Sets.newHashSet(); - for (FieldEntry obfDestField : obfDestFields) { - Type translatedDestType = translate(obfDestField.getType(), classMatches.getUniqueMatches().inverse()); - if (translatedDestType.equals(obfSourceField.getType())) { - out.add(obfDestField); - } - } - return out; - } - - @Override - public void setUpdateObfMember(ClassMapping classMapping, MemberMapping memberMapping, FieldEntry newField) { - FieldMapping fieldMapping = (FieldMapping)memberMapping; - classMapping.setFieldObfNameAndType(fieldMapping.getObfName(), fieldMapping.getObfType(), newField.getName(), newField.getType()); - } - - @Override - public boolean hasObfMember(ClassMapping classMapping, FieldEntry obfField) { - return classMapping.getFieldByObf(obfField.getName(), obfField.getType()) != null; - } - - @Override - public void removeMemberByObf(ClassMapping classMapping, FieldEntry obfField) { - classMapping.removeFieldMapping(classMapping.getFieldByObf(obfField.getName(), obfField.getType())); - } - }; - } - - public static Doer getMethodDoer() { - return new Doer() { - - @Override - public Collection getDroppedEntries(MappingsChecker checker) { - return checker.getDroppedMethodMappings().keySet(); - } - - @Override - public Collection getObfEntries(JarIndex jarIndex) { - return jarIndex.getObfBehaviorEntries(); - } - - @Override - public Collection> getMappings(ClassMapping destClassMapping) { - return (Collection>)destClassMapping.methods(); - } - - @Override - public Set filterEntries(Collection obfDestFields, BehaviorEntry obfSourceField, ClassMatches classMatches) { - Set out = Sets.newHashSet(); - for (BehaviorEntry obfDestField : obfDestFields) { - Signature translatedDestSignature = translate(obfDestField.getSignature(), classMatches.getUniqueMatches().inverse()); - if (translatedDestSignature == null && obfSourceField.getSignature() == null) { - out.add(obfDestField); - } else if (translatedDestSignature == null || obfSourceField.getSignature() == null) { - // skip it - } else if (translatedDestSignature.equals(obfSourceField.getSignature())) { - out.add(obfDestField); - } - } - return out; - } - - @Override - public void setUpdateObfMember(ClassMapping classMapping, MemberMapping memberMapping, BehaviorEntry newBehavior) { - MethodMapping methodMapping = (MethodMapping)memberMapping; - classMapping.setMethodObfNameAndSignature(methodMapping.getObfName(), methodMapping.getObfSignature(), newBehavior.getName(), newBehavior.getSignature()); - } - - @Override - public boolean hasObfMember(ClassMapping classMapping, BehaviorEntry obfBehavior) { - return classMapping.getMethodByObf(obfBehavior.getName(), obfBehavior.getSignature()) != null; - } - - @Override - public void removeMemberByObf(ClassMapping classMapping, BehaviorEntry obfBehavior) { - classMapping.removeMethodMapping(classMapping.getMethodByObf(obfBehavior.getName(), obfBehavior.getSignature())); - } - }; - } - - public static MemberMatches computeMemberMatches(Deobfuscator destDeobfuscator, Mappings destMappings, ClassMatches classMatches, Doer doer) { - - MemberMatches memberMatches = new MemberMatches(); - - // unmatched source fields are easy - MappingsChecker checker = new MappingsChecker(destDeobfuscator.getJarIndex()); - checker.dropBrokenMappings(destMappings); - for (T destObfEntry : doer.getDroppedEntries(checker)) { - T srcObfEntry = translate(destObfEntry, classMatches.getUniqueMatches().inverse()); - memberMatches.addUnmatchedSourceEntry(srcObfEntry); - } - - // get matched fields (anything that's left after the checks/drops is matched( - for (ClassMapping classMapping : destMappings.classes()) { - collectMatchedFields(memberMatches, classMapping, classMatches, doer); - } - - // get unmatched dest fields - for (T destEntry : doer.getObfEntries(destDeobfuscator.getJarIndex())) { - if (!memberMatches.isMatchedDestEntry(destEntry)) { - memberMatches.addUnmatchedDestEntry(destEntry); - } - } - - System.out.println("Automatching " + memberMatches.getUnmatchedSourceEntries().size() + " unmatched source entries..."); - - // go through the unmatched source fields and try to pick out the easy matches - for (ClassEntry obfSourceClass : Lists.newArrayList(memberMatches.getSourceClassesWithUnmatchedEntries())) { - for (T obfSourceEntry : Lists.newArrayList(memberMatches.getUnmatchedSourceEntries(obfSourceClass))) { - - // get the possible dest matches - ClassEntry obfDestClass = classMatches.getUniqueMatches().get(obfSourceClass); - - // filter by type/signature - Set obfDestEntries = doer.filterEntries(memberMatches.getUnmatchedDestEntries(obfDestClass), obfSourceEntry, classMatches); - - if (obfDestEntries.size() == 1) { - // make the easy match - memberMatches.makeMatch(obfSourceEntry, obfDestEntries.iterator().next()); - } else if (obfDestEntries.isEmpty()) { - // no match is possible =( - memberMatches.makeSourceUnmatchable(obfSourceEntry); - } - } - } - - System.out.println(String.format("Ended up with %d ambiguous and %d unmatchable source entries", - memberMatches.getUnmatchedSourceEntries().size(), - memberMatches.getUnmatchableSourceEntries().size() - )); - - return memberMatches; - } - - private static void collectMatchedFields(MemberMatches memberMatches, ClassMapping destClassMapping, ClassMatches classMatches, Doer doer) { - - // get the fields for this class - for (MemberMapping destEntryMapping : doer.getMappings(destClassMapping)) { - T destObfField = destEntryMapping.getObfEntry(destClassMapping.getObfEntry()); - T srcObfField = translate(destObfField, classMatches.getUniqueMatches().inverse()); - memberMatches.addMatch(srcObfField, destObfField); - } - - // recurse - for (ClassMapping destInnerClassMapping : destClassMapping.innerClasses()) { - collectMatchedFields(memberMatches, destInnerClassMapping, classMatches, doer); - } - } - - @SuppressWarnings("unchecked") - private static T translate(T in, BiMap map) { - if (in instanceof FieldEntry) { - return (T)new FieldEntry( - map.get(in.getClassEntry()), - in.getName(), - translate(((FieldEntry)in).getType(), map) - ); - } else if (in instanceof MethodEntry) { - return (T)new MethodEntry( - map.get(in.getClassEntry()), - in.getName(), - translate(((MethodEntry)in).getSignature(), map) - ); - } else if (in instanceof ConstructorEntry) { - return (T)new ConstructorEntry( - map.get(in.getClassEntry()), - translate(((ConstructorEntry)in).getSignature(), map) - ); - } - throw new Error("Unhandled entry type: " + in.getClass()); - } - - private static Type translate(Type type, final BiMap map) { - return new Type(type, new ClassNameReplacer() { - @Override - public String replace(String inClassName) { - ClassEntry outClassEntry = map.get(new ClassEntry(inClassName)); - if (outClassEntry == null) { - return null; - } - return outClassEntry.getName(); - } - }); - } - - private static Signature translate(Signature signature, final BiMap map) { - if (signature == null) { - return null; - } - return new Signature(signature, new ClassNameReplacer() { - @Override - public String replace(String inClassName) { - ClassEntry outClassEntry = map.get(new ClassEntry(inClassName)); - if (outClassEntry == null) { - return null; - } - return outClassEntry.getName(); - } - }); - } - - public static void applyMemberMatches(Mappings mappings, ClassMatches classMatches, MemberMatches memberMatches, Doer doer) { - for (ClassMapping classMapping : mappings.classes()) { - applyMemberMatches(classMapping, classMatches, memberMatches, doer); - } - } - - private static void applyMemberMatches(ClassMapping classMapping, ClassMatches classMatches, MemberMatches memberMatches, Doer doer) { - - // get the classes - ClassEntry obfDestClass = classMapping.getObfEntry(); - - // make a map of all the renames we need to make - Map renames = Maps.newHashMap(); - for (MemberMapping memberMapping : Lists.newArrayList(doer.getMappings(classMapping))) { - T obfOldDestEntry = memberMapping.getObfEntry(obfDestClass); - T obfSourceEntry = getSourceEntryFromDestMapping(memberMapping, obfDestClass, classMatches); - - // but drop the unmatchable things - if (memberMatches.isUnmatchableSourceEntry(obfSourceEntry)) { - doer.removeMemberByObf(classMapping, obfOldDestEntry); - continue; - } - - T obfNewDestEntry = memberMatches.matches().get(obfSourceEntry); - if (obfNewDestEntry != null && !obfOldDestEntry.getName().equals(obfNewDestEntry.getName())) { - renames.put(obfOldDestEntry, obfNewDestEntry); - } - } - - if (!renames.isEmpty()) { - - // apply to this class (should never need more than n passes) - int numRenamesAppliedThisRound; - do { - numRenamesAppliedThisRound = 0; - - for (MemberMapping memberMapping : Lists.newArrayList(doer.getMappings(classMapping))) { - T obfOldDestEntry = memberMapping.getObfEntry(obfDestClass); - T obfNewDestEntry = renames.get(obfOldDestEntry); - if (obfNewDestEntry != null) { - // make sure this rename won't cause a collision - // otherwise, save it for the next round and try again next time - if (!doer.hasObfMember(classMapping, obfNewDestEntry)) { - doer.setUpdateObfMember(classMapping, memberMapping, obfNewDestEntry); - renames.remove(obfOldDestEntry); - numRenamesAppliedThisRound++; - } - } - } - } while(numRenamesAppliedThisRound > 0); - - if (!renames.isEmpty()) { - System.err.println(String.format("WARNING: Couldn't apply all the renames for class %s. %d renames left.", - classMapping.getObfFullName(), renames.size() - )); - for (Map.Entry entry : renames.entrySet()) { - System.err.println(String.format("\t%s -> %s", entry.getKey().getName(), entry.getValue().getName())); - } - } - } - - // recurse - for (ClassMapping innerClassMapping : classMapping.innerClasses()) { - applyMemberMatches(innerClassMapping, classMatches, memberMatches, doer); - } - } - - private static T getSourceEntryFromDestMapping(MemberMapping destMemberMapping, ClassEntry obfDestClass, ClassMatches classMatches) { - return translate(destMemberMapping.getObfEntry(obfDestClass), classMatches.getUniqueMatches().inverse()); - } -} diff --git a/src/cuchaz/enigma/convert/MatchesReader.java b/src/cuchaz/enigma/convert/MatchesReader.java deleted file mode 100644 index 7514e2a9..00000000 --- a/src/cuchaz/enigma/convert/MatchesReader.java +++ /dev/null @@ -1,113 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.convert; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.util.Collection; -import java.util.List; - -import com.google.common.collect.Lists; - -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.Entry; -import cuchaz.enigma.mapping.EntryFactory; -import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.Type; - - -public class MatchesReader { - - public static ClassMatches readClasses(File file) - throws IOException { - try (BufferedReader in = new BufferedReader(new FileReader(file))) { - ClassMatches matches = new ClassMatches(); - String line = null; - while ((line = in.readLine()) != null) { - matches.add(readClassMatch(line)); - } - return matches; - } - } - - private static ClassMatch readClassMatch(String line) - throws IOException { - String[] sides = line.split(":", 2); - return new ClassMatch(readClasses(sides[0]), readClasses(sides[1])); - } - - private static Collection readClasses(String in) { - List entries = Lists.newArrayList(); - for (String className : in.split(",")) { - className = className.trim(); - if (className.length() > 0) { - entries.add(new ClassEntry(className)); - } - } - return entries; - } - - public static MemberMatches readMembers(File file) - throws IOException { - try (BufferedReader in = new BufferedReader(new FileReader(file))) { - MemberMatches matches = new MemberMatches(); - String line = null; - while ((line = in.readLine()) != null) { - readMemberMatch(matches, line); - } - return matches; - } - } - - private static void readMemberMatch(MemberMatches matches, String line) { - if (line.startsWith("!")) { - T source = readEntry(line.substring(1)); - matches.addUnmatchableSourceEntry(source); - } else { - String[] parts = line.split(":", 2); - T source = readEntry(parts[0]); - T dest = readEntry(parts[1]); - if (source != null && dest != null) { - matches.addMatch(source, dest); - } else if (source != null) { - matches.addUnmatchedSourceEntry(source); - } else if (dest != null) { - matches.addUnmatchedDestEntry(dest); - } - } - } - - @SuppressWarnings("unchecked") - private static T readEntry(String in) { - if (in.length() <= 0) { - return null; - } - String[] parts = in.split(" "); - if (parts.length == 3 && parts[2].indexOf('(') < 0) { - return (T)new FieldEntry( - new ClassEntry(parts[0]), - parts[1], - new Type(parts[2]) - ); - } else { - assert(parts.length == 2 || parts.length == 3); - if (parts.length == 2) { - return (T)EntryFactory.getBehaviorEntry(parts[0], parts[1]); - } else if (parts.length == 3) { - return (T)EntryFactory.getBehaviorEntry(parts[0], parts[1], parts[2]); - } else { - throw new Error("Malformed behavior entry: " + in); - } - } - } -} diff --git a/src/cuchaz/enigma/convert/MatchesWriter.java b/src/cuchaz/enigma/convert/MatchesWriter.java deleted file mode 100644 index 42c6b61b..00000000 --- a/src/cuchaz/enigma/convert/MatchesWriter.java +++ /dev/null @@ -1,121 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.convert; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.Map; - -import cuchaz.enigma.mapping.BehaviorEntry; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.Entry; -import cuchaz.enigma.mapping.FieldEntry; - - -public class MatchesWriter { - - public static void writeClasses(ClassMatches matches, File file) - throws IOException { - try (FileWriter out = new FileWriter(file)) { - for (ClassMatch match : matches) { - writeClassMatch(out, match); - } - } - } - - private static void writeClassMatch(FileWriter out, ClassMatch match) - throws IOException { - writeClasses(out, match.sourceClasses); - out.write(":"); - writeClasses(out, match.destClasses); - out.write("\n"); - } - - private static void writeClasses(FileWriter out, Iterable classes) - throws IOException { - boolean isFirst = true; - for (ClassEntry entry : classes) { - if (isFirst) { - isFirst = false; - } else { - out.write(","); - } - out.write(entry.toString()); - } - } - - public static void writeMembers(MemberMatches matches, File file) - throws IOException { - try (FileWriter out = new FileWriter(file)) { - for (Map.Entry match : matches.matches().entrySet()) { - writeMemberMatch(out, match.getKey(), match.getValue()); - } - for (T entry : matches.getUnmatchedSourceEntries()) { - writeMemberMatch(out, entry, null); - } - for (T entry : matches.getUnmatchedDestEntries()) { - writeMemberMatch(out, null, entry); - } - for (T entry : matches.getUnmatchableSourceEntries()) { - writeUnmatchableEntry(out, entry); - } - } - } - - private static void writeMemberMatch(FileWriter out, T source, T dest) - throws IOException { - if (source != null) { - writeEntry(out, source); - } - out.write(":"); - if (dest != null) { - writeEntry(out, dest); - } - out.write("\n"); - } - - private static void writeUnmatchableEntry(FileWriter out, T entry) - throws IOException { - out.write("!"); - writeEntry(out, entry); - out.write("\n"); - } - - private static void writeEntry(FileWriter out, T entry) - throws IOException { - if (entry instanceof FieldEntry) { - writeField(out, (FieldEntry)entry); - } else if (entry instanceof BehaviorEntry) { - writeBehavior(out, (BehaviorEntry)entry); - } - } - - private static void writeField(FileWriter out, FieldEntry fieldEntry) - throws IOException { - out.write(fieldEntry.getClassName()); - out.write(" "); - out.write(fieldEntry.getName()); - out.write(" "); - out.write(fieldEntry.getType().toString()); - } - - private static void writeBehavior(FileWriter out, BehaviorEntry behaviorEntry) - throws IOException { - out.write(behaviorEntry.getClassName()); - out.write(" "); - out.write(behaviorEntry.getName()); - out.write(" "); - if (behaviorEntry.getSignature() != null) { - out.write(behaviorEntry.getSignature().toString()); - } - } -} diff --git a/src/cuchaz/enigma/convert/MemberMatches.java b/src/cuchaz/enigma/convert/MemberMatches.java deleted file mode 100644 index 29def159..00000000 --- a/src/cuchaz/enigma/convert/MemberMatches.java +++ /dev/null @@ -1,159 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.convert; - -import java.util.Collection; -import java.util.Set; - -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; - -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.Entry; - - -public class MemberMatches { - - private BiMap m_matches; - private Multimap m_matchedSourceEntries; - private Multimap m_unmatchedSourceEntries; - private Multimap m_unmatchedDestEntries; - private Multimap m_unmatchableSourceEntries; - - public MemberMatches() { - m_matches = HashBiMap.create(); - m_matchedSourceEntries = HashMultimap.create(); - m_unmatchedSourceEntries = HashMultimap.create(); - m_unmatchedDestEntries = HashMultimap.create(); - m_unmatchableSourceEntries = HashMultimap.create(); - } - - public void addMatch(T srcEntry, T destEntry) { - boolean wasAdded = m_matches.put(srcEntry, destEntry) == null; - assert (wasAdded); - wasAdded = m_matchedSourceEntries.put(srcEntry.getClassEntry(), srcEntry); - assert (wasAdded); - } - - public void addUnmatchedSourceEntry(T sourceEntry) { - boolean wasAdded = m_unmatchedSourceEntries.put(sourceEntry.getClassEntry(), sourceEntry); - assert (wasAdded); - } - - public void addUnmatchedSourceEntries(Iterable sourceEntries) { - for (T sourceEntry : sourceEntries) { - addUnmatchedSourceEntry(sourceEntry); - } - } - - public void addUnmatchedDestEntry(T destEntry) { - boolean wasAdded = m_unmatchedDestEntries.put(destEntry.getClassEntry(), destEntry); - assert (wasAdded); - } - - public void addUnmatchedDestEntries(Iterable destEntriesntries) { - for (T entry : destEntriesntries) { - addUnmatchedDestEntry(entry); - } - } - - public void addUnmatchableSourceEntry(T sourceEntry) { - boolean wasAdded = m_unmatchableSourceEntries.put(sourceEntry.getClassEntry(), sourceEntry); - assert (wasAdded); - } - - public Set getSourceClassesWithUnmatchedEntries() { - return m_unmatchedSourceEntries.keySet(); - } - - public Collection getSourceClassesWithoutUnmatchedEntries() { - Set out = Sets.newHashSet(); - out.addAll(m_matchedSourceEntries.keySet()); - out.removeAll(m_unmatchedSourceEntries.keySet()); - return out; - } - - public Collection getUnmatchedSourceEntries() { - return m_unmatchedSourceEntries.values(); - } - - public Collection getUnmatchedSourceEntries(ClassEntry sourceClass) { - return m_unmatchedSourceEntries.get(sourceClass); - } - - public Collection getUnmatchedDestEntries() { - return m_unmatchedDestEntries.values(); - } - - public Collection getUnmatchedDestEntries(ClassEntry destClass) { - return m_unmatchedDestEntries.get(destClass); - } - - public Collection getUnmatchableSourceEntries() { - return m_unmatchableSourceEntries.values(); - } - - public boolean hasSource(T sourceEntry) { - return m_matches.containsKey(sourceEntry) || m_unmatchedSourceEntries.containsValue(sourceEntry); - } - - public boolean hasDest(T destEntry) { - return m_matches.containsValue(destEntry) || m_unmatchedDestEntries.containsValue(destEntry); - } - - public BiMap matches() { - return m_matches; - } - - public boolean isMatchedSourceEntry(T sourceEntry) { - return m_matches.containsKey(sourceEntry); - } - - public boolean isMatchedDestEntry(T destEntry) { - return m_matches.containsValue(destEntry); - } - - public boolean isUnmatchableSourceEntry(T sourceEntry) { - return m_unmatchableSourceEntries.containsEntry(sourceEntry.getClassEntry(), sourceEntry); - } - - public void makeMatch(T sourceEntry, T destEntry) { - boolean wasRemoved = m_unmatchedSourceEntries.remove(sourceEntry.getClassEntry(), sourceEntry); - assert (wasRemoved); - wasRemoved = m_unmatchedDestEntries.remove(destEntry.getClassEntry(), destEntry); - assert (wasRemoved); - addMatch(sourceEntry, destEntry); - } - - public boolean isMatched(T sourceEntry, T destEntry) { - T match = m_matches.get(sourceEntry); - return match != null && match.equals(destEntry); - } - - public void unmakeMatch(T sourceEntry, T destEntry) { - boolean wasRemoved = m_matches.remove(sourceEntry) != null; - assert (wasRemoved); - wasRemoved = m_matchedSourceEntries.remove(sourceEntry.getClassEntry(), sourceEntry); - assert (wasRemoved); - addUnmatchedSourceEntry(sourceEntry); - addUnmatchedDestEntry(destEntry); - } - - public void makeSourceUnmatchable(T sourceEntry) { - assert(!isMatchedSourceEntry(sourceEntry)); - boolean wasRemoved = m_unmatchedSourceEntries.remove(sourceEntry.getClassEntry(), sourceEntry); - assert (wasRemoved); - addUnmatchableSourceEntry(sourceEntry); - } -} diff --git a/src/cuchaz/enigma/gui/AboutDialog.java b/src/cuchaz/enigma/gui/AboutDialog.java deleted file mode 100644 index 3eba1e50..00000000 --- a/src/cuchaz/enigma/gui/AboutDialog.java +++ /dev/null @@ -1,86 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import java.awt.Color; -import java.awt.Container; -import java.awt.Cursor; -import java.awt.FlowLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.IOException; - -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.WindowConstants; - -import cuchaz.enigma.Constants; -import cuchaz.enigma.Util; - -public class AboutDialog { - - public static void show(JFrame parent) { - // init frame - final JFrame frame = new JFrame(Constants.Name + " - About"); - final Container pane = frame.getContentPane(); - pane.setLayout(new FlowLayout()); - - // load the content - try { - String html = Util.readResourceToString("/about.html"); - html = String.format(html, Constants.Name, Constants.Version); - JLabel label = new JLabel(html); - label.setHorizontalAlignment(JLabel.CENTER); - pane.add(label); - } catch (IOException ex) { - throw new Error(ex); - } - - // show the link - String html = "%s"; - html = String.format(html, Constants.Url, Constants.Url); - JButton link = new JButton(html); - link.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - Util.openUrl(Constants.Url); - } - }); - link.setBorderPainted(false); - link.setOpaque(false); - link.setBackground(Color.WHITE); - link.setCursor(new Cursor(Cursor.HAND_CURSOR)); - link.setFocusable(false); - JPanel linkPanel = new JPanel(); - linkPanel.add(link); - pane.add(linkPanel); - - // show ok button - JButton okButton = new JButton("Ok"); - pane.add(okButton); - okButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent arg0) { - frame.dispose(); - } - }); - - // show the frame - pane.doLayout(); - frame.setSize(400, 220); - frame.setResizable(false); - frame.setLocationRelativeTo(parent); - frame.setVisible(true); - frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - } -} diff --git a/src/cuchaz/enigma/gui/BoxHighlightPainter.java b/src/cuchaz/enigma/gui/BoxHighlightPainter.java deleted file mode 100644 index e5e05571..00000000 --- a/src/cuchaz/enigma/gui/BoxHighlightPainter.java +++ /dev/null @@ -1,64 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import java.awt.Color; -import java.awt.Graphics; -import java.awt.Rectangle; -import java.awt.Shape; - -import javax.swing.text.BadLocationException; -import javax.swing.text.Highlighter; -import javax.swing.text.JTextComponent; - -public abstract class BoxHighlightPainter implements Highlighter.HighlightPainter { - - private Color m_fillColor; - private Color m_borderColor; - - protected BoxHighlightPainter(Color fillColor, Color borderColor) { - m_fillColor = fillColor; - m_borderColor = borderColor; - } - - @Override - public void paint(Graphics g, int start, int end, Shape shape, JTextComponent text) { - Rectangle bounds = getBounds(text, start, end); - - // fill the area - if (m_fillColor != null) { - g.setColor(m_fillColor); - g.fillRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4); - } - - // draw a box around the area - g.setColor(m_borderColor); - g.drawRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4); - } - - protected static Rectangle getBounds(JTextComponent text, int start, int end) { - try { - // determine the bounds of the text - Rectangle bounds = text.modelToView(start).union(text.modelToView(end)); - - // adjust the box so it looks nice - bounds.x -= 2; - bounds.width += 2; - bounds.y += 1; - bounds.height -= 2; - - return bounds; - } catch (BadLocationException ex) { - // don't care... just return something - return new Rectangle(0, 0, 0, 0); - } - } -} diff --git a/src/cuchaz/enigma/gui/BrowserCaret.java b/src/cuchaz/enigma/gui/BrowserCaret.java deleted file mode 100644 index 6af4d248..00000000 --- a/src/cuchaz/enigma/gui/BrowserCaret.java +++ /dev/null @@ -1,45 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import java.awt.Graphics; -import java.awt.Shape; - -import javax.swing.text.DefaultCaret; -import javax.swing.text.Highlighter; -import javax.swing.text.JTextComponent; - -public class BrowserCaret extends DefaultCaret { - - private static final long serialVersionUID = 1158977422507969940L; - - private static final Highlighter.HighlightPainter m_selectionPainter = new Highlighter.HighlightPainter() { - @Override - public void paint(Graphics g, int p0, int p1, Shape bounds, JTextComponent c) { - // don't paint anything - } - }; - - @Override - public boolean isSelectionVisible() { - return false; - } - - @Override - public boolean isVisible() { - return true; - } - - @Override - public Highlighter.HighlightPainter getSelectionPainter() { - return m_selectionPainter; - } -} diff --git a/src/cuchaz/enigma/gui/ClassListCellRenderer.java b/src/cuchaz/enigma/gui/ClassListCellRenderer.java deleted file mode 100644 index cde3e4ca..00000000 --- a/src/cuchaz/enigma/gui/ClassListCellRenderer.java +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import java.awt.Component; - -import javassist.bytecode.Descriptor; - -import javax.swing.DefaultListCellRenderer; -import javax.swing.JLabel; -import javax.swing.JList; -import javax.swing.ListCellRenderer; - -public class ClassListCellRenderer implements ListCellRenderer { - - private DefaultListCellRenderer m_defaultRenderer; - - public ClassListCellRenderer() { - m_defaultRenderer = new DefaultListCellRenderer(); - } - - @Override - public Component getListCellRendererComponent(JList list, String className, int index, boolean isSelected, boolean hasFocus) { - JLabel label = (JLabel)m_defaultRenderer.getListCellRendererComponent(list, className, index, isSelected, hasFocus); - label.setText(Descriptor.toJavaName(className)); - return label; - } -} diff --git a/src/cuchaz/enigma/gui/ClassMatchingGui.java b/src/cuchaz/enigma/gui/ClassMatchingGui.java deleted file mode 100644 index 416b01f4..00000000 --- a/src/cuchaz/enigma/gui/ClassMatchingGui.java +++ /dev/null @@ -1,622 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import java.awt.BorderLayout; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Map; - -import javax.swing.BoxLayout; -import javax.swing.ButtonGroup; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JRadioButton; -import javax.swing.JScrollPane; -import javax.swing.JSplitPane; -import javax.swing.SwingConstants; -import javax.swing.WindowConstants; - -import com.google.common.collect.BiMap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - -import cuchaz.enigma.Constants; -import cuchaz.enigma.Deobfuscator; -import cuchaz.enigma.convert.ClassIdentifier; -import cuchaz.enigma.convert.ClassIdentity; -import cuchaz.enigma.convert.ClassMatch; -import cuchaz.enigma.convert.ClassMatches; -import cuchaz.enigma.convert.ClassMatching; -import cuchaz.enigma.convert.ClassNamer; -import cuchaz.enigma.convert.MappingsConverter; -import cuchaz.enigma.gui.ClassSelector.ClassSelectionListener; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.Mappings; -import cuchaz.enigma.mapping.MappingsChecker; -import de.sciss.syntaxpane.DefaultSyntaxKit; - - -public class ClassMatchingGui { - - private static enum SourceType { - Matched { - - @Override - public Collection getSourceClasses(ClassMatches matches) { - return matches.getUniqueMatches().keySet(); - } - }, - Unmatched { - - @Override - public Collection getSourceClasses(ClassMatches matches) { - return matches.getUnmatchedSourceClasses(); - } - }, - Ambiguous { - - @Override - public Collection getSourceClasses(ClassMatches matches) { - return matches.getAmbiguouslyMatchedSourceClasses(); - } - }; - - public JRadioButton newRadio(ActionListener listener, ButtonGroup group) { - JRadioButton button = new JRadioButton(name(), this == getDefault()); - button.setActionCommand(name()); - button.addActionListener(listener); - group.add(button); - return button; - } - - public abstract Collection getSourceClasses(ClassMatches matches); - - public static SourceType getDefault() { - return values()[0]; - } - } - - public static interface SaveListener { - public void save(ClassMatches matches); - } - - // controls - private JFrame m_frame; - private ClassSelector m_sourceClasses; - private ClassSelector m_destClasses; - private CodeReader m_sourceReader; - private CodeReader m_destReader; - private JLabel m_sourceClassLabel; - private JLabel m_destClassLabel; - private JButton m_matchButton; - private Map m_sourceTypeButtons; - private JCheckBox m_advanceCheck; - private JCheckBox m_top10Matches; - - private ClassMatches m_classMatches; - private Deobfuscator m_sourceDeobfuscator; - private Deobfuscator m_destDeobfuscator; - private ClassEntry m_sourceClass; - private ClassEntry m_destClass; - private SourceType m_sourceType; - private SaveListener m_saveListener; - - public ClassMatchingGui(ClassMatches matches, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) { - - m_classMatches = matches; - m_sourceDeobfuscator = sourceDeobfuscator; - m_destDeobfuscator = destDeobfuscator; - - // init frame - m_frame = new JFrame(Constants.Name + " - Class Matcher"); - final Container pane = m_frame.getContentPane(); - pane.setLayout(new BorderLayout()); - - // init source side - JPanel sourcePanel = new JPanel(); - sourcePanel.setLayout(new BoxLayout(sourcePanel, BoxLayout.PAGE_AXIS)); - sourcePanel.setPreferredSize(new Dimension(200, 0)); - pane.add(sourcePanel, BorderLayout.WEST); - sourcePanel.add(new JLabel("Source Classes")); - - // init source type radios - JPanel sourceTypePanel = new JPanel(); - sourcePanel.add(sourceTypePanel); - sourceTypePanel.setLayout(new BoxLayout(sourceTypePanel, BoxLayout.PAGE_AXIS)); - ActionListener sourceTypeListener = new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - setSourceType(SourceType.valueOf(event.getActionCommand())); - } - }; - ButtonGroup sourceTypeButtons = new ButtonGroup(); - m_sourceTypeButtons = Maps.newHashMap(); - for (SourceType sourceType : SourceType.values()) { - JRadioButton button = sourceType.newRadio(sourceTypeListener, sourceTypeButtons); - m_sourceTypeButtons.put(sourceType, button); - sourceTypePanel.add(button); - } - - m_sourceClasses = new ClassSelector(ClassSelector.DeobfuscatedClassEntryComparator); - m_sourceClasses.setListener(new ClassSelectionListener() { - @Override - public void onSelectClass(ClassEntry classEntry) { - setSourceClass(classEntry); - } - }); - JScrollPane sourceScroller = new JScrollPane(m_sourceClasses); - sourcePanel.add(sourceScroller); - - // init dest side - JPanel destPanel = new JPanel(); - destPanel.setLayout(new BoxLayout(destPanel, BoxLayout.PAGE_AXIS)); - destPanel.setPreferredSize(new Dimension(200, 0)); - pane.add(destPanel, BorderLayout.WEST); - destPanel.add(new JLabel("Destination Classes")); - - m_top10Matches = new JCheckBox("Show only top 10 matches"); - destPanel.add(m_top10Matches); - m_top10Matches.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - toggleTop10Matches(); - } - }); - - m_destClasses = new ClassSelector(ClassSelector.DeobfuscatedClassEntryComparator); - m_destClasses.setListener(new ClassSelectionListener() { - @Override - public void onSelectClass(ClassEntry classEntry) { - setDestClass(classEntry); - } - }); - JScrollPane destScroller = new JScrollPane(m_destClasses); - destPanel.add(destScroller); - - JButton autoMatchButton = new JButton("AutoMatch"); - autoMatchButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - autoMatch(); - } - }); - destPanel.add(autoMatchButton); - - // init source panels - DefaultSyntaxKit.initKit(); - m_sourceReader = new CodeReader(); - m_destReader = new CodeReader(); - - // init all the splits - JSplitPane splitLeft = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, sourcePanel, new JScrollPane(m_sourceReader)); - splitLeft.setResizeWeight(0); // let the right side take all the slack - JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, new JScrollPane(m_destReader), destPanel); - splitRight.setResizeWeight(1); // let the left side take all the slack - JSplitPane splitCenter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, splitLeft, splitRight); - splitCenter.setResizeWeight(0.5); // resize 50:50 - pane.add(splitCenter, BorderLayout.CENTER); - splitCenter.resetToPreferredSizes(); - - // init bottom panel - JPanel bottomPanel = new JPanel(); - bottomPanel.setLayout(new FlowLayout()); - - m_sourceClassLabel = new JLabel(); - m_sourceClassLabel.setHorizontalAlignment(SwingConstants.RIGHT); - m_destClassLabel = new JLabel(); - m_destClassLabel.setHorizontalAlignment(SwingConstants.LEFT); - - m_matchButton = new JButton(); - - m_advanceCheck = new JCheckBox("Advance to next likely match"); - m_advanceCheck.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - if (m_advanceCheck.isSelected()) { - advance(); - } - } - }); - - bottomPanel.add(m_sourceClassLabel); - bottomPanel.add(m_matchButton); - bottomPanel.add(m_destClassLabel); - bottomPanel.add(m_advanceCheck); - pane.add(bottomPanel, BorderLayout.SOUTH); - - // show the frame - pane.doLayout(); - m_frame.setSize(1024, 576); - m_frame.setMinimumSize(new Dimension(640, 480)); - m_frame.setVisible(true); - m_frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - - // init state - updateDestMappings(); - setSourceType(SourceType.getDefault()); - updateMatchButton(); - m_saveListener = null; - } - - public void setSaveListener(SaveListener val) { - m_saveListener = val; - } - - private void updateDestMappings() { - - Mappings newMappings = MappingsConverter.newMappings( - m_classMatches, - m_sourceDeobfuscator.getMappings(), - m_sourceDeobfuscator, - m_destDeobfuscator - ); - - // look for dropped mappings - MappingsChecker checker = new MappingsChecker(m_destDeobfuscator.getJarIndex()); - checker.dropBrokenMappings(newMappings); - - // count them - int numDroppedFields = checker.getDroppedFieldMappings().size(); - int numDroppedMethods = checker.getDroppedMethodMappings().size(); - System.out.println(String.format( - "%d mappings from matched classes don't match the dest jar:\n\t%5d fields\n\t%5d methods", - numDroppedFields + numDroppedMethods, - numDroppedFields, - numDroppedMethods - )); - - m_destDeobfuscator.setMappings(newMappings); - } - - protected void setSourceType(SourceType val) { - - // show the source classes - m_sourceType = val; - m_sourceClasses.setClasses(deobfuscateClasses(m_sourceType.getSourceClasses(m_classMatches), m_sourceDeobfuscator)); - - // update counts - for (SourceType sourceType : SourceType.values()) { - m_sourceTypeButtons.get(sourceType).setText(String.format("%s (%d)", - sourceType.name(), - sourceType.getSourceClasses(m_classMatches).size() - )); - } - } - - private Collection deobfuscateClasses(Collection in, Deobfuscator deobfuscator) { - List out = Lists.newArrayList(); - for (ClassEntry entry : in) { - - ClassEntry deobf = deobfuscator.deobfuscateEntry(entry); - - // make sure we preserve any scores - if (entry instanceof ScoredClassEntry) { - deobf = new ScoredClassEntry(deobf, ((ScoredClassEntry)entry).getScore()); - } - - out.add(deobf); - } - return out; - } - - protected void setSourceClass(ClassEntry classEntry) { - - Runnable onGetDestClasses = null; - if (m_advanceCheck.isSelected()) { - onGetDestClasses = new Runnable() { - @Override - public void run() { - pickBestDestClass(); - } - }; - } - - setSourceClass(classEntry, onGetDestClasses); - } - - protected void setSourceClass(ClassEntry classEntry, final Runnable onGetDestClasses) { - - // update the current source class - m_sourceClass = classEntry; - m_sourceClassLabel.setText(m_sourceClass != null ? m_sourceClass.getName() : ""); - - if (m_sourceClass != null) { - - // show the dest class(es) - ClassMatch match = m_classMatches.getMatchBySource(m_sourceDeobfuscator.obfuscateEntry(m_sourceClass)); - assert(match != null); - if (match.destClasses.isEmpty()) { - - m_destClasses.setClasses(null); - - // run in a separate thread to keep ui responsive - new Thread() { - @Override - public void run() { - m_destClasses.setClasses(deobfuscateClasses(getLikelyMatches(m_sourceClass), m_destDeobfuscator)); - m_destClasses.expandAll(); - - if (onGetDestClasses != null) { - onGetDestClasses.run(); - } - } - }.start(); - - } else { - - m_destClasses.setClasses(deobfuscateClasses(match.destClasses, m_destDeobfuscator)); - m_destClasses.expandAll(); - - if (onGetDestClasses != null) { - onGetDestClasses.run(); - } - } - } - - setDestClass(null); - m_sourceReader.decompileClass(m_sourceClass, m_sourceDeobfuscator, new Runnable() { - @Override - public void run() { - m_sourceReader.navigateToClassDeclaration(m_sourceClass); - } - }); - - updateMatchButton(); - } - - private Collection getLikelyMatches(ClassEntry sourceClass) { - - ClassEntry obfSourceClass = m_sourceDeobfuscator.obfuscateEntry(sourceClass); - - // set up identifiers - ClassNamer namer = new ClassNamer(m_classMatches.getUniqueMatches()); - ClassIdentifier sourceIdentifier = new ClassIdentifier( - m_sourceDeobfuscator.getJar(), m_sourceDeobfuscator.getJarIndex(), - namer.getSourceNamer(), true - ); - ClassIdentifier destIdentifier = new ClassIdentifier( - m_destDeobfuscator.getJar(), m_destDeobfuscator.getJarIndex(), - namer.getDestNamer(), true - ); - - try { - - // rank all the unmatched dest classes against the source class - ClassIdentity sourceIdentity = sourceIdentifier.identify(obfSourceClass); - List scoredDestClasses = Lists.newArrayList(); - for (ClassEntry unmatchedDestClass : m_classMatches.getUnmatchedDestClasses()) { - ClassIdentity destIdentity = destIdentifier.identify(unmatchedDestClass); - float score = 100.0f*(sourceIdentity.getMatchScore(destIdentity) + destIdentity.getMatchScore(sourceIdentity)) - /(sourceIdentity.getMaxMatchScore() + destIdentity.getMaxMatchScore()); - scoredDestClasses.add(new ScoredClassEntry(unmatchedDestClass, score)); - } - - if (m_top10Matches.isSelected() && scoredDestClasses.size() > 10) { - Collections.sort(scoredDestClasses, new Comparator() { - @Override - public int compare(ClassEntry a, ClassEntry b) { - ScoredClassEntry sa = (ScoredClassEntry)a; - ScoredClassEntry sb = (ScoredClassEntry)b; - return -Float.compare(sa.getScore(), sb.getScore()); - } - }); - scoredDestClasses = scoredDestClasses.subList(0, 10); - } - - return scoredDestClasses; - - } catch (ClassNotFoundException ex) { - throw new Error("Unable to find class " + ex.getMessage()); - } - } - - protected void setDestClass(ClassEntry classEntry) { - - // update the current source class - m_destClass = classEntry; - m_destClassLabel.setText(m_destClass != null ? m_destClass.getName() : ""); - - m_destReader.decompileClass(m_destClass, m_destDeobfuscator, new Runnable() { - @Override - public void run() { - m_destReader.navigateToClassDeclaration(m_destClass); - } - }); - - updateMatchButton(); - } - - private void updateMatchButton() { - - ClassEntry obfSource = m_sourceDeobfuscator.obfuscateEntry(m_sourceClass); - ClassEntry obfDest = m_destDeobfuscator.obfuscateEntry(m_destClass); - - BiMap uniqueMatches = m_classMatches.getUniqueMatches(); - boolean twoSelected = m_sourceClass != null && m_destClass != null; - boolean isMatched = uniqueMatches.containsKey(obfSource) && uniqueMatches.containsValue(obfDest); - boolean canMatch = !uniqueMatches.containsKey(obfSource) && ! uniqueMatches.containsValue(obfDest); - - GuiTricks.deactivateButton(m_matchButton); - if (twoSelected) { - if (isMatched) { - GuiTricks.activateButton(m_matchButton, "Unmatch", new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - onUnmatchClick(); - } - }); - } else if (canMatch) { - GuiTricks.activateButton(m_matchButton, "Match", new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - onMatchClick(); - } - }); - } - } - } - - private void onMatchClick() { - // precondition: source and dest classes are set correctly - - ClassEntry obfSource = m_sourceDeobfuscator.obfuscateEntry(m_sourceClass); - ClassEntry obfDest = m_destDeobfuscator.obfuscateEntry(m_destClass); - - // remove the classes from their match - m_classMatches.removeSource(obfSource); - m_classMatches.removeDest(obfDest); - - // add them as matched classes - m_classMatches.add(new ClassMatch(obfSource, obfDest)); - - ClassEntry nextClass = null; - if (m_advanceCheck.isSelected()) { - nextClass = m_sourceClasses.getNextClass(m_sourceClass); - } - - save(); - updateMatches(); - - if (nextClass != null) { - advance(nextClass); - } - } - - private void onUnmatchClick() { - // precondition: source and dest classes are set to a unique match - - ClassEntry obfSource = m_sourceDeobfuscator.obfuscateEntry(m_sourceClass); - - // remove the source to break the match, then add the source back as unmatched - m_classMatches.removeSource(obfSource); - m_classMatches.add(new ClassMatch(obfSource, null)); - - save(); - updateMatches(); - } - - private void updateMatches() { - updateDestMappings(); - setDestClass(null); - m_destClasses.setClasses(null); - updateMatchButton(); - - // remember where we were in the source tree - String packageName = m_sourceClasses.getSelectedPackage(); - - setSourceType(m_sourceType); - - m_sourceClasses.expandPackage(packageName); - } - - private void save() { - if (m_saveListener != null) { - m_saveListener.save(m_classMatches); - } - } - - private void autoMatch() { - - System.out.println("Automatching..."); - - // compute a new matching - ClassMatching matching = MappingsConverter.computeMatching( - m_sourceDeobfuscator.getJar(), m_sourceDeobfuscator.getJarIndex(), - m_destDeobfuscator.getJar(), m_destDeobfuscator.getJarIndex(), - m_classMatches.getUniqueMatches() - ); - ClassMatches newMatches = new ClassMatches(matching.matches()); - System.out.println(String.format("Automatch found %d new matches", - newMatches.getUniqueMatches().size() - m_classMatches.getUniqueMatches().size() - )); - - // update the current matches - m_classMatches = newMatches; - save(); - updateMatches(); - } - - private void advance() { - advance(null); - } - - private void advance(ClassEntry sourceClass) { - - // make sure we have a source class - if (sourceClass == null) { - sourceClass = m_sourceClasses.getSelectedClass(); - if (sourceClass != null) { - sourceClass = m_sourceClasses.getNextClass(sourceClass); - } else { - sourceClass = m_sourceClasses.getFirstClass(); - } - } - - // set the source class - setSourceClass(sourceClass, new Runnable() { - @Override - public void run() { - pickBestDestClass(); - } - }); - m_sourceClasses.setSelectionClass(sourceClass); - } - - private void pickBestDestClass() { - - // then, pick the best dest class - ClassEntry firstClass = null; - ScoredClassEntry bestDestClass = null; - for (ClassSelectorPackageNode packageNode : m_destClasses.packageNodes()) { - for (ClassSelectorClassNode classNode : m_destClasses.classNodes(packageNode)) { - if (firstClass == null) { - firstClass = classNode.getClassEntry(); - } - if (classNode.getClassEntry() instanceof ScoredClassEntry) { - ScoredClassEntry scoredClass = (ScoredClassEntry)classNode.getClassEntry(); - if (bestDestClass == null || bestDestClass.getScore() < scoredClass.getScore()) { - bestDestClass = scoredClass; - } - } - } - } - - // pick the entry to show - ClassEntry destClass = null; - if (bestDestClass != null) { - destClass = bestDestClass; - } else if (firstClass != null) { - destClass = firstClass; - } - - setDestClass(destClass); - m_destClasses.setSelectionClass(destClass); - } - - private void toggleTop10Matches() { - if (m_sourceClass != null) { - m_destClasses.clearSelection(); - m_destClasses.setClasses(deobfuscateClasses(getLikelyMatches(m_sourceClass), m_destDeobfuscator)); - m_destClasses.expandAll(); - } - } -} diff --git a/src/cuchaz/enigma/gui/ClassSelector.java b/src/cuchaz/enigma/gui/ClassSelector.java deleted file mode 100644 index 11333a96..00000000 --- a/src/cuchaz/enigma/gui/ClassSelector.java +++ /dev/null @@ -1,293 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.Enumeration; -import java.util.List; -import java.util.Map; - -import javax.swing.JTree; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreePath; - -import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; - -import cuchaz.enigma.mapping.ClassEntry; - -public class ClassSelector extends JTree { - - private static final long serialVersionUID = -7632046902384775977L; - - public interface ClassSelectionListener { - void onSelectClass(ClassEntry classEntry); - } - - public static Comparator ObfuscatedClassEntryComparator; - public static Comparator DeobfuscatedClassEntryComparator; - - static { - ObfuscatedClassEntryComparator = new Comparator() { - @Override - public int compare(ClassEntry a, ClassEntry b) { - String aname = a.getName(); - String bname = a.getName(); - if (aname.length() != bname.length()) { - return aname.length() - bname.length(); - } - return aname.compareTo(bname); - } - }; - - DeobfuscatedClassEntryComparator = new Comparator() { - @Override - public int compare(ClassEntry a, ClassEntry b) { - if (a instanceof ScoredClassEntry && b instanceof ScoredClassEntry) { - return Float.compare( - ((ScoredClassEntry)b).getScore(), - ((ScoredClassEntry)a).getScore() - ); - } - return a.getName().compareTo(b.getName()); - } - }; - } - - private ClassSelectionListener m_listener; - private Comparator m_comparator; - - public ClassSelector(Comparator comparator) { - m_comparator = comparator; - - // configure the tree control - setRootVisible(false); - setShowsRootHandles(false); - setModel(null); - - // hook events - addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent event) { - if (m_listener != null && event.getClickCount() == 2) { - // get the selected node - TreePath path = getSelectionPath(); - if (path != null && path.getLastPathComponent() instanceof ClassSelectorClassNode) { - ClassSelectorClassNode node = (ClassSelectorClassNode)path.getLastPathComponent(); - m_listener.onSelectClass(node.getClassEntry()); - } - } - } - }); - - // init defaults - m_listener = null; - } - - public void setListener(ClassSelectionListener val) { - m_listener = val; - } - - public void setClasses(Collection classEntries) { - if (classEntries == null) { - setModel(null); - return; - } - - // build the package names - Map packages = Maps.newHashMap(); - for (ClassEntry classEntry : classEntries) { - packages.put(classEntry.getPackageName(), null); - } - - // sort the packages - List sortedPackageNames = Lists.newArrayList(packages.keySet()); - Collections.sort(sortedPackageNames, new Comparator() { - @Override - public int compare(String a, String b) { - // I can never keep this rule straight when writing these damn things... - // a < b => -1, a == b => 0, a > b => +1 - - String[] aparts = a.split("/"); - String[] bparts = b.split("/"); - for (int i = 0; true; i++) { - if (i >= aparts.length) { - return -1; - } else if (i >= bparts.length) { - return 1; - } - - int result = aparts[i].compareTo(bparts[i]); - if (result != 0) { - return result; - } - } - } - }); - - // create the root node and the package nodes - DefaultMutableTreeNode root = new DefaultMutableTreeNode(); - for (String packageName : sortedPackageNames) { - ClassSelectorPackageNode node = new ClassSelectorPackageNode(packageName); - packages.put(packageName, node); - root.add(node); - } - - // put the classes into packages - Multimap packagedClassEntries = ArrayListMultimap.create(); - for (ClassEntry classEntry : classEntries) { - packagedClassEntries.put(classEntry.getPackageName(), classEntry); - } - - // build the class nodes - for (String packageName : packagedClassEntries.keySet()) { - // sort the class entries - List classEntriesInPackage = Lists.newArrayList(packagedClassEntries.get(packageName)); - Collections.sort(classEntriesInPackage, m_comparator); - - // create the nodes in order - for (ClassEntry classEntry : classEntriesInPackage) { - ClassSelectorPackageNode node = packages.get(packageName); - node.add(new ClassSelectorClassNode(classEntry)); - } - } - - // finally, update the tree control - setModel(new DefaultTreeModel(root)); - } - - public ClassEntry getSelectedClass() { - if (!isSelectionEmpty()) { - Object selectedNode = getSelectionPath().getLastPathComponent(); - if (selectedNode instanceof ClassSelectorClassNode) { - ClassSelectorClassNode classNode = (ClassSelectorClassNode)selectedNode; - return classNode.getClassEntry(); - } - } - return null; - } - - public String getSelectedPackage() { - if (!isSelectionEmpty()) { - Object selectedNode = getSelectionPath().getLastPathComponent(); - if (selectedNode instanceof ClassSelectorPackageNode) { - ClassSelectorPackageNode packageNode = (ClassSelectorPackageNode)selectedNode; - return packageNode.getPackageName(); - } else if (selectedNode instanceof ClassSelectorClassNode) { - ClassSelectorClassNode classNode = (ClassSelectorClassNode)selectedNode; - return classNode.getClassEntry().getPackageName(); - } - } - return null; - } - - public Iterable packageNodes() { - List nodes = Lists.newArrayList(); - DefaultMutableTreeNode root = (DefaultMutableTreeNode)getModel().getRoot(); - Enumeration children = root.children(); - while (children.hasMoreElements()) { - ClassSelectorPackageNode packageNode = (ClassSelectorPackageNode)children.nextElement(); - nodes.add(packageNode); - } - return nodes; - } - - public Iterable classNodes(ClassSelectorPackageNode packageNode) { - List nodes = Lists.newArrayList(); - Enumeration children = packageNode.children(); - while (children.hasMoreElements()) { - ClassSelectorClassNode classNode = (ClassSelectorClassNode)children.nextElement(); - nodes.add(classNode); - } - return nodes; - } - - public void expandPackage(String packageName) { - if (packageName == null) { - return; - } - for (ClassSelectorPackageNode packageNode : packageNodes()) { - if (packageNode.getPackageName().equals(packageName)) { - expandPath(new TreePath(new Object[] {getModel().getRoot(), packageNode})); - return; - } - } - } - - public void expandAll() { - for (ClassSelectorPackageNode packageNode : packageNodes()) { - expandPath(new TreePath(new Object[] {getModel().getRoot(), packageNode})); - } - } - - public ClassEntry getFirstClass() { - for (ClassSelectorPackageNode packageNode : packageNodes()) { - for (ClassSelectorClassNode classNode : classNodes(packageNode)) { - return classNode.getClassEntry(); - } - } - return null; - } - - public ClassSelectorPackageNode getPackageNode(ClassEntry entry) { - for (ClassSelectorPackageNode packageNode : packageNodes()) { - if (packageNode.getPackageName().equals(entry.getPackageName())) { - return packageNode; - } - } - return null; - } - - public ClassEntry getNextClass(ClassEntry entry) { - boolean foundIt = false; - for (ClassSelectorPackageNode packageNode : packageNodes()) { - if (!foundIt) { - // skip to the package with our target in it - if (packageNode.getPackageName().equals(entry.getPackageName())) { - for (ClassSelectorClassNode classNode : classNodes(packageNode)) { - if (!foundIt) { - if (classNode.getClassEntry().equals(entry)) { - foundIt = true; - } - } else { - // return the next class - return classNode.getClassEntry(); - } - } - } - } else { - // return the next class - for (ClassSelectorClassNode classNode : classNodes(packageNode)) { - return classNode.getClassEntry(); - } - } - } - return null; - } - - public void setSelectionClass(ClassEntry classEntry) { - expandPackage(classEntry.getPackageName()); - for (ClassSelectorPackageNode packageNode : packageNodes()) { - for (ClassSelectorClassNode classNode : classNodes(packageNode)) { - if (classNode.getClassEntry().equals(classEntry)) { - setSelectionPath(new TreePath(new Object[] {getModel().getRoot(), packageNode, classNode})); - } - } - } - } -} diff --git a/src/cuchaz/enigma/gui/ClassSelectorClassNode.java b/src/cuchaz/enigma/gui/ClassSelectorClassNode.java deleted file mode 100644 index 1219e890..00000000 --- a/src/cuchaz/enigma/gui/ClassSelectorClassNode.java +++ /dev/null @@ -1,50 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import javax.swing.tree.DefaultMutableTreeNode; - -import cuchaz.enigma.mapping.ClassEntry; - -public class ClassSelectorClassNode extends DefaultMutableTreeNode { - - private static final long serialVersionUID = -8956754339813257380L; - - private ClassEntry m_classEntry; - - public ClassSelectorClassNode(ClassEntry classEntry) { - m_classEntry = classEntry; - } - - public ClassEntry getClassEntry() { - return m_classEntry; - } - - @Override - public String toString() { - if (m_classEntry instanceof ScoredClassEntry) { - return String.format("%d%% %s", (int)((ScoredClassEntry)m_classEntry).getScore(), m_classEntry.getSimpleName()); - } - return m_classEntry.getSimpleName(); - } - - @Override - public boolean equals(Object other) { - if (other instanceof ClassSelectorClassNode) { - return equals((ClassSelectorClassNode)other); - } - return false; - } - - public boolean equals(ClassSelectorClassNode other) { - return m_classEntry.equals(other.m_classEntry); - } -} diff --git a/src/cuchaz/enigma/gui/ClassSelectorPackageNode.java b/src/cuchaz/enigma/gui/ClassSelectorPackageNode.java deleted file mode 100644 index 7259f54d..00000000 --- a/src/cuchaz/enigma/gui/ClassSelectorPackageNode.java +++ /dev/null @@ -1,45 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import javax.swing.tree.DefaultMutableTreeNode; - -public class ClassSelectorPackageNode extends DefaultMutableTreeNode { - - private static final long serialVersionUID = -3730868701219548043L; - - private String m_packageName; - - public ClassSelectorPackageNode(String packageName) { - m_packageName = packageName; - } - - public String getPackageName() { - return m_packageName; - } - - @Override - public String toString() { - return m_packageName; - } - - @Override - public boolean equals(Object other) { - if (other instanceof ClassSelectorPackageNode) { - return equals((ClassSelectorPackageNode)other); - } - return false; - } - - public boolean equals(ClassSelectorPackageNode other) { - return m_packageName.equals(other.m_packageName); - } -} diff --git a/src/cuchaz/enigma/gui/CodeReader.java b/src/cuchaz/enigma/gui/CodeReader.java deleted file mode 100644 index 5033a2cd..00000000 --- a/src/cuchaz/enigma/gui/CodeReader.java +++ /dev/null @@ -1,222 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.JEditorPane; -import javax.swing.SwingUtilities; -import javax.swing.Timer; -import javax.swing.event.CaretEvent; -import javax.swing.event.CaretListener; -import javax.swing.text.BadLocationException; -import javax.swing.text.Highlighter.HighlightPainter; - -import com.strobel.decompiler.languages.java.ast.CompilationUnit; - -import cuchaz.enigma.Deobfuscator; -import cuchaz.enigma.analysis.EntryReference; -import cuchaz.enigma.analysis.SourceIndex; -import cuchaz.enigma.analysis.Token; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.Entry; -import de.sciss.syntaxpane.DefaultSyntaxKit; - - -public class CodeReader extends JEditorPane { - - private static final long serialVersionUID = 3673180950485748810L; - - private static final Object m_lock = new Object(); - - public static interface SelectionListener { - void onSelect(EntryReference reference); - } - - private SelectionHighlightPainter m_selectionHighlightPainter; - private SourceIndex m_sourceIndex; - private SelectionListener m_selectionListener; - - public CodeReader() { - - setEditable(false); - setContentType("text/java"); - - // turn off token highlighting (it's wrong most of the time anyway...) - DefaultSyntaxKit kit = (DefaultSyntaxKit)getEditorKit(); - kit.toggleComponent(this, "de.sciss.syntaxpane.components.TokenMarker"); - - // hook events - addCaretListener(new CaretListener() { - @Override - public void caretUpdate(CaretEvent event) { - if (m_selectionListener != null && m_sourceIndex != null) { - Token token = m_sourceIndex.getReferenceToken(event.getDot()); - if (token != null) { - m_selectionListener.onSelect(m_sourceIndex.getDeobfReference(token)); - } else { - m_selectionListener.onSelect(null); - } - } - } - }); - - m_selectionHighlightPainter = new SelectionHighlightPainter(); - m_sourceIndex = null; - m_selectionListener = null; - } - - public void setSelectionListener(SelectionListener val) { - m_selectionListener = val; - } - - public void setCode(String code) { - // sadly, the java lexer is not thread safe, so we have to serialize all these calls - synchronized (m_lock) { - setText(code); - } - } - - public SourceIndex getSourceIndex() { - return m_sourceIndex; - } - - public void decompileClass(ClassEntry classEntry, Deobfuscator deobfuscator) { - decompileClass(classEntry, deobfuscator, null); - } - - public void decompileClass(ClassEntry classEntry, Deobfuscator deobfuscator, Runnable callback) { - decompileClass(classEntry, deobfuscator, null, callback); - } - - public void decompileClass(final ClassEntry classEntry, final Deobfuscator deobfuscator, final Boolean ignoreBadTokens, final Runnable callback) { - - if (classEntry == null) { - setCode(null); - return; - } - - setCode("(decompiling...)"); - - // run decompilation in a separate thread to keep ui responsive - new Thread() { - @Override - public void run() { - - // decompile it - CompilationUnit sourceTree = deobfuscator.getSourceTree(classEntry.getOutermostClassName()); - String source = deobfuscator.getSource(sourceTree); - setCode(source); - m_sourceIndex = deobfuscator.getSourceIndex(sourceTree, source, ignoreBadTokens); - - if (callback != null) { - callback.run(); - } - } - }.start(); - } - - public void navigateToClassDeclaration(ClassEntry classEntry) { - - // navigate to the class declaration - Token token = m_sourceIndex.getDeclarationToken(classEntry); - if (token == null) { - // couldn't find the class declaration token, might be an anonymous class - // look for any declaration in that class instead - for (Entry entry : m_sourceIndex.declarations()) { - if (entry.getClassEntry().equals(classEntry)) { - token = m_sourceIndex.getDeclarationToken(entry); - break; - } - } - } - - if (token != null) { - navigateToToken(token); - } else { - // couldn't find anything =( - System.out.println("Unable to find declaration in source for " + classEntry); - } - } - - public void navigateToToken(final Token token) { - navigateToToken(this, token, m_selectionHighlightPainter); - } - - // HACKHACK: someday we can update the main GUI to use this code reader - public static void navigateToToken(final JEditorPane editor, final Token token, final HighlightPainter highlightPainter) { - - // set the caret position to the token - editor.setCaretPosition(token.start); - editor.grabFocus(); - - try { - // make sure the token is visible in the scroll window - Rectangle start = editor.modelToView(token.start); - Rectangle end = editor.modelToView(token.end); - final Rectangle show = start.union(end); - show.grow(start.width * 10, start.height * 6); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - editor.scrollRectToVisible(show); - } - }); - } catch (BadLocationException ex) { - throw new Error(ex); - } - - // highlight the token momentarily - final Timer timer = new Timer(200, new ActionListener() { - private int m_counter = 0; - private Object m_highlight = null; - - @Override - public void actionPerformed(ActionEvent event) { - if (m_counter % 2 == 0) { - try { - m_highlight = editor.getHighlighter().addHighlight(token.start, token.end, highlightPainter); - } catch (BadLocationException ex) { - // don't care - } - } else if (m_highlight != null) { - editor.getHighlighter().removeHighlight(m_highlight); - } - - if (m_counter++ > 6) { - Timer timer = (Timer)event.getSource(); - timer.stop(); - } - } - }); - timer.start(); - } - - public void setHighlightedTokens(Iterable tokens, HighlightPainter painter) { - for (Token token : tokens) { - setHighlightedToken(token, painter); - } - } - - public void setHighlightedToken(Token token, HighlightPainter painter) { - try { - getHighlighter().addHighlight(token.start, token.end, painter); - } catch (BadLocationException ex) { - throw new IllegalArgumentException(ex); - } - } - - public void clearHighlights() { - getHighlighter().removeAllHighlights(); - } -} diff --git a/src/cuchaz/enigma/gui/CrashDialog.java b/src/cuchaz/enigma/gui/CrashDialog.java deleted file mode 100644 index 904273c1..00000000 --- a/src/cuchaz/enigma/gui/CrashDialog.java +++ /dev/null @@ -1,101 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import java.awt.BorderLayout; -import java.awt.Container; -import java.awt.FlowLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.PrintWriter; -import java.io.StringWriter; - -import javax.swing.BorderFactory; -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTextArea; -import javax.swing.WindowConstants; - -import cuchaz.enigma.Constants; - -public class CrashDialog { - - private static CrashDialog m_instance = null; - - private JFrame m_frame; - private JTextArea m_text; - - private CrashDialog(JFrame parent) { - // init frame - m_frame = new JFrame(Constants.Name + " - Crash Report"); - final Container pane = m_frame.getContentPane(); - pane.setLayout(new BorderLayout()); - - JLabel label = new JLabel(Constants.Name + " has crashed! =("); - label.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); - pane.add(label, BorderLayout.NORTH); - - // report panel - m_text = new JTextArea(); - m_text.setTabSize(2); - pane.add(new JScrollPane(m_text), BorderLayout.CENTER); - - // buttons panel - JPanel buttonsPanel = new JPanel(); - FlowLayout buttonsLayout = new FlowLayout(); - buttonsLayout.setAlignment(FlowLayout.RIGHT); - buttonsPanel.setLayout(buttonsLayout); - buttonsPanel.add(GuiTricks.unboldLabel(new JLabel("If you choose exit, you will lose any unsaved work."))); - JButton ignoreButton = new JButton("Ignore"); - ignoreButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - // close (hide) the dialog - m_frame.setVisible(false); - } - }); - buttonsPanel.add(ignoreButton); - JButton exitButton = new JButton("Exit"); - exitButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - // exit enigma - System.exit(1); - } - }); - buttonsPanel.add(exitButton); - pane.add(buttonsPanel, BorderLayout.SOUTH); - - // show the frame - m_frame.setSize(600, 400); - m_frame.setLocationRelativeTo(parent); - m_frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); - } - - public static void init(JFrame parent) { - m_instance = new CrashDialog(parent); - } - - public static void show(Throwable ex) { - // get the error report - StringWriter buf = new StringWriter(); - ex.printStackTrace(new PrintWriter(buf)); - String report = buf.toString(); - - // show it! - m_instance.m_text.setText(report); - m_instance.m_frame.doLayout(); - m_instance.m_frame.setVisible(true); - } -} diff --git a/src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java b/src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java deleted file mode 100644 index 57210a84..00000000 --- a/src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java +++ /dev/null @@ -1,21 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import java.awt.Color; - -public class DeobfuscatedHighlightPainter extends BoxHighlightPainter { - - public DeobfuscatedHighlightPainter() { - // green ish - super(new Color(220, 255, 220), new Color(80, 160, 80)); - } -} diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java deleted file mode 100644 index f9192d31..00000000 --- a/src/cuchaz/enigma/gui/Gui.java +++ /dev/null @@ -1,1122 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.GridLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.InputEvent; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.io.File; -import java.io.IOException; -import java.lang.Thread.UncaughtExceptionHandler; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Vector; -import java.util.jar.JarFile; - -import javax.swing.BorderFactory; -import javax.swing.JEditorPane; -import javax.swing.JFileChooser; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JList; -import javax.swing.JMenu; -import javax.swing.JMenuBar; -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.JScrollPane; -import javax.swing.JSplitPane; -import javax.swing.JTabbedPane; -import javax.swing.JTextField; -import javax.swing.JTree; -import javax.swing.KeyStroke; -import javax.swing.ListSelectionModel; -import javax.swing.WindowConstants; -import javax.swing.event.CaretEvent; -import javax.swing.event.CaretListener; -import javax.swing.text.BadLocationException; -import javax.swing.text.Highlighter; -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreeNode; -import javax.swing.tree.TreePath; - -import com.google.common.collect.Lists; - -import cuchaz.enigma.Constants; -import cuchaz.enigma.ExceptionIgnorer; -import cuchaz.enigma.analysis.BehaviorReferenceTreeNode; -import cuchaz.enigma.analysis.ClassImplementationsTreeNode; -import cuchaz.enigma.analysis.ClassInheritanceTreeNode; -import cuchaz.enigma.analysis.EntryReference; -import cuchaz.enigma.analysis.FieldReferenceTreeNode; -import cuchaz.enigma.analysis.MethodImplementationsTreeNode; -import cuchaz.enigma.analysis.MethodInheritanceTreeNode; -import cuchaz.enigma.analysis.ReferenceTreeNode; -import cuchaz.enigma.analysis.Token; -import cuchaz.enigma.gui.ClassSelector.ClassSelectionListener; -import cuchaz.enigma.mapping.ArgumentEntry; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.ConstructorEntry; -import cuchaz.enigma.mapping.Entry; -import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.IllegalNameException; -import cuchaz.enigma.mapping.MappingParseException; -import cuchaz.enigma.mapping.MethodEntry; -import cuchaz.enigma.mapping.Signature; -import de.sciss.syntaxpane.DefaultSyntaxKit; - -public class Gui { - - private GuiController m_controller; - - // controls - private JFrame m_frame; - private ClassSelector m_obfClasses; - private ClassSelector m_deobfClasses; - private JEditorPane m_editor; - private JPanel m_classesPanel; - private JSplitPane m_splitClasses; - private JPanel m_infoPanel; - private ObfuscatedHighlightPainter m_obfuscatedHighlightPainter; - private DeobfuscatedHighlightPainter m_deobfuscatedHighlightPainter; - private OtherHighlightPainter m_otherHighlightPainter; - private SelectionHighlightPainter m_selectionHighlightPainter; - private JTree m_inheritanceTree; - private JTree m_implementationsTree; - private JTree m_callsTree; - private JList m_tokens; - private JTabbedPane m_tabs; - - // dynamic menu items - private JMenuItem m_closeJarMenu; - private JMenuItem m_openMappingsMenu; - private JMenuItem m_saveMappingsMenu; - private JMenuItem m_saveMappingsAsMenu; - private JMenuItem m_closeMappingsMenu; - private JMenuItem m_renameMenu; - private JMenuItem m_showInheritanceMenu; - private JMenuItem m_openEntryMenu; - private JMenuItem m_openPreviousMenu; - private JMenuItem m_showCallsMenu; - private JMenuItem m_showImplementationsMenu; - private JMenuItem m_toggleMappingMenu; - private JMenuItem m_exportSourceMenu; - private JMenuItem m_exportJarMenu; - - // state - private EntryReference m_reference; - private JFileChooser m_jarFileChooser; - private JFileChooser m_mappingsFileChooser; - private JFileChooser m_exportSourceFileChooser; - private JFileChooser m_exportJarFileChooser; - - public Gui() { - - // init frame - m_frame = new JFrame(Constants.Name); - final Container pane = m_frame.getContentPane(); - pane.setLayout(new BorderLayout()); - - if (Boolean.parseBoolean(System.getProperty("enigma.catchExceptions", "true"))) { - // install a global exception handler to the event thread - CrashDialog.init(m_frame); - Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() { - @Override - public void uncaughtException(Thread thread, Throwable t) { - t.printStackTrace(System.err); - if (!ExceptionIgnorer.shouldIgnore(t)) { - CrashDialog.show(t); - } - } - }); - } - - m_controller = new GuiController(this); - - // init file choosers - m_jarFileChooser = new JFileChooser(); - m_mappingsFileChooser = new JFileChooser(); - m_exportSourceFileChooser = new JFileChooser(); - m_exportSourceFileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - m_exportJarFileChooser = new JFileChooser(); - - // init obfuscated classes list - m_obfClasses = new ClassSelector(ClassSelector.ObfuscatedClassEntryComparator); - m_obfClasses.setListener(new ClassSelectionListener() { - @Override - public void onSelectClass(ClassEntry classEntry) { - navigateTo(classEntry); - } - }); - JScrollPane obfScroller = new JScrollPane(m_obfClasses); - JPanel obfPanel = new JPanel(); - obfPanel.setLayout(new BorderLayout()); - obfPanel.add(new JLabel("Obfuscated Classes"), BorderLayout.NORTH); - obfPanel.add(obfScroller, BorderLayout.CENTER); - - // init deobfuscated classes list - m_deobfClasses = new ClassSelector(ClassSelector.DeobfuscatedClassEntryComparator); - m_deobfClasses.setListener(new ClassSelectionListener() { - @Override - public void onSelectClass(ClassEntry classEntry) { - navigateTo(classEntry); - } - }); - JScrollPane deobfScroller = new JScrollPane(m_deobfClasses); - JPanel deobfPanel = new JPanel(); - deobfPanel.setLayout(new BorderLayout()); - deobfPanel.add(new JLabel("De-obfuscated Classes"), BorderLayout.NORTH); - deobfPanel.add(deobfScroller, BorderLayout.CENTER); - - // set up classes panel (don't add the splitter yet) - m_splitClasses = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, obfPanel, deobfPanel); - m_splitClasses.setResizeWeight(0.3); - m_classesPanel = new JPanel(); - m_classesPanel.setLayout(new BorderLayout()); - m_classesPanel.setPreferredSize(new Dimension(250, 0)); - - // init info panel - m_infoPanel = new JPanel(); - m_infoPanel.setLayout(new GridLayout(4, 1, 0, 0)); - m_infoPanel.setPreferredSize(new Dimension(0, 100)); - m_infoPanel.setBorder(BorderFactory.createTitledBorder("Identifier Info")); - clearReference(); - - // init editor - DefaultSyntaxKit.initKit(); - m_obfuscatedHighlightPainter = new ObfuscatedHighlightPainter(); - m_deobfuscatedHighlightPainter = new DeobfuscatedHighlightPainter(); - m_otherHighlightPainter = new OtherHighlightPainter(); - m_selectionHighlightPainter = new SelectionHighlightPainter(); - m_editor = new JEditorPane(); - m_editor.setEditable(false); - m_editor.setCaret(new BrowserCaret()); - JScrollPane sourceScroller = new JScrollPane(m_editor); - m_editor.setContentType("text/java"); - m_editor.addCaretListener(new CaretListener() { - @Override - public void caretUpdate(CaretEvent event) { - onCaretMove(event.getDot()); - } - }); - m_editor.addKeyListener(new KeyAdapter() { - @Override - public void keyPressed(KeyEvent event) { - switch (event.getKeyCode()) { - case KeyEvent.VK_R: - m_renameMenu.doClick(); - break; - - case KeyEvent.VK_I: - m_showInheritanceMenu.doClick(); - break; - - case KeyEvent.VK_M: - m_showImplementationsMenu.doClick(); - break; - - case KeyEvent.VK_N: - m_openEntryMenu.doClick(); - break; - - case KeyEvent.VK_P: - m_openPreviousMenu.doClick(); - break; - - case KeyEvent.VK_C: - m_showCallsMenu.doClick(); - break; - - case KeyEvent.VK_T: - m_toggleMappingMenu.doClick(); - break; - } - } - }); - - // turn off token highlighting (it's wrong most of the time anyway...) - DefaultSyntaxKit kit = (DefaultSyntaxKit)m_editor.getEditorKit(); - kit.toggleComponent(m_editor, "de.sciss.syntaxpane.components.TokenMarker"); - - // init editor popup menu - JPopupMenu popupMenu = new JPopupMenu(); - m_editor.setComponentPopupMenu(popupMenu); - { - JMenuItem menu = new JMenuItem("Rename"); - menu.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - startRename(); - } - }); - menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, 0)); - menu.setEnabled(false); - popupMenu.add(menu); - m_renameMenu = menu; - } - { - JMenuItem menu = new JMenuItem("Show Inheritance"); - menu.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - showInheritance(); - } - }); - menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, 0)); - menu.setEnabled(false); - popupMenu.add(menu); - m_showInheritanceMenu = menu; - } - { - JMenuItem menu = new JMenuItem("Show Implementations"); - menu.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - showImplementations(); - } - }); - menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, 0)); - menu.setEnabled(false); - popupMenu.add(menu); - m_showImplementationsMenu = menu; - } - { - JMenuItem menu = new JMenuItem("Show Calls"); - menu.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - showCalls(); - } - }); - menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, 0)); - menu.setEnabled(false); - popupMenu.add(menu); - m_showCallsMenu = menu; - } - { - JMenuItem menu = new JMenuItem("Go to Declaration"); - menu.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - navigateTo(m_reference.entry); - } - }); - menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, 0)); - menu.setEnabled(false); - popupMenu.add(menu); - m_openEntryMenu = menu; - } - { - JMenuItem menu = new JMenuItem("Go to previous"); - menu.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - m_controller.openPreviousReference(); - } - }); - menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, 0)); - menu.setEnabled(false); - popupMenu.add(menu); - m_openPreviousMenu = menu; - } - { - JMenuItem menu = new JMenuItem("Mark as deobfuscated"); - menu.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - toggleMapping(); - } - }); - menu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, 0)); - menu.setEnabled(false); - popupMenu.add(menu); - m_toggleMappingMenu = menu; - } - - // init inheritance panel - m_inheritanceTree = new JTree(); - m_inheritanceTree.setModel(null); - m_inheritanceTree.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent event) { - if (event.getClickCount() == 2) { - // get the selected node - TreePath path = m_inheritanceTree.getSelectionPath(); - if (path == null) { - return; - } - - Object node = path.getLastPathComponent(); - if (node instanceof ClassInheritanceTreeNode) { - ClassInheritanceTreeNode classNode = (ClassInheritanceTreeNode)node; - navigateTo(new ClassEntry(classNode.getObfClassName())); - } else if (node instanceof MethodInheritanceTreeNode) { - MethodInheritanceTreeNode methodNode = (MethodInheritanceTreeNode)node; - if (methodNode.isImplemented()) { - navigateTo(methodNode.getMethodEntry()); - } - } - } - } - }); - JPanel inheritancePanel = new JPanel(); - inheritancePanel.setLayout(new BorderLayout()); - inheritancePanel.add(new JScrollPane(m_inheritanceTree)); - - // init implementations panel - m_implementationsTree = new JTree(); - m_implementationsTree.setModel(null); - m_implementationsTree.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent event) { - if (event.getClickCount() == 2) { - // get the selected node - TreePath path = m_implementationsTree.getSelectionPath(); - if (path == null) { - return; - } - - Object node = path.getLastPathComponent(); - if (node instanceof ClassImplementationsTreeNode) { - ClassImplementationsTreeNode classNode = (ClassImplementationsTreeNode)node; - navigateTo(classNode.getClassEntry()); - } else if (node instanceof MethodImplementationsTreeNode) { - MethodImplementationsTreeNode methodNode = (MethodImplementationsTreeNode)node; - navigateTo(methodNode.getMethodEntry()); - } - } - } - }); - JPanel implementationsPanel = new JPanel(); - implementationsPanel.setLayout(new BorderLayout()); - implementationsPanel.add(new JScrollPane(m_implementationsTree)); - - // init call panel - m_callsTree = new JTree(); - m_callsTree.setModel(null); - m_callsTree.addMouseListener(new MouseAdapter() { - @SuppressWarnings("unchecked") - @Override - public void mouseClicked(MouseEvent event) { - if (event.getClickCount() == 2) { - // get the selected node - TreePath path = m_callsTree.getSelectionPath(); - if (path == null) { - return; - } - - Object node = path.getLastPathComponent(); - if (node instanceof ReferenceTreeNode) { - ReferenceTreeNode referenceNode = ((ReferenceTreeNode)node); - if (referenceNode.getReference() != null) { - navigateTo(referenceNode.getReference()); - } else { - navigateTo(referenceNode.getEntry()); - } - } - } - } - }); - m_tokens = new JList(); - m_tokens.setCellRenderer(new TokenListCellRenderer(m_controller)); - m_tokens.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - m_tokens.setLayoutOrientation(JList.VERTICAL); - m_tokens.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent event) { - if (event.getClickCount() == 2) { - Token selected = m_tokens.getSelectedValue(); - if (selected != null) { - showToken(selected); - } - } - } - }); - m_tokens.setPreferredSize(new Dimension(0, 200)); - m_tokens.setMinimumSize(new Dimension(0, 200)); - JSplitPane callPanel = new JSplitPane( - JSplitPane.VERTICAL_SPLIT, - true, - new JScrollPane(m_callsTree), - new JScrollPane(m_tokens) - ); - callPanel.setResizeWeight(1); // let the top side take all the slack - callPanel.resetToPreferredSizes(); - - // layout controls - JPanel centerPanel = new JPanel(); - centerPanel.setLayout(new BorderLayout()); - centerPanel.add(m_infoPanel, BorderLayout.NORTH); - centerPanel.add(sourceScroller, BorderLayout.CENTER); - m_tabs = new JTabbedPane(); - m_tabs.setPreferredSize(new Dimension(250, 0)); - m_tabs.addTab("Inheritance", inheritancePanel); - m_tabs.addTab("Implementations", implementationsPanel); - m_tabs.addTab("Call Graph", callPanel); - JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, m_tabs); - splitRight.setResizeWeight(1); // let the left side take all the slack - splitRight.resetToPreferredSizes(); - JSplitPane splitCenter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, m_classesPanel, splitRight); - splitCenter.setResizeWeight(0); // let the right side take all the slack - pane.add(splitCenter, BorderLayout.CENTER); - - // init menus - JMenuBar menuBar = new JMenuBar(); - m_frame.setJMenuBar(menuBar); - { - JMenu menu = new JMenu("File"); - menuBar.add(menu); - { - JMenuItem item = new JMenuItem("Open Jar..."); - menu.add(item); - item.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - if (m_jarFileChooser.showOpenDialog(m_frame) == JFileChooser.APPROVE_OPTION) { - // load the jar in a separate thread - new Thread() { - @Override - public void run() { - try { - m_controller.openJar(new JarFile(m_jarFileChooser.getSelectedFile())); - } catch (IOException ex) { - throw new Error(ex); - } - } - }.start(); - } - } - }); - } - { - JMenuItem item = new JMenuItem("Close Jar"); - menu.add(item); - item.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - m_controller.closeJar(); - } - }); - m_closeJarMenu = item; - } - menu.addSeparator(); - { - JMenuItem item = new JMenuItem("Open Mappings..."); - menu.add(item); - item.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - if (m_mappingsFileChooser.showOpenDialog(m_frame) == JFileChooser.APPROVE_OPTION) { - try { - m_controller.openMappings(m_mappingsFileChooser.getSelectedFile()); - } catch (IOException ex) { - throw new Error(ex); - } catch (MappingParseException ex) { - JOptionPane.showMessageDialog(m_frame, ex.getMessage()); - } - } - } - }); - m_openMappingsMenu = item; - } - { - JMenuItem item = new JMenuItem("Save Mappings"); - menu.add(item); - item.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - try { - m_controller.saveMappings(m_mappingsFileChooser.getSelectedFile()); - } catch (IOException ex) { - throw new Error(ex); - } - } - }); - item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK)); - m_saveMappingsMenu = item; - } - { - JMenuItem item = new JMenuItem("Save Mappings As..."); - menu.add(item); - item.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - if (m_mappingsFileChooser.showSaveDialog(m_frame) == JFileChooser.APPROVE_OPTION) { - try { - m_controller.saveMappings(m_mappingsFileChooser.getSelectedFile()); - m_saveMappingsMenu.setEnabled(true); - } catch (IOException ex) { - throw new Error(ex); - } - } - } - }); - item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK)); - m_saveMappingsAsMenu = item; - } - { - JMenuItem item = new JMenuItem("Close Mappings"); - menu.add(item); - item.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - m_controller.closeMappings(); - } - }); - m_closeMappingsMenu = item; - } - menu.addSeparator(); - { - JMenuItem item = new JMenuItem("Export Source..."); - menu.add(item); - item.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - if (m_exportSourceFileChooser.showSaveDialog(m_frame) == JFileChooser.APPROVE_OPTION) { - m_controller.exportSource(m_exportSourceFileChooser.getSelectedFile()); - } - } - }); - m_exportSourceMenu = item; - } - { - JMenuItem item = new JMenuItem("Export Jar..."); - menu.add(item); - item.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - if (m_exportJarFileChooser.showSaveDialog(m_frame) == JFileChooser.APPROVE_OPTION) { - m_controller.exportJar(m_exportJarFileChooser.getSelectedFile()); - } - } - }); - m_exportJarMenu = item; - } - menu.addSeparator(); - { - JMenuItem item = new JMenuItem("Exit"); - menu.add(item); - item.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - close(); - } - }); - } - } - { - JMenu menu = new JMenu("Help"); - menuBar.add(menu); - { - JMenuItem item = new JMenuItem("About"); - menu.add(item); - item.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - AboutDialog.show(m_frame); - } - }); - } - } - - // init state - onCloseJar(); - - m_frame.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent event) { - close(); - } - }); - - // show the frame - pane.doLayout(); - m_frame.setSize(1024, 576); - m_frame.setMinimumSize(new Dimension(640, 480)); - m_frame.setVisible(true); - m_frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); - } - - public JFrame getFrame() { - return m_frame; - } - - public GuiController getController() { - return m_controller; - } - - public void onStartOpenJar() { - m_classesPanel.removeAll(); - JPanel panel = new JPanel(); - panel.setLayout(new FlowLayout()); - panel.add(new JLabel("Loading...")); - m_classesPanel.add(panel); - redraw(); - } - - public void onFinishOpenJar(String jarName) { - // update gui - m_frame.setTitle(Constants.Name + " - " + jarName); - m_classesPanel.removeAll(); - m_classesPanel.add(m_splitClasses); - setSource(null); - - // update menu - m_closeJarMenu.setEnabled(true); - m_openMappingsMenu.setEnabled(true); - m_saveMappingsMenu.setEnabled(false); - m_saveMappingsAsMenu.setEnabled(true); - m_closeMappingsMenu.setEnabled(true); - m_exportSourceMenu.setEnabled(true); - m_exportJarMenu.setEnabled(true); - - redraw(); - } - - public void onCloseJar() { - // update gui - m_frame.setTitle(Constants.Name); - setObfClasses(null); - setDeobfClasses(null); - setSource(null); - m_classesPanel.removeAll(); - - // update menu - m_closeJarMenu.setEnabled(false); - m_openMappingsMenu.setEnabled(false); - m_saveMappingsMenu.setEnabled(false); - m_saveMappingsAsMenu.setEnabled(false); - m_closeMappingsMenu.setEnabled(false); - m_exportSourceMenu.setEnabled(false); - m_exportJarMenu.setEnabled(false); - - redraw(); - } - - public void setObfClasses(Collection obfClasses) { - m_obfClasses.setClasses(obfClasses); - } - - public void setDeobfClasses(Collection deobfClasses) { - m_deobfClasses.setClasses(deobfClasses); - } - - public void setMappingsFile(File file) { - m_mappingsFileChooser.setSelectedFile(file); - m_saveMappingsMenu.setEnabled(file != null); - } - - public void setSource(String source) { - m_editor.getHighlighter().removeAllHighlights(); - m_editor.setText(source); - } - - public void showToken(final Token token) { - if (token == null) { - throw new IllegalArgumentException("Token cannot be null!"); - } - CodeReader.navigateToToken(m_editor, token, m_selectionHighlightPainter); - redraw(); - } - - public void showTokens(Collection tokens) { - Vector sortedTokens = new Vector(tokens); - Collections.sort(sortedTokens); - if (sortedTokens.size() > 1) { - // sort the tokens and update the tokens panel - m_tokens.setListData(sortedTokens); - m_tokens.setSelectedIndex(0); - } else { - m_tokens.setListData(new Vector()); - } - - // show the first token - showToken(sortedTokens.get(0)); - } - - public void setHighlightedTokens(Iterable obfuscatedTokens, Iterable deobfuscatedTokens, Iterable otherTokens) { - - // remove any old highlighters - m_editor.getHighlighter().removeAllHighlights(); - - // color things based on the index - if (obfuscatedTokens != null) { - setHighlightedTokens(obfuscatedTokens, m_obfuscatedHighlightPainter); - } - if (deobfuscatedTokens != null) { - setHighlightedTokens(deobfuscatedTokens, m_deobfuscatedHighlightPainter); - } - if (otherTokens != null) { - setHighlightedTokens(otherTokens, m_otherHighlightPainter); - } - - redraw(); - } - - private void setHighlightedTokens(Iterable tokens, Highlighter.HighlightPainter painter) { - for (Token token : tokens) { - try { - m_editor.getHighlighter().addHighlight(token.start, token.end, painter); - } catch (BadLocationException ex) { - throw new IllegalArgumentException(ex); - } - } - } - - private void clearReference() { - m_infoPanel.removeAll(); - JLabel label = new JLabel("No identifier selected"); - GuiTricks.unboldLabel(label); - label.setHorizontalAlignment(JLabel.CENTER); - m_infoPanel.add(label); - - redraw(); - } - - private void showReference(EntryReference reference) { - if (reference == null) { - clearReference(); - return; - } - - m_reference = reference; - - m_infoPanel.removeAll(); - if (reference.entry instanceof ClassEntry) { - showClassEntry((ClassEntry)m_reference.entry); - } else if (m_reference.entry instanceof FieldEntry) { - showFieldEntry((FieldEntry)m_reference.entry); - } else if (m_reference.entry instanceof MethodEntry) { - showMethodEntry((MethodEntry)m_reference.entry); - } else if (m_reference.entry instanceof ConstructorEntry) { - showConstructorEntry((ConstructorEntry)m_reference.entry); - } else if (m_reference.entry instanceof ArgumentEntry) { - showArgumentEntry((ArgumentEntry)m_reference.entry); - } else { - throw new Error("Unknown entry type: " + m_reference.entry.getClass().getName()); - } - - redraw(); - } - - private void showClassEntry(ClassEntry entry) { - addNameValue(m_infoPanel, "Class", entry.getName()); - } - - private void showFieldEntry(FieldEntry entry) { - addNameValue(m_infoPanel, "Field", entry.getName()); - addNameValue(m_infoPanel, "Class", entry.getClassEntry().getName()); - addNameValue(m_infoPanel, "Type", entry.getType().toString()); - } - - private void showMethodEntry(MethodEntry entry) { - addNameValue(m_infoPanel, "Method", entry.getName()); - addNameValue(m_infoPanel, "Class", entry.getClassEntry().getName()); - addNameValue(m_infoPanel, "Signature", entry.getSignature().toString()); - } - - private void showConstructorEntry(ConstructorEntry entry) { - addNameValue(m_infoPanel, "Constructor", entry.getClassEntry().getName()); - if (!entry.isStatic()) { - addNameValue(m_infoPanel, "Signature", entry.getSignature().toString()); - } - } - - private void showArgumentEntry(ArgumentEntry entry) { - addNameValue(m_infoPanel, "Argument", entry.getName()); - addNameValue(m_infoPanel, "Class", entry.getClassEntry().getName()); - addNameValue(m_infoPanel, "Method", entry.getBehaviorEntry().getName()); - addNameValue(m_infoPanel, "Index", Integer.toString(entry.getIndex())); - } - - private void addNameValue(JPanel container, String name, String value) { - JPanel panel = new JPanel(); - panel.setLayout(new FlowLayout(FlowLayout.LEFT, 6, 0)); - container.add(panel); - - JLabel label = new JLabel(name + ":", JLabel.RIGHT); - label.setPreferredSize(new Dimension(100, label.getPreferredSize().height)); - panel.add(label); - - panel.add(GuiTricks.unboldLabel(new JLabel(value, JLabel.LEFT))); - } - - private void onCaretMove(int pos) { - - Token token = m_controller.getToken(pos); - boolean isToken = token != null; - - m_reference = m_controller.getDeobfReference(token); - boolean isClassEntry = isToken && m_reference.entry instanceof ClassEntry; - boolean isFieldEntry = isToken && m_reference.entry instanceof FieldEntry; - boolean isMethodEntry = isToken && m_reference.entry instanceof MethodEntry; - boolean isConstructorEntry = isToken && m_reference.entry instanceof ConstructorEntry; - boolean isInJar = isToken && m_controller.entryIsInJar(m_reference.entry); - boolean isRenameable = isToken && m_controller.referenceIsRenameable(m_reference); - - if (isToken) { - showReference(m_reference); - } else { - clearReference(); - } - - m_renameMenu.setEnabled(isRenameable && isToken); - m_showInheritanceMenu.setEnabled(isClassEntry || isMethodEntry || isConstructorEntry); - m_showImplementationsMenu.setEnabled(isClassEntry || isMethodEntry); - m_showCallsMenu.setEnabled(isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry); - m_openEntryMenu.setEnabled(isInJar && (isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry)); - m_openPreviousMenu.setEnabled(m_controller.hasPreviousLocation()); - m_toggleMappingMenu.setEnabled(isRenameable && isToken); - - if (isToken && m_controller.entryHasDeobfuscatedName(m_reference.entry)) { - m_toggleMappingMenu.setText("Reset to obfuscated"); - } else { - m_toggleMappingMenu.setText("Mark as deobfuscated"); - } - } - - private void navigateTo(Entry entry) { - if (!m_controller.entryIsInJar(entry)) { - // entry is not in the jar. Ignore it - return; - } - if (m_reference != null) { - m_controller.savePreviousReference(m_reference); - } - m_controller.openDeclaration(entry); - } - - private void navigateTo(EntryReference reference) { - if (!m_controller.entryIsInJar(reference.getLocationClassEntry())) { - // reference is not in the jar. Ignore it - return; - } - if (m_reference != null) { - m_controller.savePreviousReference(m_reference); - } - m_controller.openReference(reference); - } - - private void startRename() { - - // init the text box - final JTextField text = new JTextField(); - text.setText(m_reference.getNamableName()); - text.setPreferredSize(new Dimension(360, text.getPreferredSize().height)); - text.addKeyListener(new KeyAdapter() { - @Override - public void keyPressed(KeyEvent event) { - switch (event.getKeyCode()) { - case KeyEvent.VK_ENTER: - finishRename(text, true); - break; - - case KeyEvent.VK_ESCAPE: - finishRename(text, false); - break; - } - } - }); - - // find the label with the name and replace it with the text box - JPanel panel = (JPanel)m_infoPanel.getComponent(0); - panel.remove(panel.getComponentCount() - 1); - panel.add(text); - text.grabFocus(); - text.selectAll(); - - redraw(); - } - - private void finishRename(JTextField text, boolean saveName) { - String newName = text.getText(); - if (saveName && newName != null && newName.length() > 0) { - try { - m_controller.rename(m_reference, newName); - } catch (IllegalNameException ex) { - text.setBorder(BorderFactory.createLineBorder(Color.red, 1)); - text.setToolTipText(ex.getReason()); - GuiTricks.showToolTipNow(text); - } - return; - } - - // abort the rename - JPanel panel = (JPanel)m_infoPanel.getComponent(0); - panel.remove(panel.getComponentCount() - 1); - panel.add(GuiTricks.unboldLabel(new JLabel(m_reference.getNamableName(), JLabel.LEFT))); - - m_editor.grabFocus(); - - redraw(); - } - - private void showInheritance() { - - if (m_reference == null) { - return; - } - - m_inheritanceTree.setModel(null); - - if (m_reference.entry instanceof ClassEntry) { - // get the class inheritance - ClassInheritanceTreeNode classNode = m_controller.getClassInheritance((ClassEntry)m_reference.entry); - - // show the tree at the root - TreePath path = getPathToRoot(classNode); - m_inheritanceTree.setModel(new DefaultTreeModel((TreeNode)path.getPathComponent(0))); - m_inheritanceTree.expandPath(path); - m_inheritanceTree.setSelectionRow(m_inheritanceTree.getRowForPath(path)); - } else if (m_reference.entry instanceof MethodEntry) { - // get the method inheritance - MethodInheritanceTreeNode classNode = m_controller.getMethodInheritance((MethodEntry)m_reference.entry); - - // show the tree at the root - TreePath path = getPathToRoot(classNode); - m_inheritanceTree.setModel(new DefaultTreeModel((TreeNode)path.getPathComponent(0))); - m_inheritanceTree.expandPath(path); - m_inheritanceTree.setSelectionRow(m_inheritanceTree.getRowForPath(path)); - } - - m_tabs.setSelectedIndex(0); - redraw(); - } - - private void showImplementations() { - - if (m_reference == null) { - return; - } - - m_implementationsTree.setModel(null); - - if (m_reference.entry instanceof ClassEntry) { - // get the class implementations - ClassImplementationsTreeNode node = m_controller.getClassImplementations((ClassEntry)m_reference.entry); - if (node != null) { - // show the tree at the root - TreePath path = getPathToRoot(node); - m_implementationsTree.setModel(new DefaultTreeModel((TreeNode)path.getPathComponent(0))); - m_implementationsTree.expandPath(path); - m_implementationsTree.setSelectionRow(m_implementationsTree.getRowForPath(path)); - } - } else if (m_reference.entry instanceof MethodEntry) { - // get the method implementations - MethodImplementationsTreeNode node = m_controller.getMethodImplementations((MethodEntry)m_reference.entry); - if (node != null) { - // show the tree at the root - TreePath path = getPathToRoot(node); - m_implementationsTree.setModel(new DefaultTreeModel((TreeNode)path.getPathComponent(0))); - m_implementationsTree.expandPath(path); - m_implementationsTree.setSelectionRow(m_implementationsTree.getRowForPath(path)); - } - } - - m_tabs.setSelectedIndex(1); - redraw(); - } - - private void showCalls() { - - if (m_reference == null) { - return; - } - - if (m_reference.entry instanceof ClassEntry) { - // look for calls to the default constructor - // TODO: get a list of all the constructors and find calls to all of them - BehaviorReferenceTreeNode node = m_controller.getMethodReferences(new ConstructorEntry((ClassEntry)m_reference.entry, new Signature("()V"))); - m_callsTree.setModel(new DefaultTreeModel(node)); - } else if (m_reference.entry instanceof FieldEntry) { - FieldReferenceTreeNode node = m_controller.getFieldReferences((FieldEntry)m_reference.entry); - m_callsTree.setModel(new DefaultTreeModel(node)); - } else if (m_reference.entry instanceof MethodEntry) { - BehaviorReferenceTreeNode node = m_controller.getMethodReferences((MethodEntry)m_reference.entry); - m_callsTree.setModel(new DefaultTreeModel(node)); - } else if (m_reference.entry instanceof ConstructorEntry) { - BehaviorReferenceTreeNode node = m_controller.getMethodReferences((ConstructorEntry)m_reference.entry); - m_callsTree.setModel(new DefaultTreeModel(node)); - } - - m_tabs.setSelectedIndex(2); - redraw(); - } - - private void toggleMapping() { - if (m_controller.entryHasDeobfuscatedName(m_reference.entry)) { - m_controller.removeMapping(m_reference); - } else { - m_controller.markAsDeobfuscated(m_reference); - } - } - - private TreePath getPathToRoot(TreeNode node) { - List nodes = Lists.newArrayList(); - TreeNode n = node; - do { - nodes.add(n); - n = n.getParent(); - } while (n != null); - Collections.reverse(nodes); - return new TreePath(nodes.toArray()); - } - - private void close() { - if (!m_controller.isDirty()) { - // everything is saved, we can exit safely - m_frame.dispose(); - } else { - // ask to save before closing - String[] options = { "Save and exit", "Discard changes", "Cancel" }; - int response = JOptionPane.showOptionDialog(m_frame, "Your mappings have not been saved yet. Do you want to save?", "Save your changes?", JOptionPane.YES_NO_CANCEL_OPTION, - JOptionPane.QUESTION_MESSAGE, null, options, options[2]); - switch (response) { - case JOptionPane.YES_OPTION: // save and exit - if (m_mappingsFileChooser.getSelectedFile() != null || m_mappingsFileChooser.showSaveDialog(m_frame) == JFileChooser.APPROVE_OPTION) { - try { - m_controller.saveMappings(m_mappingsFileChooser.getSelectedFile()); - m_frame.dispose(); - } catch (IOException ex) { - throw new Error(ex); - } - } - break; - - case JOptionPane.NO_OPTION: - // don't save, exit - m_frame.dispose(); - break; - - // cancel means do nothing - } - } - } - - private void redraw() { - m_frame.validate(); - m_frame.repaint(); - } -} diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java deleted file mode 100644 index 66906227..00000000 --- a/src/cuchaz/enigma/gui/GuiController.java +++ /dev/null @@ -1,358 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.util.Collection; -import java.util.Deque; -import java.util.List; -import java.util.jar.JarFile; - -import com.google.common.collect.Lists; -import com.google.common.collect.Queues; -import com.strobel.decompiler.languages.java.ast.CompilationUnit; - -import cuchaz.enigma.Deobfuscator; -import cuchaz.enigma.Deobfuscator.ProgressListener; -import cuchaz.enigma.analysis.BehaviorReferenceTreeNode; -import cuchaz.enigma.analysis.ClassImplementationsTreeNode; -import cuchaz.enigma.analysis.ClassInheritanceTreeNode; -import cuchaz.enigma.analysis.EntryReference; -import cuchaz.enigma.analysis.FieldReferenceTreeNode; -import cuchaz.enigma.analysis.MethodImplementationsTreeNode; -import cuchaz.enigma.analysis.MethodInheritanceTreeNode; -import cuchaz.enigma.analysis.SourceIndex; -import cuchaz.enigma.analysis.Token; -import cuchaz.enigma.gui.ProgressDialog.ProgressRunnable; -import cuchaz.enigma.mapping.BehaviorEntry; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.Entry; -import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.MappingParseException; -import cuchaz.enigma.mapping.MappingsReader; -import cuchaz.enigma.mapping.MappingsWriter; -import cuchaz.enigma.mapping.MethodEntry; -import cuchaz.enigma.mapping.TranslationDirection; - -public class GuiController { - - private Deobfuscator m_deobfuscator; - private Gui m_gui; - private SourceIndex m_index; - private ClassEntry m_currentObfClass; - private boolean m_isDirty; - private Deque> m_referenceStack; - - public GuiController(Gui gui) { - m_gui = gui; - m_deobfuscator = null; - m_index = null; - m_currentObfClass = null; - m_isDirty = false; - m_referenceStack = Queues.newArrayDeque(); - } - - public boolean isDirty() { - return m_isDirty; - } - - public void openJar(final JarFile jar) throws IOException { - m_gui.onStartOpenJar(); - m_deobfuscator = new Deobfuscator(jar); - m_gui.onFinishOpenJar(m_deobfuscator.getJarName()); - refreshClasses(); - } - - public void closeJar() { - m_deobfuscator = null; - m_gui.onCloseJar(); - } - - public void openMappings(File file) throws IOException, MappingParseException { - FileReader in = new FileReader(file); - m_deobfuscator.setMappings(new MappingsReader().read(in)); - in.close(); - m_isDirty = false; - m_gui.setMappingsFile(file); - refreshClasses(); - refreshCurrentClass(); - } - - public void saveMappings(File file) throws IOException { - FileWriter out = new FileWriter(file); - new MappingsWriter().write(out, m_deobfuscator.getMappings()); - out.close(); - m_isDirty = false; - } - - public void closeMappings() { - m_deobfuscator.setMappings(null); - m_gui.setMappingsFile(null); - refreshClasses(); - refreshCurrentClass(); - } - - public void exportSource(final File dirOut) { - ProgressDialog.runInThread(m_gui.getFrame(), new ProgressRunnable() { - @Override - public void run(ProgressListener progress) throws Exception { - m_deobfuscator.writeSources(dirOut, progress); - } - }); - } - - public void exportJar(final File fileOut) { - ProgressDialog.runInThread(m_gui.getFrame(), new ProgressRunnable() { - @Override - public void run(ProgressListener progress) { - m_deobfuscator.writeJar(fileOut, progress); - } - }); - } - - public Token getToken(int pos) { - if (m_index == null) { - return null; - } - return m_index.getReferenceToken(pos); - } - - public EntryReference getDeobfReference(Token token) { - if (m_index == null) { - return null; - } - return m_index.getDeobfReference(token); - } - - public ReadableToken getReadableToken(Token token) { - if (m_index == null) { - return null; - } - return new ReadableToken( - m_index.getLineNumber(token.start), - m_index.getColumnNumber(token.start), - m_index.getColumnNumber(token.end) - ); - } - - public boolean entryHasDeobfuscatedName(Entry deobfEntry) { - return m_deobfuscator.hasDeobfuscatedName(m_deobfuscator.obfuscateEntry(deobfEntry)); - } - - public boolean entryIsInJar(Entry deobfEntry) { - return m_deobfuscator.isObfuscatedIdentifier(m_deobfuscator.obfuscateEntry(deobfEntry)); - } - - public boolean referenceIsRenameable(EntryReference deobfReference) { - return m_deobfuscator.isRenameable(m_deobfuscator.obfuscateReference(deobfReference)); - } - - public ClassInheritanceTreeNode getClassInheritance(ClassEntry deobfClassEntry) { - ClassEntry obfClassEntry = m_deobfuscator.obfuscateEntry(deobfClassEntry); - ClassInheritanceTreeNode rootNode = m_deobfuscator.getJarIndex().getClassInheritance( - m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating), - obfClassEntry - ); - return ClassInheritanceTreeNode.findNode(rootNode, obfClassEntry); - } - - public ClassImplementationsTreeNode getClassImplementations(ClassEntry deobfClassEntry) { - ClassEntry obfClassEntry = m_deobfuscator.obfuscateEntry(deobfClassEntry); - return m_deobfuscator.getJarIndex().getClassImplementations( - m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating), - obfClassEntry - ); - } - - public MethodInheritanceTreeNode getMethodInheritance(MethodEntry deobfMethodEntry) { - MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry(deobfMethodEntry); - MethodInheritanceTreeNode rootNode = m_deobfuscator.getJarIndex().getMethodInheritance( - m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating), - obfMethodEntry - ); - return MethodInheritanceTreeNode.findNode(rootNode, obfMethodEntry); - } - - public MethodImplementationsTreeNode getMethodImplementations(MethodEntry deobfMethodEntry) { - MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry(deobfMethodEntry); - List rootNodes = m_deobfuscator.getJarIndex().getMethodImplementations( - m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating), - obfMethodEntry - ); - if (rootNodes.isEmpty()) { - return null; - } - if (rootNodes.size() > 1) { - System.err.println("WARNING: Method " + deobfMethodEntry + " implements multiple interfaces. Only showing first one."); - } - return MethodImplementationsTreeNode.findNode(rootNodes.get(0), obfMethodEntry); - } - - public FieldReferenceTreeNode getFieldReferences(FieldEntry deobfFieldEntry) { - FieldEntry obfFieldEntry = m_deobfuscator.obfuscateEntry(deobfFieldEntry); - FieldReferenceTreeNode rootNode = new FieldReferenceTreeNode( - m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating), - obfFieldEntry - ); - rootNode.load(m_deobfuscator.getJarIndex(), true); - return rootNode; - } - - public BehaviorReferenceTreeNode getMethodReferences(BehaviorEntry deobfBehaviorEntry) { - BehaviorEntry obfBehaviorEntry = m_deobfuscator.obfuscateEntry(deobfBehaviorEntry); - BehaviorReferenceTreeNode rootNode = new BehaviorReferenceTreeNode( - m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating), - obfBehaviorEntry - ); - rootNode.load(m_deobfuscator.getJarIndex(), true); - return rootNode; - } - - public void rename(EntryReference deobfReference, String newName) { - EntryReference obfReference = m_deobfuscator.obfuscateReference(deobfReference); - m_deobfuscator.rename(obfReference.getNameableEntry(), newName); - m_isDirty = true; - refreshClasses(); - refreshCurrentClass(obfReference); - } - - public void removeMapping(EntryReference deobfReference) { - EntryReference obfReference = m_deobfuscator.obfuscateReference(deobfReference); - m_deobfuscator.removeMapping(obfReference.getNameableEntry()); - m_isDirty = true; - refreshClasses(); - refreshCurrentClass(obfReference); - } - - public void markAsDeobfuscated(EntryReference deobfReference) { - EntryReference obfReference = m_deobfuscator.obfuscateReference(deobfReference); - m_deobfuscator.markAsDeobfuscated(obfReference.getNameableEntry()); - m_isDirty = true; - refreshClasses(); - refreshCurrentClass(obfReference); - } - - public void openDeclaration(Entry deobfEntry) { - if (deobfEntry == null) { - throw new IllegalArgumentException("Entry cannot be null!"); - } - openReference(new EntryReference(deobfEntry, deobfEntry.getName())); - } - - public void openReference(EntryReference deobfReference) { - if (deobfReference == null) { - throw new IllegalArgumentException("Reference cannot be null!"); - } - - // get the reference target class - EntryReference obfReference = m_deobfuscator.obfuscateReference(deobfReference); - ClassEntry obfClassEntry = obfReference.getLocationClassEntry().getOutermostClassEntry(); - if (!m_deobfuscator.isObfuscatedIdentifier(obfClassEntry)) { - throw new IllegalArgumentException("Obfuscated class " + obfClassEntry + " was not found in the jar!"); - } - if (m_currentObfClass == null || !m_currentObfClass.equals(obfClassEntry)) { - // deobfuscate the class, then navigate to the reference - m_currentObfClass = obfClassEntry; - deobfuscate(m_currentObfClass, obfReference); - } else { - showReference(obfReference); - } - } - - private void showReference(EntryReference obfReference) { - EntryReference deobfReference = m_deobfuscator.deobfuscateReference(obfReference); - Collection tokens = m_index.getReferenceTokens(deobfReference); - if (tokens.isEmpty()) { - // DEBUG - System.err.println(String.format("WARNING: no tokens found for %s in %s", deobfReference, m_currentObfClass)); - } else { - m_gui.showTokens(tokens); - } - } - - public void savePreviousReference(EntryReference deobfReference) { - m_referenceStack.push(m_deobfuscator.obfuscateReference(deobfReference)); - } - - public void openPreviousReference() { - if (hasPreviousLocation()) { - openReference(m_deobfuscator.deobfuscateReference(m_referenceStack.pop())); - } - } - - public boolean hasPreviousLocation() { - return !m_referenceStack.isEmpty(); - } - - private void refreshClasses() { - List obfClasses = Lists.newArrayList(); - List deobfClasses = Lists.newArrayList(); - m_deobfuscator.getSeparatedClasses(obfClasses, deobfClasses); - m_gui.setObfClasses(obfClasses); - m_gui.setDeobfClasses(deobfClasses); - } - - private void refreshCurrentClass() { - refreshCurrentClass(null); - } - - private void refreshCurrentClass(EntryReference obfReference) { - if (m_currentObfClass != null) { - deobfuscate(m_currentObfClass, obfReference); - } - } - - private void deobfuscate(final ClassEntry classEntry, final EntryReference obfReference) { - - m_gui.setSource("(deobfuscating...)"); - - // run the deobfuscator in a separate thread so we don't block the GUI event queue - new Thread() { - @Override - public void run() { - // decompile,deobfuscate the bytecode - CompilationUnit sourceTree = m_deobfuscator.getSourceTree(classEntry.getClassName()); - if (sourceTree == null) { - // decompilation of this class is not supported - m_gui.setSource("Unable to find class: " + classEntry); - return; - } - String source = m_deobfuscator.getSource(sourceTree); - m_index = m_deobfuscator.getSourceIndex(sourceTree, source); - m_gui.setSource(m_index.getSource()); - if (obfReference != null) { - showReference(obfReference); - } - - // set the highlighted tokens - List obfuscatedTokens = Lists.newArrayList(); - List deobfuscatedTokens = Lists.newArrayList(); - List otherTokens = Lists.newArrayList(); - for (Token token : m_index.referenceTokens()) { - EntryReference reference = m_index.getDeobfReference(token); - if (referenceIsRenameable(reference)) { - if (entryHasDeobfuscatedName(reference.getNameableEntry())) { - deobfuscatedTokens.add(token); - } else { - obfuscatedTokens.add(token); - } - } else { - otherTokens.add(token); - } - } - m_gui.setHighlightedTokens(obfuscatedTokens, deobfuscatedTokens, otherTokens); - } - }.start(); - } -} diff --git a/src/cuchaz/enigma/gui/GuiTricks.java b/src/cuchaz/enigma/gui/GuiTricks.java deleted file mode 100644 index 5dc3ffb3..00000000 --- a/src/cuchaz/enigma/gui/GuiTricks.java +++ /dev/null @@ -1,56 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import java.awt.Font; -import java.awt.event.ActionListener; -import java.awt.event.MouseEvent; -import java.util.Arrays; - -import javax.swing.JButton; -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.ToolTipManager; - -public class GuiTricks { - - public static JLabel unboldLabel(JLabel label) { - Font font = label.getFont(); - label.setFont(font.deriveFont(font.getStyle() & ~Font.BOLD)); - return label; - } - - public static void showToolTipNow(JComponent component) { - // HACKHACK: trick the tooltip manager into showing the tooltip right now - ToolTipManager manager = ToolTipManager.sharedInstance(); - int oldDelay = manager.getInitialDelay(); - manager.setInitialDelay(0); - manager.mouseMoved(new MouseEvent(component, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, 0, 0, 0, false)); - manager.setInitialDelay(oldDelay); - } - - public static void deactivateButton(JButton button) { - button.setEnabled(false); - button.setText(""); - for (ActionListener listener : Arrays.asList(button.getActionListeners())) { - button.removeActionListener(listener); - } - } - - public static void activateButton(JButton button, String text, ActionListener newListener) { - button.setText(text); - button.setEnabled(true); - for (ActionListener listener : Arrays.asList(button.getActionListeners())) { - button.removeActionListener(listener); - } - button.addActionListener(newListener); - } -} diff --git a/src/cuchaz/enigma/gui/MemberMatchingGui.java b/src/cuchaz/enigma/gui/MemberMatchingGui.java deleted file mode 100644 index 150eaadb..00000000 --- a/src/cuchaz/enigma/gui/MemberMatchingGui.java +++ /dev/null @@ -1,499 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import java.awt.BorderLayout; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -import javax.swing.BoxLayout; -import javax.swing.ButtonGroup; -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JRadioButton; -import javax.swing.JScrollPane; -import javax.swing.JSplitPane; -import javax.swing.WindowConstants; -import javax.swing.text.Highlighter.HighlightPainter; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - -import cuchaz.enigma.Constants; -import cuchaz.enigma.Deobfuscator; -import cuchaz.enigma.analysis.EntryReference; -import cuchaz.enigma.analysis.SourceIndex; -import cuchaz.enigma.analysis.Token; -import cuchaz.enigma.convert.ClassMatches; -import cuchaz.enigma.convert.MemberMatches; -import cuchaz.enigma.gui.ClassSelector.ClassSelectionListener; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.Entry; -import de.sciss.syntaxpane.DefaultSyntaxKit; - - -public class MemberMatchingGui { - - private static enum SourceType { - Matched { - - @Override - public Collection getObfSourceClasses(MemberMatches matches) { - return matches.getSourceClassesWithoutUnmatchedEntries(); - } - }, - Unmatched { - - @Override - public Collection getObfSourceClasses(MemberMatches matches) { - return matches.getSourceClassesWithUnmatchedEntries(); - } - }; - - public JRadioButton newRadio(ActionListener listener, ButtonGroup group) { - JRadioButton button = new JRadioButton(name(), this == getDefault()); - button.setActionCommand(name()); - button.addActionListener(listener); - group.add(button); - return button; - } - - public abstract Collection getObfSourceClasses(MemberMatches matches); - - public static SourceType getDefault() { - return values()[0]; - } - } - - public static interface SaveListener { - public void save(MemberMatches matches); - } - - // controls - private JFrame m_frame; - private Map m_sourceTypeButtons; - private ClassSelector m_sourceClasses; - private CodeReader m_sourceReader; - private CodeReader m_destReader; - private JButton m_matchButton; - private JButton m_unmatchableButton; - private JLabel m_sourceLabel; - private JLabel m_destLabel; - private HighlightPainter m_unmatchedHighlightPainter; - private HighlightPainter m_matchedHighlightPainter; - - private ClassMatches m_classMatches; - private MemberMatches m_memberMatches; - private Deobfuscator m_sourceDeobfuscator; - private Deobfuscator m_destDeobfuscator; - private SaveListener m_saveListener; - private SourceType m_sourceType; - private ClassEntry m_obfSourceClass; - private ClassEntry m_obfDestClass; - private T m_obfSourceEntry; - private T m_obfDestEntry; - - public MemberMatchingGui(ClassMatches classMatches, MemberMatches fieldMatches, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) { - - m_classMatches = classMatches; - m_memberMatches = fieldMatches; - m_sourceDeobfuscator = sourceDeobfuscator; - m_destDeobfuscator = destDeobfuscator; - - // init frame - m_frame = new JFrame(Constants.Name + " - Member Matcher"); - final Container pane = m_frame.getContentPane(); - pane.setLayout(new BorderLayout()); - - // init classes side - JPanel classesPanel = new JPanel(); - classesPanel.setLayout(new BoxLayout(classesPanel, BoxLayout.PAGE_AXIS)); - classesPanel.setPreferredSize(new Dimension(200, 0)); - pane.add(classesPanel, BorderLayout.WEST); - classesPanel.add(new JLabel("Classes")); - - // init source type radios - JPanel sourceTypePanel = new JPanel(); - classesPanel.add(sourceTypePanel); - sourceTypePanel.setLayout(new BoxLayout(sourceTypePanel, BoxLayout.PAGE_AXIS)); - ActionListener sourceTypeListener = new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - setSourceType(SourceType.valueOf(event.getActionCommand())); - } - }; - ButtonGroup sourceTypeButtons = new ButtonGroup(); - m_sourceTypeButtons = Maps.newHashMap(); - for (SourceType sourceType : SourceType.values()) { - JRadioButton button = sourceType.newRadio(sourceTypeListener, sourceTypeButtons); - m_sourceTypeButtons.put(sourceType, button); - sourceTypePanel.add(button); - } - - m_sourceClasses = new ClassSelector(ClassSelector.DeobfuscatedClassEntryComparator); - m_sourceClasses.setListener(new ClassSelectionListener() { - @Override - public void onSelectClass(ClassEntry classEntry) { - setSourceClass(classEntry); - } - }); - JScrollPane sourceScroller = new JScrollPane(m_sourceClasses); - classesPanel.add(sourceScroller); - - // init readers - DefaultSyntaxKit.initKit(); - m_sourceReader = new CodeReader(); - m_sourceReader.setSelectionListener(new CodeReader.SelectionListener() { - @Override - public void onSelect(EntryReference reference) { - if (reference != null) { - onSelectSource(reference.entry); - } else { - onSelectSource(null); - } - } - }); - m_destReader = new CodeReader(); - m_destReader.setSelectionListener(new CodeReader.SelectionListener() { - @Override - public void onSelect(EntryReference reference) { - if (reference != null) { - onSelectDest(reference.entry); - } else { - onSelectDest(null); - } - } - }); - - // add key bindings - KeyAdapter keyListener = new KeyAdapter() { - @Override - public void keyPressed(KeyEvent event) { - switch (event.getKeyCode()) { - case KeyEvent.VK_M: - m_matchButton.doClick(); - break; - } - } - }; - m_sourceReader.addKeyListener(keyListener); - m_destReader.addKeyListener(keyListener); - - // init all the splits - JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, new JScrollPane(m_sourceReader), new JScrollPane(m_destReader)); - splitRight.setResizeWeight(0.5); // resize 50:50 - JSplitPane splitLeft = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, classesPanel, splitRight); - splitLeft.setResizeWeight(0); // let the right side take all the slack - pane.add(splitLeft, BorderLayout.CENTER); - splitLeft.resetToPreferredSizes(); - - // init bottom panel - JPanel bottomPanel = new JPanel(); - bottomPanel.setLayout(new FlowLayout()); - pane.add(bottomPanel, BorderLayout.SOUTH); - - m_matchButton = new JButton(); - m_unmatchableButton = new JButton(); - - m_sourceLabel = new JLabel(); - bottomPanel.add(m_sourceLabel); - bottomPanel.add(m_matchButton); - bottomPanel.add(m_unmatchableButton); - m_destLabel = new JLabel(); - bottomPanel.add(m_destLabel); - - // show the frame - pane.doLayout(); - m_frame.setSize(1024, 576); - m_frame.setMinimumSize(new Dimension(640, 480)); - m_frame.setVisible(true); - m_frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - - m_unmatchedHighlightPainter = new ObfuscatedHighlightPainter(); - m_matchedHighlightPainter = new DeobfuscatedHighlightPainter(); - - // init state - m_saveListener = null; - m_obfSourceClass = null; - m_obfDestClass = null; - m_obfSourceEntry = null; - m_obfDestEntry = null; - setSourceType(SourceType.getDefault()); - updateButtons(); - } - - protected void setSourceType(SourceType val) { - m_sourceType = val; - updateSourceClasses(); - } - - public void setSaveListener(SaveListener val) { - m_saveListener = val; - } - - private void updateSourceClasses() { - - String selectedPackage = m_sourceClasses.getSelectedPackage(); - - List deobfClassEntries = Lists.newArrayList(); - for (ClassEntry entry : m_sourceType.getObfSourceClasses(m_memberMatches)) { - deobfClassEntries.add(m_sourceDeobfuscator.deobfuscateEntry(entry)); - } - m_sourceClasses.setClasses(deobfClassEntries); - - if (selectedPackage != null) { - m_sourceClasses.expandPackage(selectedPackage); - } - - for (SourceType sourceType : SourceType.values()) { - m_sourceTypeButtons.get(sourceType).setText(String.format("%s (%d)", - sourceType.name(), sourceType.getObfSourceClasses(m_memberMatches).size() - )); - } - } - - protected void setSourceClass(ClassEntry sourceClass) { - - m_obfSourceClass = m_sourceDeobfuscator.obfuscateEntry(sourceClass); - m_obfDestClass = m_classMatches.getUniqueMatches().get(m_obfSourceClass); - if (m_obfDestClass == null) { - throw new Error("No matching dest class for source class: " + m_obfSourceClass); - } - - m_sourceReader.decompileClass(m_obfSourceClass, m_sourceDeobfuscator, false, new Runnable() { - @Override - public void run() { - updateSourceHighlights(); - } - }); - m_destReader.decompileClass(m_obfDestClass, m_destDeobfuscator, false, new Runnable() { - @Override - public void run() { - updateDestHighlights(); - } - }); - } - - protected void updateSourceHighlights() { - highlightEntries(m_sourceReader, m_sourceDeobfuscator, m_memberMatches.matches().keySet(), m_memberMatches.getUnmatchedSourceEntries()); - } - - protected void updateDestHighlights() { - highlightEntries(m_destReader, m_destDeobfuscator, m_memberMatches.matches().values(), m_memberMatches.getUnmatchedDestEntries()); - } - - private void highlightEntries(CodeReader reader, Deobfuscator deobfuscator, Collection obfMatchedEntries, Collection obfUnmatchedEntries) { - reader.clearHighlights(); - SourceIndex index = reader.getSourceIndex(); - - // matched fields - for (T obfT : obfMatchedEntries) { - T deobfT = deobfuscator.deobfuscateEntry(obfT); - Token token = index.getDeclarationToken(deobfT); - if (token != null) { - reader.setHighlightedToken(token, m_matchedHighlightPainter); - } - } - - // unmatched fields - for (T obfT : obfUnmatchedEntries) { - T deobfT = deobfuscator.deobfuscateEntry(obfT); - Token token = index.getDeclarationToken(deobfT); - if (token != null) { - reader.setHighlightedToken(token, m_unmatchedHighlightPainter); - } - } - } - - private boolean isSelectionMatched() { - return m_obfSourceEntry != null && m_obfDestEntry != null - && m_memberMatches.isMatched(m_obfSourceEntry, m_obfDestEntry); - } - - protected void onSelectSource(Entry source) { - - // start with no selection - if (isSelectionMatched()) { - setDest(null); - } - setSource(null); - - // then look for a valid source selection - if (source != null) { - - // this looks really scary, but it's actually ok - // Deobfuscator.obfuscateEntry can handle all implementations of Entry - // and MemberMatches.hasSource() will only pass entries that actually match T - @SuppressWarnings("unchecked") - T sourceEntry = (T)source; - - T obfSourceEntry = m_sourceDeobfuscator.obfuscateEntry(sourceEntry); - if (m_memberMatches.hasSource(obfSourceEntry)) { - setSource(obfSourceEntry); - - // look for a matched dest too - T obfDestEntry = m_memberMatches.matches().get(obfSourceEntry); - if (obfDestEntry != null) { - setDest(obfDestEntry); - } - } - } - - updateButtons(); - } - - protected void onSelectDest(Entry dest) { - - // start with no selection - if (isSelectionMatched()) { - setSource(null); - } - setDest(null); - - // then look for a valid dest selection - if (dest != null) { - - // this looks really scary, but it's actually ok - // Deobfuscator.obfuscateEntry can handle all implementations of Entry - // and MemberMatches.hasSource() will only pass entries that actually match T - @SuppressWarnings("unchecked") - T destEntry = (T)dest; - - T obfDestEntry = m_destDeobfuscator.obfuscateEntry(destEntry); - if (m_memberMatches.hasDest(obfDestEntry)) { - setDest(obfDestEntry); - - // look for a matched source too - T obfSourceEntry = m_memberMatches.matches().inverse().get(obfDestEntry); - if (obfSourceEntry != null) { - setSource(obfSourceEntry); - } - } - } - - updateButtons(); - } - - private void setSource(T obfEntry) { - if (obfEntry == null) { - m_obfSourceEntry = obfEntry; - m_sourceLabel.setText(""); - } else { - m_obfSourceEntry = obfEntry; - m_sourceLabel.setText(getEntryLabel(obfEntry, m_sourceDeobfuscator)); - } - } - - private void setDest(T obfEntry) { - if (obfEntry == null) { - m_obfDestEntry = obfEntry; - m_destLabel.setText(""); - } else { - m_obfDestEntry = obfEntry; - m_destLabel.setText(getEntryLabel(obfEntry, m_destDeobfuscator)); - } - } - - private String getEntryLabel(T obfEntry, Deobfuscator deobfuscator) { - // show obfuscated and deobfuscated names, but no types/signatures - T deobfEntry = deobfuscator.deobfuscateEntry(obfEntry); - return String.format("%s (%s)", deobfEntry.getName(), obfEntry.getName()); - } - - private void updateButtons() { - - GuiTricks.deactivateButton(m_matchButton); - GuiTricks.deactivateButton(m_unmatchableButton); - - if (m_obfSourceEntry != null && m_obfDestEntry != null) { - if (m_memberMatches.isMatched(m_obfSourceEntry, m_obfDestEntry)) { - GuiTricks.activateButton(m_matchButton, "Unmatch", new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - unmatch(); - } - }); - } else if (!m_memberMatches.isMatchedSourceEntry(m_obfSourceEntry) && !m_memberMatches.isMatchedDestEntry(m_obfDestEntry)) { - GuiTricks.activateButton(m_matchButton, "Match", new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - match(); - } - }); - } - } else if (m_obfSourceEntry != null) { - GuiTricks.activateButton(m_unmatchableButton, "Set Unmatchable", new ActionListener() { - @Override - public void actionPerformed(ActionEvent event) { - unmatchable(); - } - }); - } - } - - protected void match() { - - // update the field matches - m_memberMatches.makeMatch(m_obfSourceEntry, m_obfDestEntry); - save(); - - // update the ui - onSelectSource(null); - onSelectDest(null); - updateSourceHighlights(); - updateDestHighlights(); - updateSourceClasses(); - } - - protected void unmatch() { - - // update the field matches - m_memberMatches.unmakeMatch(m_obfSourceEntry, m_obfDestEntry); - save(); - - // update the ui - onSelectSource(null); - onSelectDest(null); - updateSourceHighlights(); - updateDestHighlights(); - updateSourceClasses(); - } - - protected void unmatchable() { - - // update the field matches - m_memberMatches.makeSourceUnmatchable(m_obfSourceEntry); - save(); - - // update the ui - onSelectSource(null); - onSelectDest(null); - updateSourceHighlights(); - updateDestHighlights(); - updateSourceClasses(); - } - - private void save() { - if (m_saveListener != null) { - m_saveListener.save(m_memberMatches); - } - } -} diff --git a/src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java b/src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java deleted file mode 100644 index 4c3714a9..00000000 --- a/src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java +++ /dev/null @@ -1,21 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import java.awt.Color; - -public class ObfuscatedHighlightPainter extends BoxHighlightPainter { - - public ObfuscatedHighlightPainter() { - // red ish - super(new Color(255, 220, 220), new Color(160, 80, 80)); - } -} diff --git a/src/cuchaz/enigma/gui/OtherHighlightPainter.java b/src/cuchaz/enigma/gui/OtherHighlightPainter.java deleted file mode 100644 index 8d3fbe86..00000000 --- a/src/cuchaz/enigma/gui/OtherHighlightPainter.java +++ /dev/null @@ -1,21 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import java.awt.Color; - -public class OtherHighlightPainter extends BoxHighlightPainter { - - public OtherHighlightPainter() { - // grey - super(null, new Color(180, 180, 180)); - } -} diff --git a/src/cuchaz/enigma/gui/ProgressDialog.java b/src/cuchaz/enigma/gui/ProgressDialog.java deleted file mode 100644 index 1c20f10b..00000000 --- a/src/cuchaz/enigma/gui/ProgressDialog.java +++ /dev/null @@ -1,105 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import java.awt.BorderLayout; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.FlowLayout; - -import javax.swing.BorderFactory; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JProgressBar; -import javax.swing.WindowConstants; - -import cuchaz.enigma.Constants; -import cuchaz.enigma.Deobfuscator.ProgressListener; - -public class ProgressDialog implements ProgressListener, AutoCloseable { - - private JFrame m_frame; - private JLabel m_title; - private JLabel m_text; - private JProgressBar m_progress; - - public ProgressDialog(JFrame parent) { - - // init frame - m_frame = new JFrame(Constants.Name + " - Operation in progress"); - final Container pane = m_frame.getContentPane(); - FlowLayout layout = new FlowLayout(); - layout.setAlignment(FlowLayout.LEFT); - pane.setLayout(layout); - - m_title = new JLabel(); - pane.add(m_title); - - // set up the progress bar - JPanel panel = new JPanel(); - pane.add(panel); - panel.setLayout(new BorderLayout()); - m_text = GuiTricks.unboldLabel(new JLabel()); - m_progress = new JProgressBar(); - m_text.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0)); - panel.add(m_text, BorderLayout.NORTH); - panel.add(m_progress, BorderLayout.CENTER); - panel.setPreferredSize(new Dimension(360, 50)); - - // show the frame - pane.doLayout(); - m_frame.setSize(400, 120); - m_frame.setResizable(false); - m_frame.setLocationRelativeTo(parent); - m_frame.setVisible(true); - m_frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); - } - - public void close() { - m_frame.dispose(); - } - - @Override - public void init(int totalWork, String title) { - m_title.setText(title); - m_progress.setMinimum(0); - m_progress.setMaximum(totalWork); - m_progress.setValue(0); - } - - @Override - public void onProgress(int numDone, String message) { - m_text.setText(message); - m_progress.setValue(numDone); - - // update the frame - m_frame.validate(); - m_frame.repaint(); - } - - public static interface ProgressRunnable { - void run(ProgressListener listener) throws Exception; - } - - public static void runInThread(final JFrame parent, final ProgressRunnable runnable) { - new Thread() { - @Override - public void run() { - try (ProgressDialog progress = new ProgressDialog(parent)) { - runnable.run(progress); - } catch (Exception ex) { - throw new Error(ex); - } - } - }.start(); - } -} diff --git a/src/cuchaz/enigma/gui/ReadableToken.java b/src/cuchaz/enigma/gui/ReadableToken.java deleted file mode 100644 index 0741af39..00000000 --- a/src/cuchaz/enigma/gui/ReadableToken.java +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -public class ReadableToken { - - public int line; - public int startColumn; - public int endColumn; - - public ReadableToken(int line, int startColumn, int endColumn) { - this.line = line; - this.startColumn = startColumn; - this.endColumn = endColumn; - } - - @Override - public String toString() { - StringBuilder buf = new StringBuilder(); - buf.append("line "); - buf.append(line); - buf.append(" columns "); - buf.append(startColumn); - buf.append("-"); - buf.append(endColumn); - return buf.toString(); - } -} diff --git a/src/cuchaz/enigma/gui/RenameListener.java b/src/cuchaz/enigma/gui/RenameListener.java deleted file mode 100644 index 8b515bbd..00000000 --- a/src/cuchaz/enigma/gui/RenameListener.java +++ /dev/null @@ -1,17 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import cuchaz.enigma.mapping.Entry; - -public interface RenameListener { - void rename(Entry obfEntry, String newName); -} diff --git a/src/cuchaz/enigma/gui/ScoredClassEntry.java b/src/cuchaz/enigma/gui/ScoredClassEntry.java deleted file mode 100644 index 60704528..00000000 --- a/src/cuchaz/enigma/gui/ScoredClassEntry.java +++ /dev/null @@ -1,30 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import cuchaz.enigma.mapping.ClassEntry; - - -public class ScoredClassEntry extends ClassEntry { - - private static final long serialVersionUID = -8798725308554217105L; - - private float m_score; - - public ScoredClassEntry(ClassEntry other, float score) { - super(other); - m_score = score; - } - - public float getScore() { - return m_score; - } -} diff --git a/src/cuchaz/enigma/gui/SelectionHighlightPainter.java b/src/cuchaz/enigma/gui/SelectionHighlightPainter.java deleted file mode 100644 index 4165da4a..00000000 --- a/src/cuchaz/enigma/gui/SelectionHighlightPainter.java +++ /dev/null @@ -1,34 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.Shape; - -import javax.swing.text.Highlighter; -import javax.swing.text.JTextComponent; - -public class SelectionHighlightPainter implements Highlighter.HighlightPainter { - - @Override - public void paint(Graphics g, int start, int end, Shape shape, JTextComponent text) { - // draw a thick border - Graphics2D g2d = (Graphics2D)g; - Rectangle bounds = BoxHighlightPainter.getBounds(text, start, end); - g2d.setColor(Color.black); - g2d.setStroke(new BasicStroke(2.0f)); - g2d.drawRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4); - } -} diff --git a/src/cuchaz/enigma/gui/TokenListCellRenderer.java b/src/cuchaz/enigma/gui/TokenListCellRenderer.java deleted file mode 100644 index e4f7c873..00000000 --- a/src/cuchaz/enigma/gui/TokenListCellRenderer.java +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.gui; - -import java.awt.Component; - -import javax.swing.DefaultListCellRenderer; -import javax.swing.JLabel; -import javax.swing.JList; -import javax.swing.ListCellRenderer; - -import cuchaz.enigma.analysis.Token; - -public class TokenListCellRenderer implements ListCellRenderer { - - private GuiController m_controller; - private DefaultListCellRenderer m_defaultRenderer; - - public TokenListCellRenderer(GuiController controller) { - m_controller = controller; - m_defaultRenderer = new DefaultListCellRenderer(); - } - - @Override - public Component getListCellRendererComponent(JList list, Token token, int index, boolean isSelected, boolean hasFocus) { - JLabel label = (JLabel)m_defaultRenderer.getListCellRendererComponent(list, token, index, isSelected, hasFocus); - label.setText(m_controller.getReadableToken(token).toString()); - return label; - } -} diff --git a/src/cuchaz/enigma/mapping/ArgumentEntry.java b/src/cuchaz/enigma/mapping/ArgumentEntry.java deleted file mode 100644 index 9d99016e..00000000 --- a/src/cuchaz/enigma/mapping/ArgumentEntry.java +++ /dev/null @@ -1,116 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -import java.io.Serializable; - -import cuchaz.enigma.Util; - -public class ArgumentEntry implements Entry, Serializable { - - private static final long serialVersionUID = 4472172468162696006L; - - private BehaviorEntry m_behaviorEntry; - private int m_index; - private String m_name; - - public ArgumentEntry(BehaviorEntry behaviorEntry, int index, String name) { - if (behaviorEntry == null) { - throw new IllegalArgumentException("Behavior cannot be null!"); - } - if (index < 0) { - throw new IllegalArgumentException("Index must be non-negative!"); - } - if (name == null) { - throw new IllegalArgumentException("Argument name cannot be null!"); - } - - m_behaviorEntry = behaviorEntry; - m_index = index; - m_name = name; - } - - public ArgumentEntry(ArgumentEntry other) { - m_behaviorEntry = (BehaviorEntry)m_behaviorEntry.cloneToNewClass(getClassEntry()); - m_index = other.m_index; - m_name = other.m_name; - } - - public ArgumentEntry(ArgumentEntry other, String newClassName) { - m_behaviorEntry = (BehaviorEntry)other.m_behaviorEntry.cloneToNewClass(new ClassEntry(newClassName)); - m_index = other.m_index; - m_name = other.m_name; - } - - public BehaviorEntry getBehaviorEntry() { - return m_behaviorEntry; - } - - public int getIndex() { - return m_index; - } - - @Override - public String getName() { - return m_name; - } - - @Override - public ClassEntry getClassEntry() { - return m_behaviorEntry.getClassEntry(); - } - - @Override - public String getClassName() { - return m_behaviorEntry.getClassName(); - } - - @Override - public ArgumentEntry cloneToNewClass(ClassEntry classEntry) { - return new ArgumentEntry(this, classEntry.getName()); - } - - public String getMethodName() { - return m_behaviorEntry.getName(); - } - - public Signature getMethodSignature() { - return m_behaviorEntry.getSignature(); - } - - @Override - public int hashCode() { - return Util.combineHashesOrdered( - m_behaviorEntry, - Integer.valueOf(m_index).hashCode(), - m_name.hashCode() - ); - } - - @Override - public boolean equals(Object other) { - if (other instanceof ArgumentEntry) { - return equals((ArgumentEntry)other); - } - return false; - } - - public boolean equals(ArgumentEntry other) { - return m_behaviorEntry.equals(other.m_behaviorEntry) - && m_index == other.m_index - && m_name.equals(other.m_name); - } - - @Override - public String toString() { - return m_behaviorEntry.toString() + "(" + m_index + ":" + m_name + ")"; - } -} diff --git a/src/cuchaz/enigma/mapping/ArgumentMapping.java b/src/cuchaz/enigma/mapping/ArgumentMapping.java deleted file mode 100644 index a0055a63..00000000 --- a/src/cuchaz/enigma/mapping/ArgumentMapping.java +++ /dev/null @@ -1,49 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -import java.io.Serializable; - -public class ArgumentMapping implements Serializable, Comparable { - - private static final long serialVersionUID = 8610742471440861315L; - - private int m_index; - private String m_name; - - // NOTE: this argument order is important for the MethodReader/MethodWriter - public ArgumentMapping(int index, String name) { - m_index = index; - m_name = NameValidator.validateArgumentName(name); - } - - public ArgumentMapping(ArgumentMapping other) { - m_index = other.m_index; - m_name = other.m_name; - } - - public int getIndex() { - return m_index; - } - - public String getName() { - return m_name; - } - - public void setName(String val) { - m_name = NameValidator.validateArgumentName(val); - } - - @Override - public int compareTo(ArgumentMapping other) { - return Integer.compare(m_index, other.m_index); - } -} diff --git a/src/cuchaz/enigma/mapping/BehaviorEntry.java b/src/cuchaz/enigma/mapping/BehaviorEntry.java deleted file mode 100644 index 031d2670..00000000 --- a/src/cuchaz/enigma/mapping/BehaviorEntry.java +++ /dev/null @@ -1,15 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -public interface BehaviorEntry extends Entry { - Signature getSignature(); -} diff --git a/src/cuchaz/enigma/mapping/ClassEntry.java b/src/cuchaz/enigma/mapping/ClassEntry.java deleted file mode 100644 index 373203f0..00000000 --- a/src/cuchaz/enigma/mapping/ClassEntry.java +++ /dev/null @@ -1,172 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -import java.io.Serializable; -import java.util.List; - -import com.google.common.collect.Lists; - -public class ClassEntry implements Entry, Serializable { - - private static final long serialVersionUID = 4235460580973955811L; - - private String m_name; - - public ClassEntry(String className) { - if (className == null) { - throw new IllegalArgumentException("Class name cannot be null!"); - } - if (className.indexOf('.') >= 0) { - throw new IllegalArgumentException("Class name must be in JVM format. ie, path/to/package/class$inner : " + className); - } - - m_name = className; - - if (isInnerClass() && getInnermostClassName().indexOf('/') >= 0) { - throw new IllegalArgumentException("Inner class must not have a package: " + className); - } - } - - public ClassEntry(ClassEntry other) { - m_name = other.m_name; - } - - @Override - public String getName() { - return m_name; - } - - @Override - public String getClassName() { - return m_name; - } - - @Override - public ClassEntry getClassEntry() { - return this; - } - - @Override - public ClassEntry cloneToNewClass(ClassEntry classEntry) { - return classEntry; - } - - @Override - public int hashCode() { - return m_name.hashCode(); - } - - @Override - public boolean equals(Object other) { - if (other instanceof ClassEntry) { - return equals((ClassEntry)other); - } - return false; - } - - public boolean equals(ClassEntry other) { - return m_name.equals(other.m_name); - } - - @Override - public String toString() { - return m_name; - } - - public boolean isInnerClass() { - return m_name.lastIndexOf('$') >= 0; - } - - public List getClassChainNames() { - return Lists.newArrayList(m_name.split("\\$")); - } - - public List getClassChain() { - List entries = Lists.newArrayList(); - StringBuilder buf = new StringBuilder(); - for (String name : getClassChainNames()) { - if (buf.length() > 0) { - buf.append("$"); - } - buf.append(name); - entries.add(new ClassEntry(buf.toString())); - } - return entries; - } - - public String getOutermostClassName() { - if (isInnerClass()) { - return m_name.substring(0, m_name.indexOf('$')); - } - return m_name; - } - - public ClassEntry getOutermostClassEntry() { - return new ClassEntry(getOutermostClassName()); - } - - public String getOuterClassName() { - if (!isInnerClass()) { - throw new Error("This is not an inner class!"); - } - return m_name.substring(0, m_name.lastIndexOf('$')); - } - - public ClassEntry getOuterClassEntry() { - return new ClassEntry(getOuterClassName()); - } - - public String getInnermostClassName() { - if (!isInnerClass()) { - throw new Error("This is not an inner class!"); - } - return m_name.substring(m_name.lastIndexOf('$') + 1); - } - - public boolean isInDefaultPackage() { - return m_name.indexOf('/') < 0; - } - - public String getPackageName() { - int pos = m_name.lastIndexOf('/'); - if (pos > 0) { - return m_name.substring(0, pos); - } - return null; - } - - public String getSimpleName() { - int pos = m_name.lastIndexOf('/'); - if (pos > 0) { - return m_name.substring(pos + 1); - } - return m_name; - } - - public ClassEntry buildClassEntry(List classChain) { - assert(classChain.contains(this)); - StringBuilder buf = new StringBuilder(); - for (ClassEntry chainEntry : classChain) { - if (buf.length() == 0) { - buf.append(chainEntry.getName()); - } else { - buf.append("$"); - buf.append(chainEntry.isInnerClass() ? chainEntry.getInnermostClassName() : chainEntry.getSimpleName()); - } - - if (chainEntry == this) { - break; - } - } - return new ClassEntry(buf.toString()); - } -} diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java deleted file mode 100644 index 0b0105ec..00000000 --- a/src/cuchaz/enigma/mapping/ClassMapping.java +++ /dev/null @@ -1,460 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Map; - -import com.google.common.collect.Maps; - -public class ClassMapping implements Serializable, Comparable { - - private static final long serialVersionUID = -5148491146902340107L; - - private String m_obfFullName; - private String m_obfSimpleName; - private String m_deobfName; - private Map m_innerClassesByObfSimple; - private Map m_innerClassesByDeobf; - private Map m_fieldsByObf; - private Map m_fieldsByDeobf; - private Map m_methodsByObf; - private Map m_methodsByDeobf; - - public ClassMapping(String obfFullName) { - this(obfFullName, null); - } - - public ClassMapping(String obfFullName, String deobfName) { - m_obfFullName = obfFullName; - ClassEntry classEntry = new ClassEntry(obfFullName); - m_obfSimpleName = classEntry.isInnerClass() ? classEntry.getInnermostClassName() : classEntry.getSimpleName(); - m_deobfName = NameValidator.validateClassName(deobfName, false); - m_innerClassesByObfSimple = Maps.newHashMap(); - m_innerClassesByDeobf = Maps.newHashMap(); - m_fieldsByObf = Maps.newHashMap(); - m_fieldsByDeobf = Maps.newHashMap(); - m_methodsByObf = Maps.newHashMap(); - m_methodsByDeobf = Maps.newHashMap(); - } - - public String getObfFullName() { - return m_obfFullName; - } - - public String getObfSimpleName() { - return m_obfSimpleName; - } - - public String getDeobfName() { - return m_deobfName; - } - - public void setDeobfName(String val) { - m_deobfName = NameValidator.validateClassName(val, false); - } - - //// INNER CLASSES //////// - - public Iterable innerClasses() { - assert (m_innerClassesByObfSimple.size() >= m_innerClassesByDeobf.size()); - return m_innerClassesByObfSimple.values(); - } - - public void addInnerClassMapping(ClassMapping classMapping) { - boolean obfWasAdded = m_innerClassesByObfSimple.put(classMapping.getObfSimpleName(), classMapping) == null; - assert (obfWasAdded); - if (classMapping.getDeobfName() != null) { - assert (isSimpleClassName(classMapping.getDeobfName())); - boolean deobfWasAdded = m_innerClassesByDeobf.put(classMapping.getDeobfName(), classMapping) == null; - assert (deobfWasAdded); - } - } - - public void removeInnerClassMapping(ClassMapping classMapping) { - boolean obfWasRemoved = m_innerClassesByObfSimple.remove(classMapping.getObfSimpleName()) != null; - assert (obfWasRemoved); - if (classMapping.getDeobfName() != null) { - boolean deobfWasRemoved = m_innerClassesByDeobf.remove(classMapping.getDeobfName()) != null; - assert (deobfWasRemoved); - } - } - - public ClassMapping getOrCreateInnerClass(ClassEntry obfInnerClass) { - ClassMapping classMapping = m_innerClassesByObfSimple.get(obfInnerClass.getInnermostClassName()); - if (classMapping == null) { - classMapping = new ClassMapping(obfInnerClass.getName()); - boolean wasAdded = m_innerClassesByObfSimple.put(classMapping.getObfSimpleName(), classMapping) == null; - assert (wasAdded); - } - return classMapping; - } - - public ClassMapping getInnerClassByObfSimple(String obfSimpleName) { - assert (isSimpleClassName(obfSimpleName)); - return m_innerClassesByObfSimple.get(obfSimpleName); - } - - public ClassMapping getInnerClassByDeobf(String deobfName) { - assert (isSimpleClassName(deobfName)); - return m_innerClassesByDeobf.get(deobfName); - } - - public ClassMapping getInnerClassByDeobfThenObfSimple(String name) { - ClassMapping classMapping = getInnerClassByDeobf(name); - if (classMapping == null) { - classMapping = getInnerClassByObfSimple(name); - } - return classMapping; - } - - public String getDeobfInnerClassName(String obfSimpleName) { - assert (isSimpleClassName(obfSimpleName)); - ClassMapping classMapping = m_innerClassesByObfSimple.get(obfSimpleName); - if (classMapping != null) { - return classMapping.getDeobfName(); - } - return null; - } - - public void setInnerClassName(ClassEntry obfInnerClass, String deobfName) { - ClassMapping classMapping = getOrCreateInnerClass(obfInnerClass); - if (classMapping.getDeobfName() != null) { - boolean wasRemoved = m_innerClassesByDeobf.remove(classMapping.getDeobfName()) != null; - assert (wasRemoved); - } - classMapping.setDeobfName(deobfName); - if (deobfName != null) { - assert (isSimpleClassName(deobfName)); - boolean wasAdded = m_innerClassesByDeobf.put(deobfName, classMapping) == null; - assert (wasAdded); - } - } - - public boolean hasInnerClassByObfSimple(String obfSimpleName) { - return m_innerClassesByObfSimple.containsKey(obfSimpleName); - } - - public boolean hasInnerClassByDeobf(String deobfName) { - return m_innerClassesByDeobf.containsKey(deobfName); - } - - - //// FIELDS //////// - - public Iterable fields() { - assert (m_fieldsByObf.size() == m_fieldsByDeobf.size()); - return m_fieldsByObf.values(); - } - - public boolean containsObfField(String obfName, Type obfType) { - return m_fieldsByObf.containsKey(getFieldKey(obfName, obfType)); - } - - public boolean containsDeobfField(String deobfName, Type deobfType) { - return m_fieldsByDeobf.containsKey(getFieldKey(deobfName, deobfType)); - } - - public void addFieldMapping(FieldMapping fieldMapping) { - String obfKey = getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType()); - if (m_fieldsByObf.containsKey(obfKey)) { - throw new Error("Already have mapping for " + m_obfFullName + "." + obfKey); - } - String deobfKey = getFieldKey(fieldMapping.getDeobfName(), fieldMapping.getObfType()); - if (m_fieldsByDeobf.containsKey(deobfKey)) { - throw new Error("Already have mapping for " + m_deobfName + "." + deobfKey); - } - boolean obfWasAdded = m_fieldsByObf.put(obfKey, fieldMapping) == null; - assert (obfWasAdded); - boolean deobfWasAdded = m_fieldsByDeobf.put(deobfKey, fieldMapping) == null; - assert (deobfWasAdded); - assert (m_fieldsByObf.size() == m_fieldsByDeobf.size()); - } - - public void removeFieldMapping(FieldMapping fieldMapping) { - boolean obfWasRemoved = m_fieldsByObf.remove(getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType())) != null; - assert (obfWasRemoved); - if (fieldMapping.getDeobfName() != null) { - boolean deobfWasRemoved = m_fieldsByDeobf.remove(getFieldKey(fieldMapping.getDeobfName(), fieldMapping.getObfType())) != null; - assert (deobfWasRemoved); - } - } - - public FieldMapping getFieldByObf(String obfName, Type obfType) { - return m_fieldsByObf.get(getFieldKey(obfName, obfType)); - } - - public FieldMapping getFieldByDeobf(String deobfName, Type obfType) { - return m_fieldsByDeobf.get(getFieldKey(deobfName, obfType)); - } - - public String getObfFieldName(String deobfName, Type obfType) { - FieldMapping fieldMapping = m_fieldsByDeobf.get(getFieldKey(deobfName, obfType)); - if (fieldMapping != null) { - return fieldMapping.getObfName(); - } - return null; - } - - public String getDeobfFieldName(String obfName, Type obfType) { - FieldMapping fieldMapping = m_fieldsByObf.get(getFieldKey(obfName, obfType)); - if (fieldMapping != null) { - return fieldMapping.getDeobfName(); - } - return null; - } - - private String getFieldKey(String name, Type type) { - if (name == null) { - throw new IllegalArgumentException("name cannot be null!"); - } - if (type == null) { - throw new IllegalArgumentException("type cannot be null!"); - } - return name + ":" + type; - } - - - public void setFieldName(String obfName, Type obfType, String deobfName) { - assert(deobfName != null); - FieldMapping fieldMapping = m_fieldsByObf.get(getFieldKey(obfName, obfType)); - if (fieldMapping == null) { - fieldMapping = new FieldMapping(obfName, obfType, deobfName); - boolean obfWasAdded = m_fieldsByObf.put(getFieldKey(obfName, obfType), fieldMapping) == null; - assert (obfWasAdded); - } else { - boolean wasRemoved = m_fieldsByDeobf.remove(getFieldKey(fieldMapping.getDeobfName(), obfType)) != null; - assert (wasRemoved); - } - fieldMapping.setDeobfName(deobfName); - if (deobfName != null) { - boolean wasAdded = m_fieldsByDeobf.put(getFieldKey(deobfName, obfType), fieldMapping) == null; - assert (wasAdded); - } - } - - public void setFieldObfNameAndType(String oldObfName, Type obfType, String newObfName, Type newObfType) { - assert(newObfName != null); - FieldMapping fieldMapping = m_fieldsByObf.remove(getFieldKey(oldObfName, obfType)); - assert(fieldMapping != null); - fieldMapping.setObfName(newObfName); - fieldMapping.setObfType(newObfType); - boolean obfWasAdded = m_fieldsByObf.put(getFieldKey(newObfName, newObfType), fieldMapping) == null; - assert(obfWasAdded); - } - - - //// METHODS //////// - - public Iterable methods() { - assert (m_methodsByObf.size() >= m_methodsByDeobf.size()); - return m_methodsByObf.values(); - } - - public boolean containsObfMethod(String obfName, Signature obfSignature) { - return m_methodsByObf.containsKey(getMethodKey(obfName, obfSignature)); - } - - public boolean containsDeobfMethod(String deobfName, Signature obfSignature) { - return m_methodsByDeobf.containsKey(getMethodKey(deobfName, obfSignature)); - } - - public void addMethodMapping(MethodMapping methodMapping) { - String obfKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature()); - if (m_methodsByObf.containsKey(obfKey)) { - throw new Error("Already have mapping for " + m_obfFullName + "." + obfKey); - } - boolean wasAdded = m_methodsByObf.put(obfKey, methodMapping) == null; - assert (wasAdded); - if (methodMapping.getDeobfName() != null) { - String deobfKey = getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature()); - if (m_methodsByDeobf.containsKey(deobfKey)) { - throw new Error("Already have mapping for " + m_deobfName + "." + deobfKey); - } - boolean deobfWasAdded = m_methodsByDeobf.put(deobfKey, methodMapping) == null; - assert (deobfWasAdded); - } - assert (m_methodsByObf.size() >= m_methodsByDeobf.size()); - } - - public void removeMethodMapping(MethodMapping methodMapping) { - boolean obfWasRemoved = m_methodsByObf.remove(getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature())) != null; - assert (obfWasRemoved); - if (methodMapping.getDeobfName() != null) { - boolean deobfWasRemoved = m_methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature())) != null; - assert (deobfWasRemoved); - } - } - - public MethodMapping getMethodByObf(String obfName, Signature obfSignature) { - return m_methodsByObf.get(getMethodKey(obfName, obfSignature)); - } - - public MethodMapping getMethodByDeobf(String deobfName, Signature obfSignature) { - return m_methodsByDeobf.get(getMethodKey(deobfName, obfSignature)); - } - - private String getMethodKey(String name, Signature signature) { - if (name == null) { - throw new IllegalArgumentException("name cannot be null!"); - } - if (signature == null) { - throw new IllegalArgumentException("signature cannot be null!"); - } - return name + signature; - } - - public void setMethodName(String obfName, Signature obfSignature, String deobfName) { - MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfName, obfSignature)); - if (methodMapping == null) { - methodMapping = createMethodMapping(obfName, obfSignature); - } else if (methodMapping.getDeobfName() != null) { - boolean wasRemoved = m_methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature())) != null; - assert (wasRemoved); - } - methodMapping.setDeobfName(deobfName); - if (deobfName != null) { - boolean wasAdded = m_methodsByDeobf.put(getMethodKey(deobfName, obfSignature), methodMapping) == null; - assert (wasAdded); - } - } - - public void setMethodObfNameAndSignature(String oldObfName, Signature obfSignature, String newObfName, Signature newObfSignature) { - assert(newObfName != null); - MethodMapping methodMapping = m_methodsByObf.remove(getMethodKey(oldObfName, obfSignature)); - assert(methodMapping != null); - methodMapping.setObfName(newObfName); - methodMapping.setObfSignature(newObfSignature); - boolean obfWasAdded = m_methodsByObf.put(getMethodKey(newObfName, newObfSignature), methodMapping) == null; - assert(obfWasAdded); - } - - //// ARGUMENTS //////// - - public void setArgumentName(String obfMethodName, Signature obfMethodSignature, int argumentIndex, String argumentName) { - assert(argumentName != null); - MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfMethodName, obfMethodSignature)); - if (methodMapping == null) { - methodMapping = createMethodMapping(obfMethodName, obfMethodSignature); - } - methodMapping.setArgumentName(argumentIndex, argumentName); - } - - public void removeArgumentName(String obfMethodName, Signature obfMethodSignature, int argumentIndex) { - m_methodsByObf.get(getMethodKey(obfMethodName, obfMethodSignature)).removeArgumentName(argumentIndex); - } - - private MethodMapping createMethodMapping(String obfName, Signature obfSignature) { - MethodMapping methodMapping = new MethodMapping(obfName, obfSignature); - boolean wasAdded = m_methodsByObf.put(getMethodKey(obfName, obfSignature), methodMapping) == null; - assert (wasAdded); - return methodMapping; - } - - @Override - public String toString() { - StringBuilder buf = new StringBuilder(); - buf.append(m_obfFullName); - buf.append(" <-> "); - buf.append(m_deobfName); - buf.append("\n"); - buf.append("Fields:\n"); - for (FieldMapping fieldMapping : fields()) { - buf.append("\t"); - buf.append(fieldMapping.getObfName()); - buf.append(" <-> "); - buf.append(fieldMapping.getDeobfName()); - buf.append("\n"); - } - buf.append("Methods:\n"); - for (MethodMapping methodMapping : m_methodsByObf.values()) { - buf.append(methodMapping.toString()); - buf.append("\n"); - } - buf.append("Inner Classes:\n"); - for (ClassMapping classMapping : m_innerClassesByObfSimple.values()) { - buf.append("\t"); - buf.append(classMapping.getObfSimpleName()); - buf.append(" <-> "); - buf.append(classMapping.getDeobfName()); - buf.append("\n"); - } - return buf.toString(); - } - - @Override - public int compareTo(ClassMapping other) { - // sort by a, b, c, ... aa, ab, etc - if (m_obfFullName.length() != other.m_obfFullName.length()) { - return m_obfFullName.length() - other.m_obfFullName.length(); - } - return m_obfFullName.compareTo(other.m_obfFullName); - } - - public boolean renameObfClass(String oldObfClassName, String newObfClassName) { - - // rename inner classes - for (ClassMapping innerClassMapping : new ArrayList(m_innerClassesByObfSimple.values())) { - if (innerClassMapping.renameObfClass(oldObfClassName, newObfClassName)) { - boolean wasRemoved = m_innerClassesByObfSimple.remove(oldObfClassName) != null; - assert (wasRemoved); - boolean wasAdded = m_innerClassesByObfSimple.put(newObfClassName, innerClassMapping) == null; - assert (wasAdded); - } - } - - // rename field types - for (FieldMapping fieldMapping : new ArrayList(m_fieldsByObf.values())) { - String oldFieldKey = getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType()); - if (fieldMapping.renameObfClass(oldObfClassName, newObfClassName)) { - boolean wasRemoved = m_fieldsByObf.remove(oldFieldKey) != null; - assert (wasRemoved); - boolean wasAdded = m_fieldsByObf.put(getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType()), fieldMapping) == null; - assert (wasAdded); - } - } - - // rename method signatures - for (MethodMapping methodMapping : new ArrayList(m_methodsByObf.values())) { - String oldMethodKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature()); - if (methodMapping.renameObfClass(oldObfClassName, newObfClassName)) { - boolean wasRemoved = m_methodsByObf.remove(oldMethodKey) != null; - assert (wasRemoved); - boolean wasAdded = m_methodsByObf.put(getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature()), methodMapping) == null; - assert (wasAdded); - } - } - - if (m_obfFullName.equals(oldObfClassName)) { - // rename this class - m_obfFullName = newObfClassName; - return true; - } - return false; - } - - public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) { - MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfBehaviorEntry.getName(), obfBehaviorEntry.getSignature())); - if (methodMapping != null) { - return methodMapping.containsArgument(name); - } - return false; - } - - public static boolean isSimpleClassName(String name) { - return name.indexOf('/') < 0 && name.indexOf('$') < 0; - } - - public ClassEntry getObfEntry() { - return new ClassEntry(m_obfFullName); - } -} diff --git a/src/cuchaz/enigma/mapping/ClassNameReplacer.java b/src/cuchaz/enigma/mapping/ClassNameReplacer.java deleted file mode 100644 index f00d811e..00000000 --- a/src/cuchaz/enigma/mapping/ClassNameReplacer.java +++ /dev/null @@ -1,15 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -public interface ClassNameReplacer { - String replace(String className); -} diff --git a/src/cuchaz/enigma/mapping/ConstructorEntry.java b/src/cuchaz/enigma/mapping/ConstructorEntry.java deleted file mode 100644 index 7cde8f65..00000000 --- a/src/cuchaz/enigma/mapping/ConstructorEntry.java +++ /dev/null @@ -1,116 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -import java.io.Serializable; - -import cuchaz.enigma.Util; - -public class ConstructorEntry implements BehaviorEntry, Serializable { - - private static final long serialVersionUID = -868346075317366758L; - - private ClassEntry m_classEntry; - private Signature m_signature; - - public ConstructorEntry(ClassEntry classEntry) { - this(classEntry, null); - } - - public ConstructorEntry(ClassEntry classEntry, Signature signature) { - if (classEntry == null) { - throw new IllegalArgumentException("Class cannot be null!"); - } - - m_classEntry = classEntry; - m_signature = signature; - } - - public ConstructorEntry(ConstructorEntry other) { - m_classEntry = new ClassEntry(other.m_classEntry); - m_signature = other.m_signature; - } - - public ConstructorEntry(ConstructorEntry other, String newClassName) { - m_classEntry = new ClassEntry(newClassName); - m_signature = other.m_signature; - } - - @Override - public ClassEntry getClassEntry() { - return m_classEntry; - } - - @Override - public String getName() { - if (isStatic()) { - return ""; - } - return ""; - } - - public boolean isStatic() { - return m_signature == null; - } - - @Override - public Signature getSignature() { - return m_signature; - } - - @Override - public String getClassName() { - return m_classEntry.getName(); - } - - @Override - public ConstructorEntry cloneToNewClass(ClassEntry classEntry) { - return new ConstructorEntry(this, classEntry.getName()); - } - - @Override - public int hashCode() { - if (isStatic()) { - return Util.combineHashesOrdered(m_classEntry); - } else { - return Util.combineHashesOrdered(m_classEntry, m_signature); - } - } - - @Override - public boolean equals(Object other) { - if (other instanceof ConstructorEntry) { - return equals((ConstructorEntry)other); - } - return false; - } - - public boolean equals(ConstructorEntry other) { - if (isStatic() != other.isStatic()) { - return false; - } - - if (isStatic()) { - return m_classEntry.equals(other.m_classEntry); - } else { - return m_classEntry.equals(other.m_classEntry) && m_signature.equals(other.m_signature); - } - } - - @Override - public String toString() { - if (isStatic()) { - return m_classEntry.getName() + "." + getName(); - } else { - return m_classEntry.getName() + "." + getName() + m_signature; - } - } -} diff --git a/src/cuchaz/enigma/mapping/Entry.java b/src/cuchaz/enigma/mapping/Entry.java deleted file mode 100644 index 3c94a95a..00000000 --- a/src/cuchaz/enigma/mapping/Entry.java +++ /dev/null @@ -1,18 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -public interface Entry { - String getName(); - String getClassName(); - ClassEntry getClassEntry(); - Entry cloneToNewClass(ClassEntry classEntry); -} diff --git a/src/cuchaz/enigma/mapping/EntryFactory.java b/src/cuchaz/enigma/mapping/EntryFactory.java deleted file mode 100644 index 03d97ba1..00000000 --- a/src/cuchaz/enigma/mapping/EntryFactory.java +++ /dev/null @@ -1,166 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -import javassist.CtBehavior; -import javassist.CtClass; -import javassist.CtConstructor; -import javassist.CtField; -import javassist.CtMethod; -import javassist.bytecode.Descriptor; -import javassist.expr.ConstructorCall; -import javassist.expr.FieldAccess; -import javassist.expr.MethodCall; -import javassist.expr.NewExpr; - -import cuchaz.enigma.analysis.JarIndex; - -public class EntryFactory { - - public static ClassEntry getClassEntry(CtClass c) { - return new ClassEntry(Descriptor.toJvmName(c.getName())); - } - - public static ClassEntry getObfClassEntry(JarIndex jarIndex, ClassMapping classMapping) { - ClassEntry obfClassEntry = new ClassEntry(classMapping.getObfFullName()); - return obfClassEntry.buildClassEntry(jarIndex.getObfClassChain(obfClassEntry)); - } - - private static ClassEntry getObfClassEntry(ClassMapping classMapping) { - return new ClassEntry(classMapping.getObfFullName()); - } - - public static ClassEntry getDeobfClassEntry(ClassMapping classMapping) { - return new ClassEntry(classMapping.getDeobfName()); - } - - public static ClassEntry getSuperclassEntry(CtClass c) { - return new ClassEntry(Descriptor.toJvmName(c.getClassFile().getSuperclass())); - } - - public static FieldEntry getFieldEntry(CtField field) { - return new FieldEntry( - getClassEntry(field.getDeclaringClass()), - field.getName(), - new Type(field.getFieldInfo().getDescriptor()) - ); - } - - public static FieldEntry getFieldEntry(FieldAccess call) { - return new FieldEntry( - new ClassEntry(Descriptor.toJvmName(call.getClassName())), - call.getFieldName(), - new Type(call.getSignature()) - ); - } - - public static FieldEntry getFieldEntry(String className, String name, String type) { - return new FieldEntry(new ClassEntry(className), name, new Type(type)); - } - - public static FieldEntry getObfFieldEntry(ClassMapping classMapping, FieldMapping fieldMapping) { - return new FieldEntry( - getObfClassEntry(classMapping), - fieldMapping.getObfName(), - fieldMapping.getObfType() - ); - } - - public static MethodEntry getMethodEntry(CtMethod method) { - return new MethodEntry( - getClassEntry(method.getDeclaringClass()), - method.getName(), - new Signature(method.getMethodInfo().getDescriptor()) - ); - } - - public static MethodEntry getMethodEntry(MethodCall call) { - return new MethodEntry( - new ClassEntry(Descriptor.toJvmName(call.getClassName())), - call.getMethodName(), - new Signature(call.getSignature()) - ); - } - - public static ConstructorEntry getConstructorEntry(CtConstructor constructor) { - if (constructor.isClassInitializer()) { - return new ConstructorEntry( - getClassEntry(constructor.getDeclaringClass()) - ); - } else { - return new ConstructorEntry( - getClassEntry(constructor.getDeclaringClass()), - new Signature(constructor.getMethodInfo().getDescriptor()) - ); - } - } - - public static ConstructorEntry getConstructorEntry(ConstructorCall call) { - return new ConstructorEntry( - new ClassEntry(Descriptor.toJvmName(call.getClassName())), - new Signature(call.getSignature()) - ); - } - - public static ConstructorEntry getConstructorEntry(NewExpr call) { - return new ConstructorEntry( - new ClassEntry(Descriptor.toJvmName(call.getClassName())), - new Signature(call.getSignature()) - ); - } - - public static BehaviorEntry getBehaviorEntry(CtBehavior behavior) { - if (behavior instanceof CtMethod) { - return getMethodEntry((CtMethod)behavior); - } else if (behavior instanceof CtConstructor) { - return getConstructorEntry((CtConstructor)behavior); - } - throw new Error("behavior is neither Method nor Constructor!"); - } - - public static BehaviorEntry getBehaviorEntry(String className, String behaviorName, String behaviorSignature) { - return getBehaviorEntry(new ClassEntry(className), behaviorName, new Signature(behaviorSignature)); - } - - public static BehaviorEntry getBehaviorEntry(String className, String behaviorName) { - return getBehaviorEntry(new ClassEntry(className), behaviorName); - } - - public static BehaviorEntry getBehaviorEntry(String className) { - return new ConstructorEntry(new ClassEntry(className)); - } - - public static BehaviorEntry getBehaviorEntry(ClassEntry classEntry, String behaviorName, Signature behaviorSignature) { - if (behaviorName.equals("")) { - return new ConstructorEntry(classEntry, behaviorSignature); - } else if(behaviorName.equals("")) { - return new ConstructorEntry(classEntry); - } else { - return new MethodEntry(classEntry, behaviorName, behaviorSignature); - } - } - - public static BehaviorEntry getBehaviorEntry(ClassEntry classEntry, String behaviorName) { - if(behaviorName.equals("")) { - return new ConstructorEntry(classEntry); - } else { - throw new IllegalArgumentException("Only class initializers don't have signatures"); - } - } - - public static BehaviorEntry getObfBehaviorEntry(ClassEntry classEntry, MethodMapping methodMapping) { - return getBehaviorEntry(classEntry, methodMapping.getObfName(), methodMapping.getObfSignature()); - } - - public static BehaviorEntry getObfBehaviorEntry(ClassMapping classMapping, MethodMapping methodMapping) { - return getObfBehaviorEntry(getObfClassEntry(classMapping), methodMapping); - } -} diff --git a/src/cuchaz/enigma/mapping/EntryPair.java b/src/cuchaz/enigma/mapping/EntryPair.java deleted file mode 100644 index 82b28cd1..00000000 --- a/src/cuchaz/enigma/mapping/EntryPair.java +++ /dev/null @@ -1,22 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -public class EntryPair { - - public T obf; - public T deobf; - - public EntryPair(T obf, T deobf) { - this.obf = obf; - this.deobf = deobf; - } -} diff --git a/src/cuchaz/enigma/mapping/FieldEntry.java b/src/cuchaz/enigma/mapping/FieldEntry.java deleted file mode 100644 index e4a74f4f..00000000 --- a/src/cuchaz/enigma/mapping/FieldEntry.java +++ /dev/null @@ -1,99 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -import java.io.Serializable; - -import cuchaz.enigma.Util; - -public class FieldEntry implements Entry, Serializable { - - private static final long serialVersionUID = 3004663582802885451L; - - private ClassEntry m_classEntry; - private String m_name; - private Type m_type; - - // NOTE: this argument order is important for the MethodReader/MethodWriter - public FieldEntry(ClassEntry classEntry, String name, Type type) { - if (classEntry == null) { - throw new IllegalArgumentException("Class cannot be null!"); - } - if (name == null) { - throw new IllegalArgumentException("Field name cannot be null!"); - } - if (type == null) { - throw new IllegalArgumentException("Field type cannot be null!"); - } - - m_classEntry = classEntry; - m_name = name; - m_type = type; - } - - public FieldEntry(FieldEntry other) { - this(other, new ClassEntry(other.m_classEntry)); - } - - public FieldEntry(FieldEntry other, ClassEntry newClassEntry) { - m_classEntry = newClassEntry; - m_name = other.m_name; - m_type = other.m_type; - } - - @Override - public ClassEntry getClassEntry() { - return m_classEntry; - } - - @Override - public String getName() { - return m_name; - } - - @Override - public String getClassName() { - return m_classEntry.getName(); - } - - public Type getType() { - return m_type; - } - - @Override - public FieldEntry cloneToNewClass(ClassEntry classEntry) { - return new FieldEntry(this, classEntry); - } - - @Override - public int hashCode() { - return Util.combineHashesOrdered(m_classEntry, m_name, m_type); - } - - @Override - public boolean equals(Object other) { - if (other instanceof FieldEntry) { - return equals((FieldEntry)other); - } - return false; - } - - public boolean equals(FieldEntry other) { - return m_classEntry.equals(other.m_classEntry) - && m_name.equals(other.m_name) - && m_type.equals(other.m_type); - } - - @Override - public String toString() { - return m_classEntry.getName() + "." + m_name + ":" + m_type; - } -} diff --git a/src/cuchaz/enigma/mapping/FieldMapping.java b/src/cuchaz/enigma/mapping/FieldMapping.java deleted file mode 100644 index 28557406..00000000 --- a/src/cuchaz/enigma/mapping/FieldMapping.java +++ /dev/null @@ -1,89 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -import java.io.Serializable; - -public class FieldMapping implements Serializable, Comparable, MemberMapping { - - private static final long serialVersionUID = 8610742471440861315L; - - private String m_obfName; - private String m_deobfName; - private Type m_obfType; - - public FieldMapping(String obfName, Type obfType, String deobfName) { - m_obfName = obfName; - m_deobfName = NameValidator.validateFieldName(deobfName); - m_obfType = obfType; - } - - public FieldMapping(FieldMapping other, ClassNameReplacer obfClassNameReplacer) { - m_obfName = other.m_obfName; - m_deobfName = other.m_deobfName; - m_obfType = new Type(other.m_obfType, obfClassNameReplacer); - } - - @Override - public String getObfName() { - return m_obfName; - } - - public void setObfName(String val) { - m_obfName = NameValidator.validateFieldName(val); - } - - public String getDeobfName() { - return m_deobfName; - } - - public void setDeobfName(String val) { - m_deobfName = NameValidator.validateFieldName(val); - } - - public Type getObfType() { - return m_obfType; - } - - public void setObfType(Type val) { - m_obfType = val; - } - - @Override - public int compareTo(FieldMapping other) { - return (m_obfName + m_obfType).compareTo(other.m_obfName + other.m_obfType); - } - - public boolean renameObfClass(final String oldObfClassName, final String newObfClassName) { - - // rename obf classes in the type - Type newType = new Type(m_obfType, new ClassNameReplacer() { - @Override - public String replace(String className) { - if (className.equals(oldObfClassName)) { - return newObfClassName; - } - return null; - } - }); - - if (!newType.equals(m_obfType)) { - m_obfType = newType; - return true; - } - return false; - } - - @Override - public FieldEntry getObfEntry(ClassEntry classEntry) { - return new FieldEntry(classEntry, m_obfName, new Type(m_obfType)); - } -} diff --git a/src/cuchaz/enigma/mapping/IllegalNameException.java b/src/cuchaz/enigma/mapping/IllegalNameException.java deleted file mode 100644 index f62df7c4..00000000 --- a/src/cuchaz/enigma/mapping/IllegalNameException.java +++ /dev/null @@ -1,44 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -public class IllegalNameException extends RuntimeException { - - private static final long serialVersionUID = -2279910052561114323L; - - private String m_name; - private String m_reason; - - public IllegalNameException(String name) { - this(name, null); - } - - public IllegalNameException(String name, String reason) { - m_name = name; - m_reason = reason; - } - - public String getReason() { - return m_reason; - } - - @Override - public String getMessage() { - StringBuilder buf = new StringBuilder(); - buf.append("Illegal name: "); - buf.append(m_name); - if (m_reason != null) { - buf.append(" because "); - buf.append(m_reason); - } - return buf.toString(); - } -} diff --git a/src/cuchaz/enigma/mapping/MappingParseException.java b/src/cuchaz/enigma/mapping/MappingParseException.java deleted file mode 100644 index 73fca94a..00000000 --- a/src/cuchaz/enigma/mapping/MappingParseException.java +++ /dev/null @@ -1,29 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -public class MappingParseException extends Exception { - - private static final long serialVersionUID = -5487280332892507236L; - - private int m_line; - private String m_message; - - public MappingParseException(int line, String message) { - m_line = line; - m_message = message; - } - - @Override - public String getMessage() { - return "Line " + m_line + ": " + m_message; - } -} diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java deleted file mode 100644 index 11ed5d0c..00000000 --- a/src/cuchaz/enigma/mapping/Mappings.java +++ /dev/null @@ -1,216 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; - -import cuchaz.enigma.analysis.TranslationIndex; - -public class Mappings implements Serializable { - - private static final long serialVersionUID = 4649790259460259026L; - - protected Map m_classesByObf; - protected Map m_classesByDeobf; - - public Mappings() { - m_classesByObf = Maps.newHashMap(); - m_classesByDeobf = Maps.newHashMap(); - } - - public Mappings(Iterable classes) { - this(); - - for (ClassMapping classMapping : classes) { - m_classesByObf.put(classMapping.getObfFullName(), classMapping); - if (classMapping.getDeobfName() != null) { - m_classesByDeobf.put(classMapping.getDeobfName(), classMapping); - } - } - } - - public Collection classes() { - assert (m_classesByObf.size() >= m_classesByDeobf.size()); - return m_classesByObf.values(); - } - - public void addClassMapping(ClassMapping classMapping) { - if (m_classesByObf.containsKey(classMapping.getObfFullName())) { - throw new Error("Already have mapping for " + classMapping.getObfFullName()); - } - boolean obfWasAdded = m_classesByObf.put(classMapping.getObfFullName(), classMapping) == null; - assert (obfWasAdded); - if (classMapping.getDeobfName() != null) { - if (m_classesByDeobf.containsKey(classMapping.getDeobfName())) { - throw new Error("Already have mapping for " + classMapping.getDeobfName()); - } - boolean deobfWasAdded = m_classesByDeobf.put(classMapping.getDeobfName(), classMapping) == null; - assert (deobfWasAdded); - } - } - - public void removeClassMapping(ClassMapping classMapping) { - boolean obfWasRemoved = m_classesByObf.remove(classMapping.getObfFullName()) != null; - assert (obfWasRemoved); - if (classMapping.getDeobfName() != null) { - boolean deobfWasRemoved = m_classesByDeobf.remove(classMapping.getDeobfName()) != null; - assert (deobfWasRemoved); - } - } - - public ClassMapping getClassByObf(ClassEntry entry) { - return getClassByObf(entry.getName()); - } - - public ClassMapping getClassByObf(String obfName) { - return m_classesByObf.get(obfName); - } - - public ClassMapping getClassByDeobf(ClassEntry entry) { - return getClassByDeobf(entry.getName()); - } - - public ClassMapping getClassByDeobf(String deobfName) { - return m_classesByDeobf.get(deobfName); - } - - public void setClassDeobfName(ClassMapping classMapping, String deobfName) { - if (classMapping.getDeobfName() != null) { - boolean wasRemoved = m_classesByDeobf.remove(classMapping.getDeobfName()) != null; - assert (wasRemoved); - } - classMapping.setDeobfName(deobfName); - if (deobfName != null) { - boolean wasAdded = m_classesByDeobf.put(deobfName, classMapping) == null; - assert (wasAdded); - } - } - - public Translator getTranslator(TranslationDirection direction, TranslationIndex index) { - switch (direction) { - case Deobfuscating: - - return new Translator(direction, m_classesByObf, index); - - case Obfuscating: - - // fill in the missing deobf class entries with obf entries - Map classes = Maps.newHashMap(); - for (ClassMapping classMapping : classes()) { - if (classMapping.getDeobfName() != null) { - classes.put(classMapping.getDeobfName(), classMapping); - } else { - classes.put(classMapping.getObfFullName(), classMapping); - } - } - - // translate the translation index - // NOTE: this isn't actually recursive - TranslationIndex deobfIndex = new TranslationIndex(index, getTranslator(TranslationDirection.Deobfuscating, index)); - - return new Translator(direction, classes, deobfIndex); - - default: - throw new Error("Invalid translation direction!"); - } - } - - @Override - public String toString() { - StringBuilder buf = new StringBuilder(); - for (ClassMapping classMapping : m_classesByObf.values()) { - buf.append(classMapping.toString()); - buf.append("\n"); - } - return buf.toString(); - } - - public void renameObfClass(String oldObfName, String newObfName) { - for (ClassMapping classMapping : new ArrayList(classes())) { - if (classMapping.renameObfClass(oldObfName, newObfName)) { - boolean wasRemoved = m_classesByObf.remove(oldObfName) != null; - assert (wasRemoved); - boolean wasAdded = m_classesByObf.put(newObfName, classMapping) == null; - assert (wasAdded); - } - } - } - - public Set getAllObfClassNames() { - final Set classNames = Sets.newHashSet(); - for (ClassMapping classMapping : classes()) { - - // add the class name - classNames.add(classMapping.getObfFullName()); - - // add classes from method signatures - for (MethodMapping methodMapping : classMapping.methods()) { - for (Type type : methodMapping.getObfSignature().types()) { - if (type.hasClass()) { - classNames.add(type.getClassEntry().getClassName()); - } - } - } - } - return classNames; - } - - public boolean containsDeobfClass(String deobfName) { - return m_classesByDeobf.containsKey(deobfName); - } - - public boolean containsDeobfField(ClassEntry obfClassEntry, String deobfName, Type obfType) { - ClassMapping classMapping = m_classesByObf.get(obfClassEntry.getName()); - if (classMapping != null) { - return classMapping.containsDeobfField(deobfName, obfType); - } - return false; - } - - public boolean containsDeobfMethod(ClassEntry obfClassEntry, String deobfName, Signature deobfSignature) { - ClassMapping classMapping = m_classesByObf.get(obfClassEntry.getName()); - if (classMapping != null) { - return classMapping.containsDeobfMethod(deobfName, deobfSignature); - } - return false; - } - - public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) { - ClassMapping classMapping = m_classesByObf.get(obfBehaviorEntry.getClassName()); - if (classMapping != null) { - return classMapping.containsArgument(obfBehaviorEntry, name); - } - return false; - } - - public List getClassMappingChain(ClassEntry obfClass) { - List mappingChain = Lists.newArrayList(); - ClassMapping classMapping = null; - for (ClassEntry obfClassEntry : obfClass.getClassChain()) { - if (mappingChain.isEmpty()) { - classMapping = m_classesByObf.get(obfClassEntry.getName()); - } else if (classMapping != null) { - classMapping = classMapping.getInnerClassByObfSimple(obfClassEntry.getInnermostClassName()); - } - mappingChain.add(classMapping); - } - return mappingChain; - } -} diff --git a/src/cuchaz/enigma/mapping/MappingsChecker.java b/src/cuchaz/enigma/mapping/MappingsChecker.java deleted file mode 100644 index b25ea3cf..00000000 --- a/src/cuchaz/enigma/mapping/MappingsChecker.java +++ /dev/null @@ -1,107 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -import java.util.Map; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - -import cuchaz.enigma.analysis.JarIndex; -import cuchaz.enigma.analysis.RelatedMethodChecker; - - -public class MappingsChecker { - - private JarIndex m_index; - private RelatedMethodChecker m_relatedMethodChecker; - private Map m_droppedClassMappings; - private Map m_droppedInnerClassMappings; - private Map m_droppedFieldMappings; - private Map m_droppedMethodMappings; - - public MappingsChecker(JarIndex index) { - m_index = index; - m_relatedMethodChecker = new RelatedMethodChecker(m_index); - m_droppedClassMappings = Maps.newHashMap(); - m_droppedInnerClassMappings = Maps.newHashMap(); - m_droppedFieldMappings = Maps.newHashMap(); - m_droppedMethodMappings = Maps.newHashMap(); - } - - public RelatedMethodChecker getRelatedMethodChecker() { - return m_relatedMethodChecker; - } - - public Map getDroppedClassMappings() { - return m_droppedClassMappings; - } - - public Map getDroppedInnerClassMappings() { - return m_droppedInnerClassMappings; - } - - public Map getDroppedFieldMappings() { - return m_droppedFieldMappings; - } - - public Map getDroppedMethodMappings() { - return m_droppedMethodMappings; - } - - public void dropBrokenMappings(Mappings mappings) { - for (ClassMapping classMapping : Lists.newArrayList(mappings.classes())) { - if (!checkClassMapping(classMapping)) { - mappings.removeClassMapping(classMapping); - m_droppedClassMappings.put(EntryFactory.getObfClassEntry(m_index, classMapping), classMapping); - } - } - } - - private boolean checkClassMapping(ClassMapping classMapping) { - - // check the class - ClassEntry classEntry = EntryFactory.getObfClassEntry(m_index, classMapping); - if (!m_index.getObfClassEntries().contains(classEntry)) { - return false; - } - - // check the fields - for (FieldMapping fieldMapping : Lists.newArrayList(classMapping.fields())) { - FieldEntry obfFieldEntry = EntryFactory.getObfFieldEntry(classMapping, fieldMapping); - if (!m_index.containsObfField(obfFieldEntry)) { - classMapping.removeFieldMapping(fieldMapping); - m_droppedFieldMappings.put(obfFieldEntry, fieldMapping); - } - } - - // check methods - for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) { - BehaviorEntry obfBehaviorEntry = EntryFactory.getObfBehaviorEntry(classEntry, methodMapping); - if (!m_index.containsObfBehavior(obfBehaviorEntry)) { - classMapping.removeMethodMapping(methodMapping); - m_droppedMethodMappings.put(obfBehaviorEntry, methodMapping); - } - - m_relatedMethodChecker.checkMethod(classEntry, methodMapping); - } - - // check inner classes - for (ClassMapping innerClassMapping : Lists.newArrayList(classMapping.innerClasses())) { - if (!checkClassMapping(innerClassMapping)) { - classMapping.removeInnerClassMapping(innerClassMapping); - m_droppedInnerClassMappings.put(EntryFactory.getObfClassEntry(m_index, innerClassMapping), innerClassMapping); - } - } - - return true; - } -} diff --git a/src/cuchaz/enigma/mapping/MappingsReader.java b/src/cuchaz/enigma/mapping/MappingsReader.java deleted file mode 100644 index 0a4b117e..00000000 --- a/src/cuchaz/enigma/mapping/MappingsReader.java +++ /dev/null @@ -1,134 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.Reader; -import java.util.Deque; - -import com.google.common.collect.Queues; - -public class MappingsReader { - - public Mappings read(Reader in) - throws IOException, MappingParseException { - return read(new BufferedReader(in)); - } - - public Mappings read(BufferedReader in) - throws IOException, MappingParseException { - Mappings mappings = new Mappings(); - Deque mappingStack = Queues.newArrayDeque(); - - int lineNumber = 0; - String line = null; - while ( (line = in.readLine()) != null) { - lineNumber++; - - // strip comments - int commentPos = line.indexOf('#'); - if (commentPos >= 0) { - line = line.substring(0, commentPos); - } - - // skip blank lines - if (line.trim().length() <= 0) { - continue; - } - - // get the indent of this line - int indent = 0; - for (int i = 0; i < line.length(); i++) { - if (line.charAt(i) != '\t') { - break; - } - indent++; - } - - // handle stack pops - while (indent < mappingStack.size()) { - mappingStack.pop(); - } - - String[] parts = line.trim().split("\\s"); - try { - // read the first token - String token = parts[0]; - - if (token.equalsIgnoreCase("CLASS")) { - ClassMapping classMapping; - if (indent <= 0) { - // outer class - classMapping = readClass(parts, false); - mappings.addClassMapping(classMapping); - } else { - - // inner class - if (!(mappingStack.peek() instanceof ClassMapping)) { - throw new MappingParseException(lineNumber, "Unexpected CLASS entry here!"); - } - - classMapping = readClass(parts, true); - ((ClassMapping)mappingStack.peek()).addInnerClassMapping(classMapping); - } - mappingStack.push(classMapping); - } else if (token.equalsIgnoreCase("FIELD")) { - if (mappingStack.isEmpty() || ! (mappingStack.peek() instanceof ClassMapping)) { - throw new MappingParseException(lineNumber, "Unexpected FIELD entry here!"); - } - ((ClassMapping)mappingStack.peek()).addFieldMapping(readField(parts)); - } else if (token.equalsIgnoreCase("METHOD")) { - if (mappingStack.isEmpty() || ! (mappingStack.peek() instanceof ClassMapping)) { - throw new MappingParseException(lineNumber, "Unexpected METHOD entry here!"); - } - MethodMapping methodMapping = readMethod(parts); - ((ClassMapping)mappingStack.peek()).addMethodMapping(methodMapping); - mappingStack.push(methodMapping); - } else if (token.equalsIgnoreCase("ARG")) { - if (mappingStack.isEmpty() || ! (mappingStack.peek() instanceof MethodMapping)) { - throw new MappingParseException(lineNumber, "Unexpected ARG entry here!"); - } - ((MethodMapping)mappingStack.peek()).addArgumentMapping(readArgument(parts)); - } - } catch (ArrayIndexOutOfBoundsException | IllegalArgumentException ex) { - throw new MappingParseException(lineNumber, "Malformed line:\n" + line); - } - } - - return mappings; - } - - private ArgumentMapping readArgument(String[] parts) { - return new ArgumentMapping(Integer.parseInt(parts[1]), parts[2]); - } - - private ClassMapping readClass(String[] parts, boolean makeSimple) { - if (parts.length == 2) { - return new ClassMapping(parts[1]); - } else { - return new ClassMapping(parts[1], parts[2]); - } - } - - /* TEMP */ - protected FieldMapping readField(String[] parts) { - return new FieldMapping(parts[1], new Type(parts[3]), parts[2]); - } - - private MethodMapping readMethod(String[] parts) { - if (parts.length == 3) { - return new MethodMapping(parts[1], new Signature(parts[2])); - } else { - return new MethodMapping(parts[1], new Signature(parts[3]), parts[2]); - } - } -} diff --git a/src/cuchaz/enigma/mapping/MappingsRenamer.java b/src/cuchaz/enigma/mapping/MappingsRenamer.java deleted file mode 100644 index 47e5738c..00000000 --- a/src/cuchaz/enigma/mapping/MappingsRenamer.java +++ /dev/null @@ -1,237 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -import java.io.IOException; -import java.io.ObjectOutputStream; -import java.io.OutputStream; -import java.util.List; -import java.util.Set; -import java.util.zip.GZIPOutputStream; - -import cuchaz.enigma.analysis.JarIndex; - -public class MappingsRenamer { - - private JarIndex m_index; - private Mappings m_mappings; - - public MappingsRenamer(JarIndex index, Mappings mappings) { - m_index = index; - m_mappings = mappings; - } - - public void setClassName(ClassEntry obf, String deobfName) { - - deobfName = NameValidator.validateClassName(deobfName, !obf.isInnerClass()); - - List mappingChain = getOrCreateClassMappingChain(obf); - if (mappingChain.size() == 1) { - - if (deobfName != null) { - // make sure we don't rename to an existing obf or deobf class - if (m_mappings.containsDeobfClass(deobfName) || m_index.containsObfClass(new ClassEntry(deobfName))) { - throw new IllegalNameException(deobfName, "There is already a class with that name"); - } - } - - ClassMapping classMapping = mappingChain.get(0); - m_mappings.setClassDeobfName(classMapping, deobfName); - - } else { - - ClassMapping outerClassMapping = mappingChain.get(mappingChain.size() - 2); - - if (deobfName != null) { - // make sure we don't rename to an existing obf or deobf inner class - if (outerClassMapping.hasInnerClassByDeobf(deobfName) || outerClassMapping.hasInnerClassByObfSimple(deobfName)) { - throw new IllegalNameException(deobfName, "There is already a class with that name"); - } - } - - outerClassMapping.setInnerClassName(obf, deobfName); - } - } - - public void removeClassMapping(ClassEntry obf) { - setClassName(obf, null); - } - - public void markClassAsDeobfuscated(ClassEntry obf) { - String deobfName = obf.isInnerClass() ? obf.getInnermostClassName() : obf.getName(); - List mappingChain = getOrCreateClassMappingChain(obf); - if (mappingChain.size() == 1) { - ClassMapping classMapping = mappingChain.get(0); - m_mappings.setClassDeobfName(classMapping, deobfName); - } else { - ClassMapping outerClassMapping = mappingChain.get(mappingChain.size() - 2); - outerClassMapping.setInnerClassName(obf, deobfName); - } - } - - public void setFieldName(FieldEntry obf, String deobfName) { - deobfName = NameValidator.validateFieldName(deobfName); - FieldEntry targetEntry = new FieldEntry(obf.getClassEntry(), deobfName, obf.getType()); - if (m_mappings.containsDeobfField(obf.getClassEntry(), deobfName, obf.getType()) || m_index.containsObfField(targetEntry)) { - throw new IllegalNameException(deobfName, "There is already a field with that name"); - } - - ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry()); - classMapping.setFieldName(obf.getName(), obf.getType(), deobfName); - } - - public void removeFieldMapping(FieldEntry obf) { - ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry()); - classMapping.removeFieldMapping(classMapping.getFieldByObf(obf.getName(), obf.getType())); - } - - public void markFieldAsDeobfuscated(FieldEntry obf) { - ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry()); - classMapping.setFieldName(obf.getName(), obf.getType(), obf.getName()); - } - - public void setMethodTreeName(MethodEntry obf, String deobfName) { - Set implementations = m_index.getRelatedMethodImplementations(obf); - - deobfName = NameValidator.validateMethodName(deobfName); - for (MethodEntry entry : implementations) { - Signature deobfSignature = m_mappings.getTranslator(TranslationDirection.Deobfuscating, m_index.getTranslationIndex()).translateSignature(obf.getSignature()); - MethodEntry targetEntry = new MethodEntry(entry.getClassEntry(), deobfName, deobfSignature); - if (m_mappings.containsDeobfMethod(entry.getClassEntry(), deobfName, entry.getSignature()) || m_index.containsObfBehavior(targetEntry)) { - String deobfClassName = m_mappings.getTranslator(TranslationDirection.Deobfuscating, m_index.getTranslationIndex()).translateClass(entry.getClassName()); - throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName); - } - } - - for (MethodEntry entry : implementations) { - setMethodName(entry, deobfName); - } - } - - public void setMethodName(MethodEntry obf, String deobfName) { - deobfName = NameValidator.validateMethodName(deobfName); - MethodEntry targetEntry = new MethodEntry(obf.getClassEntry(), deobfName, obf.getSignature()); - if (m_mappings.containsDeobfMethod(obf.getClassEntry(), deobfName, obf.getSignature()) || m_index.containsObfBehavior(targetEntry)) { - String deobfClassName = m_mappings.getTranslator(TranslationDirection.Deobfuscating, m_index.getTranslationIndex()).translateClass(obf.getClassName()); - throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName); - } - - ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry()); - classMapping.setMethodName(obf.getName(), obf.getSignature(), deobfName); - } - - public void removeMethodTreeMapping(MethodEntry obf) { - for (MethodEntry implementation : m_index.getRelatedMethodImplementations(obf)) { - removeMethodMapping(implementation); - } - } - - public void removeMethodMapping(MethodEntry obf) { - ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry()); - classMapping.setMethodName(obf.getName(), obf.getSignature(), null); - } - - public void markMethodTreeAsDeobfuscated(MethodEntry obf) { - for (MethodEntry implementation : m_index.getRelatedMethodImplementations(obf)) { - markMethodAsDeobfuscated(implementation); - } - } - - public void markMethodAsDeobfuscated(MethodEntry obf) { - ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry()); - classMapping.setMethodName(obf.getName(), obf.getSignature(), obf.getName()); - } - - public void setArgumentName(ArgumentEntry obf, String deobfName) { - deobfName = NameValidator.validateArgumentName(deobfName); - // NOTE: don't need to check arguments for name collisions with names determined by Procyon - if (m_mappings.containsArgument(obf.getBehaviorEntry(), deobfName)) { - throw new IllegalNameException(deobfName, "There is already an argument with that name"); - } - - ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry()); - classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), deobfName); - } - - public void removeArgumentMapping(ArgumentEntry obf) { - ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry()); - classMapping.removeArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex()); - } - - public void markArgumentAsDeobfuscated(ArgumentEntry obf) { - ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry()); - classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), obf.getName()); - } - - public boolean moveFieldToObfClass(ClassMapping classMapping, FieldMapping fieldMapping, ClassEntry obfClass) { - classMapping.removeFieldMapping(fieldMapping); - ClassMapping targetClassMapping = getOrCreateClassMapping(obfClass); - if (!targetClassMapping.containsObfField(fieldMapping.getObfName(), fieldMapping.getObfType())) { - if (!targetClassMapping.containsDeobfField(fieldMapping.getDeobfName(), fieldMapping.getObfType())) { - targetClassMapping.addFieldMapping(fieldMapping); - return true; - } else { - System.err.println("WARNING: deobf field was already there: " + obfClass + "." + fieldMapping.getDeobfName()); - } - } - return false; - } - - public boolean moveMethodToObfClass(ClassMapping classMapping, MethodMapping methodMapping, ClassEntry obfClass) { - classMapping.removeMethodMapping(methodMapping); - ClassMapping targetClassMapping = getOrCreateClassMapping(obfClass); - if (!targetClassMapping.containsObfMethod(methodMapping.getObfName(), methodMapping.getObfSignature())) { - if (!targetClassMapping.containsDeobfMethod(methodMapping.getDeobfName(), methodMapping.getObfSignature())) { - targetClassMapping.addMethodMapping(methodMapping); - return true; - } else { - System.err.println("WARNING: deobf method was already there: " + obfClass + "." + methodMapping.getDeobfName() + methodMapping.getObfSignature()); - } - } - return false; - } - - public void write(OutputStream out) throws IOException { - // TEMP: just use the object output for now. We can find a more efficient storage format later - GZIPOutputStream gzipout = new GZIPOutputStream(out); - ObjectOutputStream oout = new ObjectOutputStream(gzipout); - oout.writeObject(this); - gzipout.finish(); - } - - private ClassMapping getOrCreateClassMapping(ClassEntry obfClassEntry) { - List mappingChain = getOrCreateClassMappingChain(obfClassEntry); - return mappingChain.get(mappingChain.size() - 1); - } - - private List getOrCreateClassMappingChain(ClassEntry obfClassEntry) { - List classChain = obfClassEntry.getClassChain(); - List mappingChain = m_mappings.getClassMappingChain(obfClassEntry); - for (int i=0; i> List sorted(Iterable classes) { - List out = new ArrayList(); - for (T t : classes) { - out.add(t); - } - Collections.sort(out); - return out; - } - - private String getIndent(int depth) { - StringBuilder buf = new StringBuilder(); - for (int i = 0; i < depth; i++) { - buf.append("\t"); - } - return buf.toString(); - } -} diff --git a/src/cuchaz/enigma/mapping/MemberMapping.java b/src/cuchaz/enigma/mapping/MemberMapping.java deleted file mode 100644 index 83782975..00000000 --- a/src/cuchaz/enigma/mapping/MemberMapping.java +++ /dev/null @@ -1,17 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - - -public interface MemberMapping { - T getObfEntry(ClassEntry classEntry); - String getObfName(); -} diff --git a/src/cuchaz/enigma/mapping/MethodEntry.java b/src/cuchaz/enigma/mapping/MethodEntry.java deleted file mode 100644 index eb9e2043..00000000 --- a/src/cuchaz/enigma/mapping/MethodEntry.java +++ /dev/null @@ -1,104 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -import java.io.Serializable; - -import cuchaz.enigma.Util; - -public class MethodEntry implements BehaviorEntry, Serializable { - - private static final long serialVersionUID = 4770915224467247458L; - - private ClassEntry m_classEntry; - private String m_name; - private Signature m_signature; - - public MethodEntry(ClassEntry classEntry, String name, Signature signature) { - if (classEntry == null) { - throw new IllegalArgumentException("Class cannot be null!"); - } - if (name == null) { - throw new IllegalArgumentException("Method name cannot be null!"); - } - if (signature == null) { - throw new IllegalArgumentException("Method signature cannot be null!"); - } - if (name.startsWith("<")) { - throw new IllegalArgumentException("Don't use MethodEntry for a constructor!"); - } - - m_classEntry = classEntry; - m_name = name; - m_signature = signature; - } - - public MethodEntry(MethodEntry other) { - m_classEntry = new ClassEntry(other.m_classEntry); - m_name = other.m_name; - m_signature = other.m_signature; - } - - public MethodEntry(MethodEntry other, String newClassName) { - m_classEntry = new ClassEntry(newClassName); - m_name = other.m_name; - m_signature = other.m_signature; - } - - @Override - public ClassEntry getClassEntry() { - return m_classEntry; - } - - @Override - public String getName() { - return m_name; - } - - @Override - public Signature getSignature() { - return m_signature; - } - - @Override - public String getClassName() { - return m_classEntry.getName(); - } - - @Override - public MethodEntry cloneToNewClass(ClassEntry classEntry) { - return new MethodEntry(this, classEntry.getName()); - } - - @Override - public int hashCode() { - return Util.combineHashesOrdered(m_classEntry, m_name, m_signature); - } - - @Override - public boolean equals(Object other) { - if (other instanceof MethodEntry) { - return equals((MethodEntry)other); - } - return false; - } - - public boolean equals(MethodEntry other) { - return m_classEntry.equals(other.m_classEntry) - && m_name.equals(other.m_name) - && m_signature.equals(other.m_signature); - } - - @Override - public String toString() { - return m_classEntry.getName() + "." + m_name + m_signature; - } -} diff --git a/src/cuchaz/enigma/mapping/MethodMapping.java b/src/cuchaz/enigma/mapping/MethodMapping.java deleted file mode 100644 index 055e1fe1..00000000 --- a/src/cuchaz/enigma/mapping/MethodMapping.java +++ /dev/null @@ -1,191 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -import java.io.Serializable; -import java.util.Map; -import java.util.Map.Entry; - -import com.google.common.collect.Maps; - -public class MethodMapping implements Serializable, Comparable, MemberMapping { - - private static final long serialVersionUID = -4409570216084263978L; - - private String m_obfName; - private String m_deobfName; - private Signature m_obfSignature; - private Map m_arguments; - - public MethodMapping(String obfName, Signature obfSignature) { - this(obfName, obfSignature, null); - } - - public MethodMapping(String obfName, Signature obfSignature, String deobfName) { - if (obfName == null) { - throw new IllegalArgumentException("obf name cannot be null!"); - } - if (obfSignature == null) { - throw new IllegalArgumentException("obf signature cannot be null!"); - } - m_obfName = obfName; - m_deobfName = NameValidator.validateMethodName(deobfName); - m_obfSignature = obfSignature; - m_arguments = Maps.newTreeMap(); - } - - public MethodMapping(MethodMapping other, ClassNameReplacer obfClassNameReplacer) { - m_obfName = other.m_obfName; - m_deobfName = other.m_deobfName; - m_obfSignature = new Signature(other.m_obfSignature, obfClassNameReplacer); - m_arguments = Maps.newTreeMap(); - for (Entry entry : other.m_arguments.entrySet()) { - m_arguments.put(entry.getKey(), new ArgumentMapping(entry.getValue())); - } - } - - @Override - public String getObfName() { - return m_obfName; - } - - public void setObfName(String val) { - m_obfName = NameValidator.validateMethodName(val); - } - - public String getDeobfName() { - return m_deobfName; - } - - public void setDeobfName(String val) { - m_deobfName = NameValidator.validateMethodName(val); - } - - public Signature getObfSignature() { - return m_obfSignature; - } - - public void setObfSignature(Signature val) { - m_obfSignature = val; - } - - public Iterable arguments() { - return m_arguments.values(); - } - - public boolean isConstructor() { - return m_obfName.startsWith("<"); - } - - public void addArgumentMapping(ArgumentMapping argumentMapping) { - boolean wasAdded = m_arguments.put(argumentMapping.getIndex(), argumentMapping) == null; - assert (wasAdded); - } - - public String getObfArgumentName(int index) { - ArgumentMapping argumentMapping = m_arguments.get(index); - if (argumentMapping != null) { - return argumentMapping.getName(); - } - - return null; - } - - public String getDeobfArgumentName(int index) { - ArgumentMapping argumentMapping = m_arguments.get(index); - if (argumentMapping != null) { - return argumentMapping.getName(); - } - - return null; - } - - public void setArgumentName(int index, String name) { - ArgumentMapping argumentMapping = m_arguments.get(index); - if (argumentMapping == null) { - argumentMapping = new ArgumentMapping(index, name); - boolean wasAdded = m_arguments.put(index, argumentMapping) == null; - assert (wasAdded); - } else { - argumentMapping.setName(name); - } - } - - public void removeArgumentName(int index) { - boolean wasRemoved = m_arguments.remove(index) != null; - assert (wasRemoved); - } - - @Override - public String toString() { - StringBuilder buf = new StringBuilder(); - buf.append("\t"); - buf.append(m_obfName); - buf.append(" <-> "); - buf.append(m_deobfName); - buf.append("\n"); - buf.append("\t"); - buf.append(m_obfSignature); - buf.append("\n"); - buf.append("\tArguments:\n"); - for (ArgumentMapping argumentMapping : m_arguments.values()) { - buf.append("\t\t"); - buf.append(argumentMapping.getIndex()); - buf.append(" -> "); - buf.append(argumentMapping.getName()); - buf.append("\n"); - } - return buf.toString(); - } - - @Override - public int compareTo(MethodMapping other) { - return (m_obfName + m_obfSignature).compareTo(other.m_obfName + other.m_obfSignature); - } - - public boolean renameObfClass(final String oldObfClassName, final String newObfClassName) { - - // rename obf classes in the signature - Signature newSignature = new Signature(m_obfSignature, new ClassNameReplacer() { - @Override - public String replace(String className) { - if (className.equals(oldObfClassName)) { - return newObfClassName; - } - return null; - } - }); - - if (!newSignature.equals(m_obfSignature)) { - m_obfSignature = newSignature; - return true; - } - return false; - } - - public boolean containsArgument(String name) { - for (ArgumentMapping argumentMapping : m_arguments.values()) { - if (argumentMapping.getName().equals(name)) { - return true; - } - } - return false; - } - - @Override - public BehaviorEntry getObfEntry(ClassEntry classEntry) { - if (isConstructor()) { - return new ConstructorEntry(classEntry, m_obfSignature); - } else { - return new MethodEntry(classEntry, m_obfName, m_obfSignature); - } - } -} diff --git a/src/cuchaz/enigma/mapping/NameValidator.java b/src/cuchaz/enigma/mapping/NameValidator.java deleted file mode 100644 index 12520e12..00000000 --- a/src/cuchaz/enigma/mapping/NameValidator.java +++ /dev/null @@ -1,80 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -import java.util.Arrays; -import java.util.List; -import java.util.regex.Pattern; - -import javassist.bytecode.Descriptor; - -public class NameValidator { - - private static final Pattern IdentifierPattern; - private static final Pattern ClassPattern; - private static final List ReservedWords = Arrays.asList( - "abstract", "continue", "for", "new", "switch", "assert", "default", "goto", "package", "synchronized", - "boolean", "do", "if", "private", "this", "break", "double", "implements", "protected", "throw", "byte", - "else", "import", "public", "throws", "case", "enum", "instanceof", "return", "transient", "catch", - "extends", "int", "short", "try", "char", "final", "interface", "static", "void", "class", "finally", - "long", "strictfp", "volatile", "const", "float", "native", "super", "while" - ); - - static { - - // java allows all kinds of weird characters... - StringBuilder startChars = new StringBuilder(); - StringBuilder partChars = new StringBuilder(); - for (int i = Character.MIN_CODE_POINT; i <= Character.MAX_CODE_POINT; i++) { - if (Character.isJavaIdentifierStart(i)) { - startChars.appendCodePoint(i); - } - if (Character.isJavaIdentifierPart(i)) { - partChars.appendCodePoint(i); - } - } - - String identifierRegex = "[A-Za-z_<][A-Za-z0-9_>]*"; - IdentifierPattern = Pattern.compile(identifierRegex); - ClassPattern = Pattern.compile(String.format("^(%s(\\.|/))*(%s)$", identifierRegex, identifierRegex)); - } - - public static String validateClassName(String name, boolean packageRequired) { - if (name == null) { - return null; - } - if (!ClassPattern.matcher(name).matches() || ReservedWords.contains(name)) { - throw new IllegalNameException(name, "This doesn't look like a legal class name"); - } - if (packageRequired && new ClassEntry(name).getPackageName() == null) { - throw new IllegalNameException(name, "Class must be in a package"); - } - return Descriptor.toJvmName(name); - } - - public static String validateFieldName(String name) { - if (name == null) { - return null; - } - if (!IdentifierPattern.matcher(name).matches() || ReservedWords.contains(name)) { - throw new IllegalNameException(name, "This doesn't look like a legal identifier"); - } - return name; - } - - public static String validateMethodName(String name) { - return validateFieldName(name); - } - - public static String validateArgumentName(String name) { - return validateFieldName(name); - } -} diff --git a/src/cuchaz/enigma/mapping/ProcyonEntryFactory.java b/src/cuchaz/enigma/mapping/ProcyonEntryFactory.java deleted file mode 100644 index 777a12e4..00000000 --- a/src/cuchaz/enigma/mapping/ProcyonEntryFactory.java +++ /dev/null @@ -1,55 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -import com.strobel.assembler.metadata.FieldDefinition; -import com.strobel.assembler.metadata.MethodDefinition; - - -public class ProcyonEntryFactory { - - public static FieldEntry getFieldEntry(FieldDefinition def) { - return new FieldEntry( - new ClassEntry(def.getDeclaringType().getInternalName()), - def.getName(), - new Type(def.getErasedSignature()) - ); - } - - public static MethodEntry getMethodEntry(MethodDefinition def) { - return new MethodEntry( - new ClassEntry(def.getDeclaringType().getInternalName()), - def.getName(), - new Signature(def.getErasedSignature()) - ); - } - - public static ConstructorEntry getConstructorEntry(MethodDefinition def) { - if (def.isTypeInitializer()) { - return new ConstructorEntry( - new ClassEntry(def.getDeclaringType().getInternalName()) - ); - } else { - return new ConstructorEntry( - new ClassEntry(def.getDeclaringType().getInternalName()), - new Signature(def.getErasedSignature()) - ); - } - } - - public static BehaviorEntry getBehaviorEntry(MethodDefinition def) { - if (def.isConstructor() || def.isTypeInitializer()) { - return getConstructorEntry(def); - } else { - return getMethodEntry(def); - } - } -} diff --git a/src/cuchaz/enigma/mapping/Signature.java b/src/cuchaz/enigma/mapping/Signature.java deleted file mode 100644 index 8f2b6b2e..00000000 --- a/src/cuchaz/enigma/mapping/Signature.java +++ /dev/null @@ -1,117 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -import java.io.Serializable; -import java.util.List; - -import com.google.common.collect.Lists; - -import cuchaz.enigma.Util; - -public class Signature implements Serializable { - - private static final long serialVersionUID = -5843719505729497539L; - - private List m_argumentTypes; - private Type m_returnType; - - public Signature(String signature) { - try { - m_argumentTypes = Lists.newArrayList(); - int i=0; - while (i getArgumentTypes() { - return m_argumentTypes; - } - - public Type getReturnType() { - return m_returnType; - } - - @Override - public String toString() { - StringBuilder buf = new StringBuilder(); - buf.append("("); - for (Type type : m_argumentTypes) { - buf.append(type.toString()); - } - buf.append(")"); - buf.append(m_returnType.toString()); - return buf.toString(); - } - - public Iterable types() { - List types = Lists.newArrayList(); - types.addAll(m_argumentTypes); - types.add(m_returnType); - return types; - } - - @Override - public boolean equals(Object other) { - if (other instanceof Signature) { - return equals((Signature)other); - } - return false; - } - - public boolean equals(Signature other) { - return m_argumentTypes.equals(other.m_argumentTypes) && m_returnType.equals(other.m_returnType); - } - - @Override - public int hashCode() { - return Util.combineHashesOrdered(m_argumentTypes.hashCode(), m_returnType.hashCode()); - } - - public boolean hasClass(ClassEntry classEntry) { - for (Type type : types()) { - if (type.hasClass() && type.getClassEntry().equals(classEntry)) { - return true; - } - } - return false; - } -} diff --git a/src/cuchaz/enigma/mapping/SignatureUpdater.java b/src/cuchaz/enigma/mapping/SignatureUpdater.java deleted file mode 100644 index eb53233e..00000000 --- a/src/cuchaz/enigma/mapping/SignatureUpdater.java +++ /dev/null @@ -1,94 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -import java.io.IOException; -import java.io.StringReader; -import java.util.List; - -import com.google.common.collect.Lists; - -public class SignatureUpdater { - - public interface ClassNameUpdater { - String update(String className); - } - - public static String update(String signature, ClassNameUpdater updater) { - try { - StringBuilder buf = new StringBuilder(); - - // read the signature character-by-character - StringReader reader = new StringReader(signature); - int i = -1; - while ( (i = reader.read()) != -1) { - char c = (char)i; - - // does this character start a class name? - if (c == 'L') { - // update the class name and add it to the buffer - buf.append('L'); - String className = readClass(reader); - if (className == null) { - throw new IllegalArgumentException("Malformed signature: " + signature); - } - buf.append(updater.update(className)); - buf.append(';'); - } else { - // copy the character into the buffer - buf.append(c); - } - } - - return buf.toString(); - } catch (IOException ex) { - // I'm pretty sure a StringReader will never throw one of these - throw new Error(ex); - } - } - - private static String readClass(StringReader reader) throws IOException { - // read all the characters in the buffer until we hit a ';' - // remember to treat generics correctly - StringBuilder buf = new StringBuilder(); - int depth = 0; - int i = -1; - while ( (i = reader.read()) != -1) { - char c = (char)i; - - if (c == '<') { - depth++; - } else if (c == '>') { - depth--; - } else if (depth == 0) { - if (c == ';') { - return buf.toString(); - } else { - buf.append(c); - } - } - } - - return null; - } - - public static List getClasses(String signature) { - final List classNames = Lists.newArrayList(); - update(signature, new ClassNameUpdater() { - @Override - public String update(String className) { - classNames.add(className); - return className; - } - }); - return classNames; - } -} diff --git a/src/cuchaz/enigma/mapping/TranslationDirection.java b/src/cuchaz/enigma/mapping/TranslationDirection.java deleted file mode 100644 index bc3aaa13..00000000 --- a/src/cuchaz/enigma/mapping/TranslationDirection.java +++ /dev/null @@ -1,29 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -public enum TranslationDirection { - - Deobfuscating { - @Override - public T choose(T deobfChoice, T obfChoice) { - return deobfChoice; - } - }, - Obfuscating { - @Override - public T choose(T deobfChoice, T obfChoice) { - return obfChoice; - } - }; - - public abstract T choose(T deobfChoice, T obfChoice); -} diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java deleted file mode 100644 index 41c7d7cc..00000000 --- a/src/cuchaz/enigma/mapping/Translator.java +++ /dev/null @@ -1,289 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Lesser General Public - * License v3.0 which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/lgpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.mapping; - -import java.util.List; -import java.util.Map; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - -import cuchaz.enigma.analysis.TranslationIndex; - -public class Translator { - - private TranslationDirection m_direction; - private Map m_classes; - private TranslationIndex m_index; - - private ClassNameReplacer m_classNameReplacer = new ClassNameReplacer() { - @Override - public String replace(String className) { - return translateEntry(new ClassEntry(className)).getName(); - } - }; - - public Translator() { - m_direction = null; - m_classes = Maps.newHashMap(); - m_index = new TranslationIndex(); - } - - public Translator(TranslationDirection direction, Map classes, TranslationIndex index) { - m_direction = direction; - m_classes = classes; - m_index = index; - } - - public TranslationDirection getDirection() { - return m_direction; - } - - public TranslationIndex getTranslationIndex() { - return m_index; - } - - @SuppressWarnings("unchecked") - public T translateEntry(T entry) { - if (entry instanceof ClassEntry) { - return (T)translateEntry((ClassEntry)entry); - } else if (entry instanceof FieldEntry) { - return (T)translateEntry((FieldEntry)entry); - } else if (entry instanceof MethodEntry) { - return (T)translateEntry((MethodEntry)entry); - } else if (entry instanceof ConstructorEntry) { - return (T)translateEntry((ConstructorEntry)entry); - } else if (entry instanceof ArgumentEntry) { - return (T)translateEntry((ArgumentEntry)entry); - } else { - throw new Error("Unknown entry type: " + entry.getClass().getName()); - } - } - - public String translate(T entry) { - if (entry instanceof ClassEntry) { - return translate((ClassEntry)entry); - } else if (entry instanceof FieldEntry) { - return translate((FieldEntry)entry); - } else if (entry instanceof MethodEntry) { - return translate((MethodEntry)entry); - } else if (entry instanceof ConstructorEntry) { - return translate((ConstructorEntry)entry); - } else if (entry instanceof ArgumentEntry) { - return translate((ArgumentEntry)entry); - } else { - throw new Error("Unknown entry type: " + entry.getClass().getName()); - } - } - - public String translate(ClassEntry in) { - ClassEntry translated = translateEntry(in); - if (translated.equals(in)) { - return null; - } - return translated.getName(); - } - - public String translateClass(String className) { - return translate(new ClassEntry(className)); - } - - public ClassEntry translateEntry(ClassEntry in) { - - if (in.isInnerClass()) { - - // translate as much of the class chain as we can - List mappingsChain = getClassMappingChain(in); - String[] obfClassNames = in.getName().split("\\$"); - StringBuilder buf = new StringBuilder(); - for (int i=0; i mappingChain = getClassMappingChain(in); - return mappingChain.get(mappingChain.size() - 1); - } - - private List getClassMappingChain(ClassEntry in) { - - // get a list of all the classes in the hierarchy - String[] parts = in.getName().split("\\$"); - List mappingsChain = Lists.newArrayList(); - - // get mappings for the outer class - ClassMapping outerClassMapping = m_classes.get(parts[0]); - mappingsChain.add(outerClassMapping); - - for (int i=1; i m_lookup; - - static { - m_lookup = Maps.newTreeMap(); - for (Primitive val : values()) { - m_lookup.put(val.getCode(), val); - } - } - - public static Primitive get(char code) { - return m_lookup.get(code); - } - - private char m_code; - - private Primitive(char code) { - m_code = code; - } - - public char getCode() { - return m_code; - } - } - - public static String parseFirst(String in) { - - if (in == null || in.length() <= 0) { - throw new IllegalArgumentException("No type to parse, input is empty!"); - } - - // read one type from the input - - char c = in.charAt(0); - - // first check for void - if (c == 'V') { - return "V"; - } - - // then check for primitives - Primitive primitive = Primitive.get(c); - if (primitive != null) { - return in.substring(0, 1); - } - - // then check for classes - if (c == 'L') { - return readClass(in); - } - - // then check for templates - if (c == 'T') { - return readClass(in); - } - - // then check for arrays - int dim = countArrayDimension(in); - if (dim > 0) { - String arrayType = Type.parseFirst(in.substring(dim)); - return in.substring(0, dim + arrayType.length()); - } - - throw new IllegalArgumentException("don't know how to parse: " + in); - } - - protected String m_name; - - public Type(String name) { - - // don't deal with generics - // this is just for raw jvm types - if (name.charAt(0) == 'T' || name.indexOf('<') >= 0 || name.indexOf('>') >= 0) { - throw new IllegalArgumentException("don't use with generic types or templates: " + name); - } - - m_name = name; - } - - public Type(Type other) { - m_name = other.m_name; - } - - public Type(ClassEntry classEntry) { - m_name = "L" + classEntry.getClassName() + ";"; - } - - public Type(Type other, ClassNameReplacer replacer) { - m_name = other.m_name; - if (other.isClass()) { - String replacedName = replacer.replace(other.getClassEntry().getClassName()); - if (replacedName != null) { - m_name = "L" + replacedName + ";"; - } - } else if (other.isArray() && other.hasClass()) { - String replacedName = replacer.replace(other.getClassEntry().getClassName()); - if (replacedName != null) { - m_name = Type.getArrayPrefix(other.getArrayDimension()) + "L" + replacedName + ";"; - } - } - } - - @Override - public String toString() { - return m_name; - } - - public boolean isVoid() { - return m_name.length() == 1 && m_name.charAt(0) == 'V'; - } - - public boolean isPrimitive() { - return m_name.length() == 1 && Primitive.get(m_name.charAt(0)) != null; - } - - public Primitive getPrimitive() { - if (!isPrimitive()) { - throw new IllegalStateException("not a primitive"); - } - return Primitive.get(m_name.charAt(0)); - } - - public boolean isClass() { - return m_name.charAt(0) == 'L' && m_name.charAt(m_name.length() - 1) == ';'; - } - - public ClassEntry getClassEntry() { - if (isClass()) { - String name = m_name.substring(1, m_name.length() - 1); - - int pos = name.indexOf('<'); - if (pos >= 0) { - // remove the parameters from the class name - name = name.substring(0, pos); - } - - return new ClassEntry(name); - - } else if (isArray() && getArrayType().isClass()) { - return getArrayType().getClassEntry(); - } else { - throw new IllegalStateException("type doesn't have a class"); - } - } - - public boolean isArray() { - return m_name.charAt(0) == '['; - } - - public int getArrayDimension() { - if (!isArray()) { - throw new IllegalStateException("not an array"); - } - return countArrayDimension(m_name); - } - - public Type getArrayType() { - if (!isArray()) { - throw new IllegalStateException("not an array"); - } - return new Type(m_name.substring(getArrayDimension(), m_name.length())); - } - - private static String getArrayPrefix(int dimension) { - StringBuilder buf = new StringBuilder(); - for (int i=0; i') { - depth--; - } else if (depth == 0 && c == ';') { - return buf.toString(); - } - } - return null; - } -} -- cgit v1.2.3