From 59e189bef2b5e6d129fb7c2c988ed0b2130e36ac Mon Sep 17 00:00:00 2001 From: lclc98 Date: Mon, 4 Jul 2016 18:14:22 +1000 Subject: Reformat --- src/main/java/cuchaz/enigma/CommandMain.java | 43 +- src/main/java/cuchaz/enigma/ConvertMain.java | 348 ------------- src/main/java/cuchaz/enigma/Deobfuscator.java | 120 +++-- .../java/cuchaz/enigma/MainFormatConverter.java | 113 ----- .../java/cuchaz/enigma/TranslatingTypeLoader.java | 76 ++- .../enigma/analysis/BehaviorReferenceTreeNode.java | 2 - .../analysis/ClassImplementationsTreeNode.java | 2 - .../enigma/analysis/ClassInheritanceTreeNode.java | 2 - .../cuchaz/enigma/analysis/EntryReference.java | 4 +- .../java/cuchaz/enigma/analysis/EntryRenamer.java | 52 +- .../enigma/analysis/FieldReferenceTreeNode.java | 2 - .../cuchaz/enigma/analysis/JarClassIterator.java | 8 - src/main/java/cuchaz/enigma/analysis/JarIndex.java | 8 - .../analysis/MethodImplementationsTreeNode.java | 2 - .../enigma/analysis/MethodInheritanceTreeNode.java | 2 - .../java/cuchaz/enigma/analysis/SourceIndex.java | 4 - src/main/java/cuchaz/enigma/analysis/Token.java | 4 - .../cuchaz/enigma/analysis/TranslationIndex.java | 41 +- .../cuchaz/enigma/bytecode/CheckCastIterator.java | 113 ----- .../cuchaz/enigma/bytecode/ConstPoolEditor.java | 26 - src/main/java/cuchaz/enigma/bytecode/InfoType.java | 62 +-- .../bytecode/accessors/ConstInfoAccessor.java | 47 +- .../java/cuchaz/enigma/convert/ClassForest.java | 54 --- .../cuchaz/enigma/convert/ClassIdentifier.java | 54 --- .../java/cuchaz/enigma/convert/ClassIdentity.java | 441 ----------------- .../java/cuchaz/enigma/convert/ClassMatch.java | 84 ---- .../java/cuchaz/enigma/convert/ClassMatches.java | 149 ------ .../java/cuchaz/enigma/convert/ClassMatching.java | 146 ------ .../java/cuchaz/enigma/convert/ClassNamer.java | 56 --- .../cuchaz/enigma/convert/MappingsConverter.java | 540 --------------------- .../java/cuchaz/enigma/convert/MatchesReader.java | 104 ---- .../java/cuchaz/enigma/convert/MatchesWriter.java | 121 ----- .../java/cuchaz/enigma/convert/MemberMatches.java | 143 ------ .../cuchaz/enigma/gui/BoxHighlightPainter.java | 64 --- src/main/java/cuchaz/enigma/gui/BrowserCaret.java | 2 - .../java/cuchaz/enigma/gui/ClassMatchingGui.java | 521 -------------------- src/main/java/cuchaz/enigma/gui/ClassSelector.java | 143 ++---- .../cuchaz/enigma/gui/ClassSelectorClassNode.java | 47 -- .../enigma/gui/ClassSelectorPackageNode.java | 42 -- src/main/java/cuchaz/enigma/gui/CodeReader.java | 202 -------- .../enigma/gui/DeobfuscatedHighlightPainter.java | 20 - src/main/java/cuchaz/enigma/gui/Gui.java | 20 +- src/main/java/cuchaz/enigma/gui/GuiController.java | 4 +- src/main/java/cuchaz/enigma/gui/GuiTricks.java | 52 -- .../java/cuchaz/enigma/gui/MemberMatchingGui.java | 442 ----------------- .../enigma/gui/ObfuscatedHighlightPainter.java | 20 - .../cuchaz/enigma/gui/OtherHighlightPainter.java | 20 - src/main/java/cuchaz/enigma/gui/ReadableToken.java | 36 -- .../java/cuchaz/enigma/gui/ScoredClassEntry.java | 29 -- .../enigma/gui/SelectionHighlightPainter.java | 29 -- .../java/cuchaz/enigma/gui/dialog/AboutDialog.java | 6 +- .../java/cuchaz/enigma/gui/dialog/CrashDialog.java | 4 +- .../cuchaz/enigma/gui/dialog/ProgressDialog.java | 4 +- .../java/cuchaz/enigma/gui/elements/MenuBar.java | 4 +- .../enigma/gui/filechooser/FileChooserFolder.java | 2 +- .../enigma/gui/highlight/BoxHighlightPainter.java | 64 +++ .../highlight/DeobfuscatedHighlightPainter.java | 20 + .../gui/highlight/ObfuscatedHighlightPainter.java | 20 + .../gui/highlight/OtherHighlightPainter.java | 20 + .../gui/highlight/SelectionHighlightPainter.java | 29 ++ .../enigma/gui/node/ClassSelectorClassNode.java | 42 ++ .../enigma/gui/node/ClassSelectorPackageNode.java | 36 ++ .../java/cuchaz/enigma/gui/panels/PanelDeobf.java | 1 - .../cuchaz/enigma/gui/panels/PanelIdentifier.java | 4 +- .../java/cuchaz/enigma/gui/panels/PanelObf.java | 2 +- .../java/cuchaz/enigma/mapping/ArgumentEntry.java | 56 +-- .../cuchaz/enigma/mapping/ArgumentMapping.java | 27 +- .../java/cuchaz/enigma/mapping/ClassEntry.java | 45 +- .../java/cuchaz/enigma/mapping/ClassMapping.java | 46 +- .../cuchaz/enigma/mapping/ConstructorEntry.java | 45 +- .../java/cuchaz/enigma/mapping/EntryFactory.java | 36 +- .../java/cuchaz/enigma/mapping/FieldEntry.java | 46 +- .../java/cuchaz/enigma/mapping/FieldMapping.java | 42 +- .../enigma/mapping/IllegalNameException.java | 44 -- .../enigma/mapping/MappingParseException.java | 29 -- src/main/java/cuchaz/enigma/mapping/Mappings.java | 83 ++-- .../cuchaz/enigma/mapping/MappingsChecker.java | 44 +- .../java/cuchaz/enigma/mapping/MappingsReader.java | 41 +- .../cuchaz/enigma/mapping/MappingsReaderOld.java | 5 + .../cuchaz/enigma/mapping/MappingsRenamer.java | 26 +- .../java/cuchaz/enigma/mapping/MappingsWriter.java | 15 +- .../java/cuchaz/enigma/mapping/MemberMapping.java | 2 - .../java/cuchaz/enigma/mapping/MethodEntry.java | 46 +- .../java/cuchaz/enigma/mapping/MethodMapping.java | 93 ++-- .../java/cuchaz/enigma/mapping/NameValidator.java | 1 + .../cuchaz/enigma/mapping/ProcyonEntryFactory.java | 22 +- src/main/java/cuchaz/enigma/mapping/Signature.java | 50 +- .../cuchaz/enigma/mapping/SignatureUpdater.java | 82 ---- .../java/cuchaz/enigma/mapping/Translator.java | 48 +- src/main/java/cuchaz/enigma/mapping/Type.java | 62 +-- .../enigma/throwables/IllegalNameException.java | 38 ++ .../cuchaz/enigma/throwables/MappingConflict.java | 7 + .../enigma/throwables/MappingParseException.java | 27 ++ .../java/cuchaz/enigma/utils/ReadableToken.java | 36 ++ src/main/java/cuchaz/enigma/utils/Utils.java | 134 +++++ 95 files changed, 996 insertions(+), 5206 deletions(-) delete mode 100644 src/main/java/cuchaz/enigma/ConvertMain.java delete mode 100644 src/main/java/cuchaz/enigma/MainFormatConverter.java delete mode 100644 src/main/java/cuchaz/enigma/bytecode/CheckCastIterator.java delete mode 100644 src/main/java/cuchaz/enigma/convert/ClassForest.java delete mode 100644 src/main/java/cuchaz/enigma/convert/ClassIdentifier.java delete mode 100644 src/main/java/cuchaz/enigma/convert/ClassIdentity.java delete mode 100644 src/main/java/cuchaz/enigma/convert/ClassMatch.java delete mode 100644 src/main/java/cuchaz/enigma/convert/ClassMatches.java delete mode 100644 src/main/java/cuchaz/enigma/convert/ClassMatching.java delete mode 100644 src/main/java/cuchaz/enigma/convert/ClassNamer.java delete mode 100644 src/main/java/cuchaz/enigma/convert/MappingsConverter.java delete mode 100644 src/main/java/cuchaz/enigma/convert/MatchesReader.java delete mode 100644 src/main/java/cuchaz/enigma/convert/MatchesWriter.java delete mode 100644 src/main/java/cuchaz/enigma/convert/MemberMatches.java delete mode 100644 src/main/java/cuchaz/enigma/gui/BoxHighlightPainter.java delete mode 100644 src/main/java/cuchaz/enigma/gui/ClassMatchingGui.java delete mode 100644 src/main/java/cuchaz/enigma/gui/ClassSelectorClassNode.java delete mode 100644 src/main/java/cuchaz/enigma/gui/ClassSelectorPackageNode.java delete mode 100644 src/main/java/cuchaz/enigma/gui/CodeReader.java delete mode 100644 src/main/java/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java delete mode 100644 src/main/java/cuchaz/enigma/gui/GuiTricks.java delete mode 100644 src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java delete mode 100644 src/main/java/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java delete mode 100644 src/main/java/cuchaz/enigma/gui/OtherHighlightPainter.java delete mode 100644 src/main/java/cuchaz/enigma/gui/ReadableToken.java delete mode 100644 src/main/java/cuchaz/enigma/gui/ScoredClassEntry.java delete mode 100644 src/main/java/cuchaz/enigma/gui/SelectionHighlightPainter.java create mode 100644 src/main/java/cuchaz/enigma/gui/highlight/BoxHighlightPainter.java create mode 100644 src/main/java/cuchaz/enigma/gui/highlight/DeobfuscatedHighlightPainter.java create mode 100644 src/main/java/cuchaz/enigma/gui/highlight/ObfuscatedHighlightPainter.java create mode 100644 src/main/java/cuchaz/enigma/gui/highlight/OtherHighlightPainter.java create mode 100644 src/main/java/cuchaz/enigma/gui/highlight/SelectionHighlightPainter.java create mode 100644 src/main/java/cuchaz/enigma/gui/node/ClassSelectorClassNode.java create mode 100644 src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java delete mode 100644 src/main/java/cuchaz/enigma/mapping/IllegalNameException.java delete mode 100644 src/main/java/cuchaz/enigma/mapping/MappingParseException.java delete mode 100644 src/main/java/cuchaz/enigma/mapping/SignatureUpdater.java create mode 100644 src/main/java/cuchaz/enigma/throwables/IllegalNameException.java create mode 100644 src/main/java/cuchaz/enigma/throwables/MappingConflict.java create mode 100644 src/main/java/cuchaz/enigma/throwables/MappingParseException.java create mode 100644 src/main/java/cuchaz/enigma/utils/ReadableToken.java create mode 100644 src/main/java/cuchaz/enigma/utils/Utils.java diff --git a/src/main/java/cuchaz/enigma/CommandMain.java b/src/main/java/cuchaz/enigma/CommandMain.java index 8dfbe24d..d7967b46 100644 --- a/src/main/java/cuchaz/enigma/CommandMain.java +++ b/src/main/java/cuchaz/enigma/CommandMain.java @@ -23,42 +23,38 @@ public class CommandMain { private static final int ReportTime = 5000; // 5s - private int m_totalWork; - private long m_startTime; - private long m_lastReportTime; + private int totalWork; + private long startTime; + private long lastReportTime; @Override public void init(int totalWork, String title) { - m_totalWork = totalWork; - m_startTime = System.currentTimeMillis(); - m_lastReportTime = m_startTime; + this.totalWork = totalWork; + this.startTime = System.currentTimeMillis(); + this.lastReportTime = this.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; + boolean isLastUpdate = numDone == this.totalWork; + boolean shouldReport = isLastUpdate || now - this.lastReportTime > ReportTime; if (shouldReport) { - int percent = numDone * 100 / m_totalWork; + int percent = numDone * 100 / this.totalWork; System.out.println(String.format("\tProgress: %3d%%", percent)); - m_lastReportTime = now; + this.lastReportTime = now; } if (isLastUpdate) { - double elapsedSeconds = (now - m_startTime) / 1000; + double elapsedSeconds = (now - this.startTime) / 1000; System.out.println(String.format("Finished in %.1f seconds", elapsedSeconds)); } } } - public static void main(String[] args) - throws Exception { - + public static void main(String[] args) throws Exception { try { - // process the command String command = getArg(args, 0, "command", true); if (command.equalsIgnoreCase("deobfuscate")) { @@ -88,8 +84,7 @@ public class CommandMain { System.out.println("\t\tprotectify "); } - private static void decompile(String[] args) - throws Exception { + 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)); @@ -97,8 +92,7 @@ public class CommandMain { deobfuscator.writeSources(fileJarOut, new ConsoleProgressListener()); } - private static void deobfuscate(String[] args) - throws Exception { + 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)); @@ -106,24 +100,21 @@ public class CommandMain { deobfuscator.writeJar(fileJarOut, new ConsoleProgressListener()); } - private static void protectify(String[] args) - throws Exception { + 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 { + 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 { + private static Deobfuscator getDeobfuscator(File fileMappings, JarFile jar) throws Exception { System.out.println("Reading jar..."); Deobfuscator deobfuscator = new Deobfuscator(jar); if (fileMappings != null) { diff --git a/src/main/java/cuchaz/enigma/ConvertMain.java b/src/main/java/cuchaz/enigma/ConvertMain.java deleted file mode 100644 index caa61545..00000000 --- a/src/main/java/cuchaz/enigma/ConvertMain.java +++ /dev/null @@ -1,348 +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.IOException; -import java.util.jar.JarFile; - -import cuchaz.enigma.convert.*; -import cuchaz.enigma.gui.ClassMatchingGui; -import cuchaz.enigma.gui.MemberMatchingGui; -import cuchaz.enigma.mapping.*; - - -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(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(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); - new MappingsWriter().write(outMappingsFile, 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(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(destMappingsFile); - MappingsChecker checker = new MappingsChecker(deobfuscators.dest.getJarIndex()); - checker.dropBrokenMappings(destMappings); - deobfuscators.dest.setMappings(destMappings); - - new MemberMatchingGui<>(classMatches, fieldMatches, deobfuscators.source, deobfuscators.dest).setSaveListener(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 - - new MappingsWriter().write(outMappingsFile, 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(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(destMappingsFile); - MappingsChecker checker = new MappingsChecker(deobfuscators.dest.getJarIndex()); - checker.dropBrokenMappings(destMappings); - deobfuscators.dest.setMappings(destMappings); - - new MemberMatchingGui<>(classMatches, methodMatches, deobfuscators.source, deobfuscators.dest).setSaveListener(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 - new MappingsWriter().write(outMappingsFile, 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/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java index f917deb7..d22260fb 100644 --- a/src/main/java/cuchaz/enigma/Deobfuscator.java +++ b/src/main/java/cuchaz/enigma/Deobfuscator.java @@ -47,50 +47,46 @@ public class Deobfuscator { 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; + private JarFile jar; + private DecompilerSettings settings; + private JarIndex jarIndex; + private Mappings mappings; + private MappingsRenamer renamer; + private Map translatorCache; - public Deobfuscator(JarFile jar) throws IOException { - m_jar = jar; + public Deobfuscator(JarFile jar) { + this.jar = jar; // build the jar index - m_jarIndex = new JarIndex(); - m_jarIndex.indexJar(m_jar, true); + this.jarIndex = new JarIndex(); + this.jarIndex.indexJar(this.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); + this.settings = DecompilerSettings.javaDefaults(); + this.settings.setMergeVariables(true); + this.settings.setForceExplicitImports(true); + this.settings.setForceExplicitTypeArguments(true); + this.settings.setShowDebugLineNumbers(true); // DEBUG - //m_settings.setShowSyntheticMembers(true); + //this.settings.setShowSyntheticMembers(true); // init defaults - m_translatorCache = Maps.newTreeMap(); + this.translatorCache = Maps.newTreeMap(); // init mappings setMappings(new Mappings()); } - public JarFile getJar() { - return m_jar; - } - public String getJarName() { - return m_jar.getName(); + return this.jar.getName(); } public JarIndex getJarIndex() { - return m_jarIndex; + return this.jarIndex; } public Mappings getMappings() { - return m_mappings; + return this.mappings; } public void setMappings(Mappings val) { @@ -103,7 +99,7 @@ public class Deobfuscator { } // drop mappings that don't match the jar - MappingsChecker checker = new MappingsChecker(m_jarIndex); + MappingsChecker checker = new MappingsChecker(this.jarIndex); checker.dropBrokenMappings(val); if (warnAboutDrops) { for (java.util.Map.Entry mapping : checker.getDroppedClassMappings().entrySet()) { @@ -120,22 +116,22 @@ public class Deobfuscator { } } - m_mappings = val; - m_renamer = new MappingsRenamer(m_jarIndex, val); - m_translatorCache.clear(); + this.mappings = val; + this.renamer = new MappingsRenamer(this.jarIndex, val); + this.translatorCache.clear(); } public Translator getTranslator(TranslationDirection direction) { - Translator translator = m_translatorCache.get(direction); + Translator translator = this.translatorCache.get(direction); if (translator == null) { - translator = m_mappings.getTranslator(direction, m_jarIndex.getTranslationIndex()); - m_translatorCache.put(direction, translator); + translator = this.mappings.getTranslator(direction, this.jarIndex.getTranslationIndex()); + this.translatorCache.put(direction, translator); } return translator; } public void getSeparatedClasses(List obfClasses, List deobfClasses) { - for (ClassEntry obfClassEntry : m_jarIndex.getObfClassEntries()) { + for (ClassEntry obfClassEntry : this.jarIndex.getObfClassEntries()) { // skip inner classes if (obfClassEntry.isInnerClass()) { continue; @@ -166,19 +162,19 @@ public class Deobfuscator { 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); + ClassMapping classMapping = this.mappings.getClassByObf(className); if (classMapping != null && classMapping.getDeobfName() != null) { deobfClassName = classMapping.getDeobfName(); } // set the type loader TranslatingTypeLoader loader = new TranslatingTypeLoader( - m_jar, - m_jarIndex, + this.jar, + this.jarIndex, getTranslator(TranslationDirection.Obfuscating), getTranslator(TranslationDirection.Deobfuscating) ); - m_settings.setTypeLoader(loader); + this.settings.setTypeLoader(loader); // see if procyon can find the type TypeReference type = new MetadataSystem(loader).lookupType(deobfClassName); @@ -192,7 +188,7 @@ public class Deobfuscator { // decompile it! DecompilerContext context = new DecompilerContext(); context.setCurrentType(resolvedType); - context.setSettings(m_settings); + context.setSettings(this.settings); AstBuilder builder = new AstBuilder(context); builder.addType(resolvedType); builder.runTransformations(null); @@ -225,7 +221,7 @@ public class Deobfuscator { Entry obfEntry = obfuscateEntry(deobfReference.entry); // try to resolve the class - ClassEntry resolvedObfClassEntry = m_jarIndex.getTranslationIndex().resolveEntryClass(obfEntry); + ClassEntry resolvedObfClassEntry = this.jarIndex.getTranslationIndex().resolveEntryClass(obfEntry); if (resolvedObfClassEntry != null && !resolvedObfClassEntry.equals(obfEntry.getClassEntry())) { // change the class of the entry obfEntry = obfEntry.cloneToNewClass(resolvedObfClassEntry); @@ -246,14 +242,14 @@ public class Deobfuscator { // render the AST into source StringWriter buf = new StringWriter(); sourceTree.acceptVisitor(new InsertParenthesesVisitor(), null); - sourceTree.acceptVisitor(new JavaOutputVisitor(new PlainTextOutput(buf), m_settings), null); + sourceTree.acceptVisitor(new JavaOutputVisitor(new PlainTextOutput(buf), this.settings), null); return buf.toString(); } - public void writeSources(File dirOut, ProgressListener progress) throws IOException { + public void writeSources(File dirOut, ProgressListener progress) { // get the classes to decompile Set classEntries = Sets.newHashSet(); - for (ClassEntry obfClassEntry : m_jarIndex.getObfClassEntries()) { + for (ClassEntry obfClassEntry : this.jarIndex.getObfClassEntries()) { // skip inner classes if (obfClassEntry.isInnerClass()) { continue; @@ -298,8 +294,8 @@ public class Deobfuscator { public void writeJar(File out, ProgressListener progress) { final TranslatingTypeLoader loader = new TranslatingTypeLoader( - m_jar, - m_jarIndex, + this.jar, + this.jarIndex, getTranslator(TranslationDirection.Obfuscating), getTranslator(TranslationDirection.Deobfuscating) ); @@ -321,11 +317,11 @@ public class Deobfuscator { 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..."); + progress.init(JarClassIterator.getClassEntries(this.jar).size(), "Transforming classes..."); } int i = 0; - for (CtClass c : JarClassIterator.classes(m_jar)) { + for (CtClass c : JarClassIterator.classes(this.jar)) { if (progress != null) { progress.onProgress(i++, c.getName()); } @@ -410,7 +406,7 @@ public class Deobfuscator { } } - return m_jarIndex.containsObfEntry(obfEntry); + return this.jarIndex.containsObfEntry(obfEntry); } public boolean isRenameable(EntryReference obfReference) { @@ -423,7 +419,7 @@ public class Deobfuscator { Translator translator = getTranslator(TranslationDirection.Deobfuscating); if (obfEntry instanceof ClassEntry) { ClassEntry obfClass = (ClassEntry) obfEntry; - List mappingChain = m_mappings.getClassMappingChain(obfClass); + List mappingChain = this.mappings.getClassMappingChain(obfClass); ClassMapping classMapping = mappingChain.get(mappingChain.size() - 1); return classMapping != null && classMapping.getDeobfName() != null; } else if (obfEntry instanceof FieldEntry) { @@ -442,58 +438,58 @@ public class Deobfuscator { public void rename(Entry obfEntry, String newName) { if (obfEntry instanceof ClassEntry) { - m_renamer.setClassName((ClassEntry) obfEntry, Descriptor.toJvmName(newName)); + this.renamer.setClassName((ClassEntry) obfEntry, Descriptor.toJvmName(newName)); } else if (obfEntry instanceof FieldEntry) { - m_renamer.setFieldName((FieldEntry) obfEntry, newName); + this.renamer.setFieldName((FieldEntry) obfEntry, newName); } else if (obfEntry instanceof MethodEntry) { - m_renamer.setMethodTreeName((MethodEntry) obfEntry, newName); + this.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); + this.renamer.setArgumentName((ArgumentEntry) obfEntry, newName); } else { throw new Error("Unknown entry type: " + obfEntry.getClass().getName()); } // clear caches - m_translatorCache.clear(); + this.translatorCache.clear(); } public void removeMapping(Entry obfEntry) { if (obfEntry instanceof ClassEntry) { - m_renamer.removeClassMapping((ClassEntry) obfEntry); + this.renamer.removeClassMapping((ClassEntry) obfEntry); } else if (obfEntry instanceof FieldEntry) { - m_renamer.removeFieldMapping((FieldEntry) obfEntry); + this.renamer.removeFieldMapping((FieldEntry) obfEntry); } else if (obfEntry instanceof MethodEntry) { - m_renamer.removeMethodTreeMapping((MethodEntry) obfEntry); + this.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); + this.renamer.removeArgumentMapping((ArgumentEntry) obfEntry); } else { throw new Error("Unknown entry type: " + obfEntry); } // clear caches - m_translatorCache.clear(); + this.translatorCache.clear(); } public void markAsDeobfuscated(Entry obfEntry) { if (obfEntry instanceof ClassEntry) { - m_renamer.markClassAsDeobfuscated((ClassEntry) obfEntry); + this.renamer.markClassAsDeobfuscated((ClassEntry) obfEntry); } else if (obfEntry instanceof FieldEntry) { - m_renamer.markFieldAsDeobfuscated((FieldEntry) obfEntry); + this.renamer.markFieldAsDeobfuscated((FieldEntry) obfEntry); } else if (obfEntry instanceof MethodEntry) { - m_renamer.markMethodTreeAsDeobfuscated((MethodEntry) obfEntry); + this.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); + this.renamer.markArgumentAsDeobfuscated((ArgumentEntry) obfEntry); } else { throw new Error("Unknown entry type: " + obfEntry); } // clear caches - m_translatorCache.clear(); + this.translatorCache.clear(); } } diff --git a/src/main/java/cuchaz/enigma/MainFormatConverter.java b/src/main/java/cuchaz/enigma/MainFormatConverter.java deleted file mode 100644 index 4dd19ea8..00000000 --- a/src/main/java/cuchaz/enigma/MainFormatConverter.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; - -import com.google.common.collect.Maps; - -import java.io.File; -import java.lang.reflect.Field; -import java.util.Map; -import java.util.jar.JarFile; - -import cuchaz.enigma.analysis.JarClassIterator; -import cuchaz.enigma.mapping.*; -import javassist.CtClass; -import javassist.CtField; - -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 obf, String deobf, String type) { - // assume the void type for now - return new FieldMapping(obf, new Type("V"), deobf); - } - }; - Mappings mappings = mappingsReader.read(fileMappings); - - System.out.println("Updating field types..."); - - for (ClassMapping classMapping : mappings.classes()) { - updateFieldsInClass(fieldTypes, classMapping); - } - - System.out.println("Saving mappings..."); - - new MappingsWriter().write(fileMappings, mappings); - - System.out.println("Done!"); - } - - private static Type moveClasssesOutOfDefaultPackage(Type type) { - return new Type(type, className -> { - ClassEntry entry = new ClassEntry(className); - if (entry.isInDefaultPackage()) { - return Constants.NONE_PACKAGE + "/" + 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/main/java/cuchaz/enigma/TranslatingTypeLoader.java b/src/main/java/cuchaz/enigma/TranslatingTypeLoader.java index 942c8308..ad1d244d 100644 --- a/src/main/java/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/main/java/cuchaz/enigma/TranslatingTypeLoader.java @@ -35,24 +35,20 @@ import javassist.bytecode.Descriptor; 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()); - } + private JarFile jar; + private JarIndex jarIndex; + private Translator obfuscatingTranslator; + private Translator deobfuscatingTranslator; + private Map cache; + private ClasspathTypeLoader defaultTypeLoader; 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(); + this.jar = jar; + this.jarIndex = jarIndex; + this.obfuscatingTranslator = obfuscatingTranslator; + this.deobfuscatingTranslator = deobfuscatingTranslator; + this.cache = Maps.newHashMap(); + this.defaultTypeLoader = new ClasspathTypeLoader(); } @Override @@ -60,16 +56,16 @@ public class TranslatingTypeLoader implements ITypeLoader { // check the cache byte[] data; - if (m_cache.containsKey(className)) { - data = m_cache.get(className); + if (this.cache.containsKey(className)) { + data = this.cache.get(className); } else { data = loadType(className); - m_cache.put(className, data); + this.cache.put(className, data); } if (data == null) { // chain to default type loader - return m_defaultTypeLoader.tryLoadType(className, out); + return this.defaultTypeLoader.tryLoadType(className, out); } // send the class to the decompiler @@ -79,33 +75,15 @@ public class TranslatingTypeLoader implements ITypeLoader { 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); + ClassEntry obfClassEntry = this.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); + List classChain = this.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) @@ -115,7 +93,7 @@ public class TranslatingTypeLoader implements ITypeLoader { } // is this a class we should even know about? - if (!m_jarIndex.containsObfClass(obfClassEntry)) { + if (!this.jarIndex.containsObfClass(obfClassEntry)) { return null; } @@ -133,7 +111,7 @@ public class TranslatingTypeLoader implements ITypeLoader { // 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")); + InputStream in = this.jar.getInputStream(this.jar.getJarEntry(classInJarName + ".class")); while (true) { int bytesRead = in.read(buf); if (bytesRead <= 0) { @@ -170,7 +148,7 @@ public class TranslatingTypeLoader implements ITypeLoader { // try to find the class in the jar for (String className : getClassNamesToTry(obfClassEntry)) { - JarEntry jarEntry = m_jar.getJarEntry(className + ".class"); + JarEntry jarEntry = this.jar.getJarEntry(className + ".class"); if (jarEntry != null) { return className; } @@ -181,7 +159,7 @@ public class TranslatingTypeLoader implements ITypeLoader { } public List getClassNamesToTry(String className) { - return getClassNamesToTry(m_obfuscatingTranslator.translateEntry(new ClassEntry(className))); + return getClassNamesToTry(this.obfuscatingTranslator.translateEntry(new ClassEntry(className))); } public List getClassNamesToTry(ClassEntry obfClassEntry) { @@ -206,7 +184,7 @@ public class TranslatingTypeLoader implements ITypeLoader { ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NONE_PACKAGE); // reconstruct inner classes - new InnerClassWriter(m_jarIndex).write(c); + new InnerClassWriter(this.jarIndex).write(c); // re-get the javassist handle since we changed class names ClassEntry obfClassEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); @@ -219,10 +197,10 @@ public class TranslatingTypeLoader implements ITypeLoader { 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); + new BridgeMarker(this.jarIndex).markBridges(c); + new MethodParameterWriter(this.deobfuscatingTranslator).writeMethodArguments(c); + new LocalVariableRenamer(this.deobfuscatingTranslator).rename(c); + new ClassTranslator(this.deobfuscatingTranslator).translate(c); return c; } diff --git a/src/main/java/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java b/src/main/java/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java index 39ff449e..98aa12e5 100644 --- a/src/main/java/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java +++ b/src/main/java/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java @@ -23,8 +23,6 @@ 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; diff --git a/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java b/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java index b1d1dee5..f5227bb9 100644 --- a/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java +++ b/src/main/java/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java @@ -21,8 +21,6 @@ import cuchaz.enigma.mapping.Translator; public class ClassImplementationsTreeNode extends DefaultMutableTreeNode { - private static final long serialVersionUID = 3112703459157851912L; - private Translator deobfuscatingTranslator; private ClassEntry entry; diff --git a/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java b/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java index beac9d5d..8a60fc72 100644 --- a/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java +++ b/src/main/java/cuchaz/enigma/analysis/ClassInheritanceTreeNode.java @@ -21,8 +21,6 @@ import cuchaz.enigma.mapping.Translator; public class ClassInheritanceTreeNode extends DefaultMutableTreeNode { - private static final long serialVersionUID = 4432367405826178490L; - private Translator deobfuscatingTranslator; private String obfClassName; diff --git a/src/main/java/cuchaz/enigma/analysis/EntryReference.java b/src/main/java/cuchaz/enigma/analysis/EntryReference.java index 6a7a4bf0..ad4baf81 100644 --- a/src/main/java/cuchaz/enigma/analysis/EntryReference.java +++ b/src/main/java/cuchaz/enigma/analysis/EntryReference.java @@ -13,10 +13,10 @@ 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; +import cuchaz.enigma.utils.Utils; public class EntryReference { @@ -84,7 +84,7 @@ public class EntryReference { @Override public int hashCode() { if (context != null) { - return Util.combineHashesOrdered(entry.hashCode(), context.hashCode()); + return Utils.combineHashesOrdered(entry.hashCode(), context.hashCode()); } return entry.hashCode(); } diff --git a/src/main/java/cuchaz/enigma/analysis/EntryRenamer.java b/src/main/java/cuchaz/enigma/analysis/EntryRenamer.java index 9a85f6ee..f0e73062 100644 --- a/src/main/java/cuchaz/enigma/analysis/EntryRenamer.java +++ b/src/main/java/cuchaz/enigma/analysis/EntryRenamer.java @@ -56,35 +56,6 @@ public class EntryRenamer { } } - @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) { @@ -97,31 +68,16 @@ public class EntryRenamer { 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()) - ); + 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()) - ); + 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()) - ); + 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() - ); + 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); diff --git a/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java b/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java index 05d9c13f..70cd0590 100644 --- a/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java +++ b/src/main/java/cuchaz/enigma/analysis/FieldReferenceTreeNode.java @@ -18,8 +18,6 @@ import cuchaz.enigma.mapping.Translator; public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode { - private static final long serialVersionUID = -7934108091928699835L; - private Translator deobfuscatingTranslator; private FieldEntry entry; private EntryReference reference; diff --git a/src/main/java/cuchaz/enigma/analysis/JarClassIterator.java b/src/main/java/cuchaz/enigma/analysis/JarClassIterator.java index 04004270..0d18105e 100644 --- a/src/main/java/cuchaz/enigma/analysis/JarClassIterator.java +++ b/src/main/java/cuchaz/enigma/analysis/JarClassIterator.java @@ -89,14 +89,6 @@ public class JarClassIterator implements 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(); diff --git a/src/main/java/cuchaz/enigma/analysis/JarIndex.java b/src/main/java/cuchaz/enigma/analysis/JarIndex.java index bd670905..9acf0b14 100644 --- a/src/main/java/cuchaz/enigma/analysis/JarIndex.java +++ b/src/main/java/cuchaz/enigma/analysis/JarIndex.java @@ -503,14 +503,6 @@ public class JarIndex { return this.obfClassEntries; } - public Collection getObfFieldEntries() { - return this.fields.values(); - } - - public Collection getObfBehaviorEntries() { - return this.behaviors.values(); - } - public TranslationIndex getTranslationIndex() { return this.translationIndex; } diff --git a/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java b/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java index 7919b5d5..9bd6219a 100644 --- a/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java +++ b/src/main/java/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java @@ -22,8 +22,6 @@ import cuchaz.enigma.mapping.Translator; public class MethodImplementationsTreeNode extends DefaultMutableTreeNode { - private static final long serialVersionUID = 3781080657461899915L; - private Translator deobfuscatingTranslator; private MethodEntry entry; diff --git a/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java b/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java index 63837830..b65b8c10 100644 --- a/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java +++ b/src/main/java/cuchaz/enigma/analysis/MethodInheritanceTreeNode.java @@ -22,8 +22,6 @@ import cuchaz.enigma.mapping.Translator; public class MethodInheritanceTreeNode extends DefaultMutableTreeNode { - private static final long serialVersionUID = 1096677030991810007L; - private Translator deobfuscatingTranslator; private MethodEntry entry; private boolean isImplemented; diff --git a/src/main/java/cuchaz/enigma/analysis/SourceIndex.java b/src/main/java/cuchaz/enigma/analysis/SourceIndex.java index 3fa1309a..73e04319 100644 --- a/src/main/java/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/main/java/cuchaz/enigma/analysis/SourceIndex.java @@ -145,10 +145,6 @@ public class SourceIndex { return this.tokenToReference.keySet(); } - public Iterable declarations() { - return this.declarationToToken.keySet(); - } - public Token getDeclarationToken(Entry deobfEntry) { return this.declarationToToken.get(deobfEntry); } diff --git a/src/main/java/cuchaz/enigma/analysis/Token.java b/src/main/java/cuchaz/enigma/analysis/Token.java index 575c373f..419842af 100644 --- a/src/main/java/cuchaz/enigma/analysis/Token.java +++ b/src/main/java/cuchaz/enigma/analysis/Token.java @@ -16,10 +16,6 @@ public class Token implements Comparable { 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; diff --git a/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java b/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java index 3d8f5560..275f56c9 100644 --- a/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java +++ b/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java @@ -15,10 +15,10 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; -import java.io.*; -import java.util.*; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; import cuchaz.enigma.mapping.*; import javassist.CtBehavior; @@ -26,9 +26,7 @@ import javassist.CtClass; import javassist.CtField; import javassist.bytecode.Descriptor; -public class TranslationIndex implements Serializable { - - private static final long serialVersionUID = 738687982126844179L; +public class TranslationIndex { private Map superclasses; private Multimap fieldEntries; @@ -43,7 +41,6 @@ public class TranslationIndex implements Serializable { } public TranslationIndex(TranslationIndex other, Translator translator) { - // translate the superclasses this.superclasses = Maps.newHashMap(); for (Map.Entry mapEntry : other.superclasses.entrySet()) { @@ -82,7 +79,6 @@ public class TranslationIndex implements Serializable { } public void indexClass(CtClass c, boolean indexMembers) { - ClassEntry classEntry = EntryFactory.getClassEntry(c); if (isJre(classEntry)) { return; @@ -139,7 +135,6 @@ public class TranslationIndex implements Serializable { } public List getSubclass(ClassEntry classEntry) { - // linear search is fast enough for now List subclasses = Lists.newArrayList(); for (Map.Entry entry : this.superclasses.entrySet()) { @@ -191,7 +186,6 @@ public class TranslationIndex implements Serializable { } public ClassEntry resolveEntryClass(Entry entry) { - if (entry instanceof ClassEntry) { return (ClassEntry) entry; } @@ -210,7 +204,6 @@ public class TranslationIndex implements Serializable { } 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)) { @@ -230,7 +223,6 @@ public class TranslationIndex implements Serializable { } public ClassEntry resolveInterface(Entry entry) { - // the interfaces for any class is a forest // so let's look at all the trees for (ClassEntry interfaceEntry : this.interfaces.get(entry.getClassEntry())) { @@ -246,27 +238,4 @@ public class TranslationIndex implements Serializable { 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(this.superclasses); - oout.writeObject(this.fieldEntries); - oout.writeObject(this.behaviorEntries); - gzipout.finish(); - } - - @SuppressWarnings("unchecked") - public void read(InputStream in) - throws IOException { - try { - ObjectInputStream oin = new ObjectInputStream(new GZIPInputStream(in)); - this.superclasses = (HashMap) oin.readObject(); - this.fieldEntries = (HashMultimap) oin.readObject(); - this.behaviorEntries = (HashMultimap) oin.readObject(); - } catch (ClassNotFoundException ex) { - throw new Error(ex); - } - } } diff --git a/src/main/java/cuchaz/enigma/bytecode/CheckCastIterator.java b/src/main/java/cuchaz/enigma/bytecode/CheckCastIterator.java deleted file mode 100644 index c47a7703..00000000 --- a/src/main/java/cuchaz/enigma/bytecode/CheckCastIterator.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.bytecode; - -import java.util.Iterator; - -import cuchaz.enigma.bytecode.CheckCastIterator.CheckCast; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.MethodEntry; -import cuchaz.enigma.mapping.Signature; -import javassist.bytecode.*; - -public class CheckCastIterator implements Iterator { - - public static class CheckCast { - - public final String className; - public final MethodEntry prevMethodEntry; - - public CheckCast(String className, MethodEntry prevMethodEntry) { - this.className = className; - this.prevMethodEntry = prevMethodEntry; - } - } - - private final ConstPool constants; - private final CodeAttribute attribute; - private final CodeIterator iter; - private CheckCast next; - - public CheckCastIterator(CodeAttribute codeAttribute) throws BadBytecode { - this.constants = codeAttribute.getConstPool(); - this.attribute = codeAttribute; - this.iter = this.attribute.iterator(); - - this.next = getNext(); - } - - @Override - public boolean hasNext() { - return this.next != null; - } - - @Override - public CheckCast next() { - CheckCast out = this.next; - try { - this.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 (this.iter.hasNext()) { - int pos = this.iter.next(); - int opcode = this.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(this.constants.getClassInfo(this.iter.s16bitAt(pos + 1)), prevMethodEntry); - } - break; - } - prevPos = pos; - } - return null; - } - - private MethodEntry getMethodEntry(int pos) { - switch (this.iter.byteAt(pos)) { - case Opcode.INVOKEVIRTUAL: - case Opcode.INVOKESTATIC: - case Opcode.INVOKEDYNAMIC: - case Opcode.INVOKESPECIAL: { - int index = this.iter.s16bitAt(pos + 1); - return new MethodEntry( - new ClassEntry(Descriptor.toJvmName(this.constants.getMethodrefClassName(index))), - this.constants.getMethodrefName(index), - new Signature(this.constants.getMethodrefType(index)) - ); - } - - case Opcode.INVOKEINTERFACE: { - int index = this.iter.s16bitAt(pos + 1); - return new MethodEntry( - new ClassEntry(Descriptor.toJvmName(this.constants.getInterfaceMethodrefClassName(index))), - this.constants.getInterfaceMethodrefName(index), - new Signature(this.constants.getInterfaceMethodrefType(index)) - ); - } - } - return null; - } -} diff --git a/src/main/java/cuchaz/enigma/bytecode/ConstPoolEditor.java b/src/main/java/cuchaz/enigma/bytecode/ConstPoolEditor.java index e49ffdbd..af8c79a1 100644 --- a/src/main/java/cuchaz/enigma/bytecode/ConstPoolEditor.java +++ b/src/main/java/cuchaz/enigma/bytecode/ConstPoolEditor.java @@ -17,7 +17,6 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.HashMap; -import cuchaz.enigma.bytecode.accessors.ClassInfoAccessor; import cuchaz.enigma.bytecode.accessors.ConstInfoAccessor; import cuchaz.enigma.bytecode.accessors.MemberRefInfoAccessor; import javassist.bytecode.ConstPool; @@ -101,32 +100,7 @@ public class ConstPoolEditor { 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(this.pool.getSize() - 1); - cache.remove(item); - } - // remove the actual item - // based off of LongVector.addElement() - Object item = items.get(this.pool); - Object[][] object = (Object[][]) objects.get(items); - int numElements = (Integer) elements.get(items) - 1; - int nth = numElements >> 7; - int offset = numElements & (128 - 1); - object[nth][offset] = null; - - // decrement the number of items - elements.set(item, numElements); - numItems.set(this.pool, (Integer) numItems.get(this.pool) - 1); - } catch (Exception ex) { - throw new Error(ex); - } - } @SuppressWarnings("rawtypes") public HashMap getCache() { diff --git a/src/main/java/cuchaz/enigma/bytecode/InfoType.java b/src/main/java/cuchaz/enigma/bytecode/InfoType.java index bd9e7d1a..21b04173 100644 --- a/src/main/java/cuchaz/enigma/bytecode/InfoType.java +++ b/src/main/java/cuchaz/enigma/bytecode/InfoType.java @@ -10,23 +10,21 @@ ******************************************************************************/ package cuchaz.enigma.bytecode; -import com.google.common.collect.Lists; import com.google.common.collect.Maps; import java.util.Collection; -import java.util.List; import java.util.Map; import cuchaz.enigma.bytecode.accessors.*; public enum InfoType { - Utf8Info(1, 0), - IntegerInfo(3, 0), - FloatInfo(4, 0), - LongInfo(5, 0), - DoubleInfo(6, 0), - ClassInfo(7, 1) { + Utf8Info(1), + IntegerInfo(3), + FloatInfo(4), + LongInfo(5), + DoubleInfo(6), + ClassInfo(7) { @Override public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { ClassInfoAccessor accessor = new ClassInfoAccessor(entry.getItem()); @@ -46,7 +44,7 @@ public enum InfoType { return nameEntry != null && nameEntry.getTag() == Utf8Info.getTag(); } }, - StringInfo(8, 1) { + StringInfo(8) { @Override public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { StringInfoAccessor accessor = new StringInfoAccessor(entry.getItem()); @@ -66,7 +64,7 @@ public enum InfoType { return stringEntry != null && stringEntry.getTag() == Utf8Info.getTag(); } }, - FieldRefInfo(9, 2) { + FieldRefInfo(9) { @Override public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { MemberRefInfoAccessor accessor = new MemberRefInfoAccessor(entry.getItem()); @@ -90,7 +88,7 @@ public enum InfoType { } }, // same as FieldRefInfo - MethodRefInfo(10, 2) { + MethodRefInfo(10) { @Override public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { FieldRefInfo.gatherIndexTree(indices, editor, entry); @@ -107,7 +105,7 @@ public enum InfoType { } }, // same as FieldRefInfo - InterfaceMethodRefInfo(11, 2) { + InterfaceMethodRefInfo(11) { @Override public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { FieldRefInfo.gatherIndexTree(indices, editor, entry); @@ -123,7 +121,7 @@ public enum InfoType { return FieldRefInfo.subIndicesAreValid(entry, pool); } }, - NameAndTypeInfo(12, 1) { + NameAndTypeInfo(12) { @Override public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { NameAndTypeInfoAccessor accessor = new NameAndTypeInfoAccessor(entry.getItem()); @@ -146,7 +144,7 @@ public enum InfoType { return nameEntry != null && nameEntry.getTag() == Utf8Info.getTag() && typeEntry != null && typeEntry.getTag() == Utf8Info.getTag(); } }, - MethodHandleInfo(15, 3) { + MethodHandleInfo(15) { @Override public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { MethodHandleInfoAccessor accessor = new MethodHandleInfoAccessor(entry.getItem()); @@ -169,7 +167,7 @@ public enum InfoType { return typeEntry != null && typeEntry.getTag() == Utf8Info.getTag() && methodRefEntry != null && methodRefEntry.getTag() == MethodRefInfo.getTag(); } }, - MethodTypeInfo(16, 1) { + MethodTypeInfo(16) { @Override public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { MethodTypeInfoAccessor accessor = new MethodTypeInfoAccessor(entry.getItem()); @@ -189,7 +187,7 @@ public enum InfoType { return typeEntry != null && typeEntry.getTag() == Utf8Info.getTag(); } }, - InvokeDynamicInfo(18, 2) { + InvokeDynamicInfo(18) { @Override public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { InvokeDynamicInfoAccessor accessor = new InvokeDynamicInfoAccessor(entry.getItem()); @@ -223,21 +221,15 @@ public enum InfoType { } private int tag; - private int level; - InfoType(int tag, int level) { + InfoType(int tag) { this.tag = tag; - this.level = level; } public int getTag() { return this.tag; } - public int getLevel() { - return this.level; - } - public void gatherIndexTree(Collection indices, ConstPoolEditor editor, ConstInfoAccessor entry) { // by default, do nothing } @@ -251,34 +243,10 @@ public enum InfoType { return true; } - public boolean selfIndexIsValid(ConstInfoAccessor entry, ConstPoolEditor pool) { - ConstInfoAccessor entryCheck = pool.getItem(entry.getIndex()); - return entryCheck != null && entryCheck.getItem().equals(entry.getItem()); - } - public static InfoType getByTag(int tag) { return 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); diff --git a/src/main/java/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java b/src/main/java/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java index 2ecda1d9..0ea2d02b 100644 --- a/src/main/java/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java +++ b/src/main/java/cuchaz/enigma/bytecode/accessors/ConstInfoAccessor.java @@ -10,8 +10,8 @@ ******************************************************************************/ package cuchaz.enigma.bytecode.accessors; -import java.io.*; -import java.lang.reflect.Constructor; +import java.io.ByteArrayOutputStream; +import java.io.PrintWriter; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -32,26 +32,6 @@ public class ConstInfoAccessor { this.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); - this.item = constructor.newInstance(in, oldIndex); - } catch (IOException ex) { - throw ex; - } catch (Exception ex) { - throw new Error(ex); - } - } - public Object getItem() { return this.item; } @@ -64,14 +44,6 @@ public class ConstInfoAccessor { } } - public void setIndex(int val) { - try { - index.set(this.item, val); - } catch (Exception ex) { - throw new Error(ex); - } - } - public int getTag() { try { return (Integer) getTag.invoke(this.item); @@ -80,21 +52,6 @@ public class ConstInfoAccessor { } } - public void write(DataOutputStream out) throws IOException { - try { - out.writeUTF(this.item.getClass().getName()); - out.writeInt(getIndex()); - - Method method = this.item.getClass().getMethod("write", DataOutputStream.class); - method.setAccessible(true); - method.invoke(this.item, out); - } catch (IOException ex) { - throw ex; - } catch (Exception ex) { - throw new Error(ex); - } - } - @Override public String toString() { try { diff --git a/src/main/java/cuchaz/enigma/convert/ClassForest.java b/src/main/java/cuchaz/enigma/convert/ClassForest.java deleted file mode 100644 index c9b44b33..00000000 --- a/src/main/java/cuchaz/enigma/convert/ClassForest.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 com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; - -import java.util.Collection; - -import cuchaz.enigma.mapping.ClassEntry; - - -public class ClassForest { - - private ClassIdentifier identifier; - private Multimap forest; - - public ClassForest(ClassIdentifier identifier) { - this.identifier = identifier; - this.forest = HashMultimap.create(); - } - - public void add(ClassEntry entry) { - try { - this.forest.put(this.identifier.identify(entry), entry); - } catch (ClassNotFoundException ex) { - throw new Error("Unable to find class " + entry.getName()); - } - } - - public Collection identities() { - return this.forest.keySet(); - } - - public Collection classes() { - return this.forest.values(); - } - - public Collection getClasses(ClassIdentity identity) { - return this.forest.get(identity); - } - - public boolean containsIdentity(ClassIdentity identity) { - return this.forest.containsKey(identity); - } -} diff --git a/src/main/java/cuchaz/enigma/convert/ClassIdentifier.java b/src/main/java/cuchaz/enigma/convert/ClassIdentifier.java deleted file mode 100644 index cc7f25b8..00000000 --- a/src/main/java/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 com.google.common.collect.Maps; - -import java.util.Map; -import java.util.jar.JarFile; - -import cuchaz.enigma.TranslatingTypeLoader; -import cuchaz.enigma.analysis.JarIndex; -import cuchaz.enigma.convert.ClassNamer.SidedClassNamer; -import cuchaz.enigma.mapping.ClassEntry; -import javassist.CtClass; - - -public class ClassIdentifier { - - private JarIndex index; - private SidedClassNamer namer; - private boolean useReferences; - private TranslatingTypeLoader loader; - private Map cache; - - public ClassIdentifier(JarFile jar, JarIndex index, SidedClassNamer namer, boolean useReferences) { - this.index = index; - this.namer = namer; - this.useReferences = useReferences; - this.loader = new TranslatingTypeLoader(jar, index); - this.cache = Maps.newHashMap(); - } - - public ClassIdentity identify(ClassEntry classEntry) - throws ClassNotFoundException { - ClassIdentity identity = this.cache.get(classEntry); - if (identity == null) { - CtClass c = this.loader.loadClass(classEntry.getName()); - if (c == null) { - throw new ClassNotFoundException(classEntry.getName()); - } - identity = new ClassIdentity(c, this.namer, this.index, this.useReferences); - this.cache.put(classEntry, identity); - } - return identity; - } -} diff --git a/src/main/java/cuchaz/enigma/convert/ClassIdentity.java b/src/main/java/cuchaz/enigma/convert/ClassIdentity.java deleted file mode 100644 index 606c1df1..00000000 --- a/src/main/java/cuchaz/enigma/convert/ClassIdentity.java +++ /dev/null @@ -1,441 +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 com.google.common.collect.*; - -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 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.*; -import javassist.*; -import javassist.bytecode.*; -import javassist.expr.*; - -public class ClassIdentity { - - private ClassEntry classEntry; - private SidedClassNamer namer; - private Multiset fields; - private Multiset methods; - private Multiset constructors; - private String staticInitializer; - private String extendz; - private Multiset implementz; - private Set stringLiterals; - private Multiset implementations; - private Multiset references; - private String 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.NONE_PACKAGE)) { - return className; - } - - // is this class ourself? - if (className.equals(classEntry.getName())) { - return "CSelf"; - } - - // try the namer - if (namer != null) { - String newName = 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) { - this.namer = namer; - - // stuff from the bytecode - - this.classEntry = EntryFactory.getClassEntry(c); - this.fields = HashMultiset.create(); - for (CtField field : c.getDeclaredFields()) { - this.fields.add(scrubType(field.getSignature())); - } - this.methods = HashMultiset.create(); - for (CtMethod method : c.getDeclaredMethods()) { - this.methods.add(scrubSignature(method.getSignature()) + "0x" + getBehaviorSignature(method)); - } - this.constructors = HashMultiset.create(); - for (CtConstructor constructor : c.getDeclaredConstructors()) { - this.constructors.add(scrubSignature(constructor.getSignature()) + "0x" + getBehaviorSignature(constructor)); - } - this.staticInitializer = ""; - if (c.getClassInitializer() != null) { - this.staticInitializer = getBehaviorSignature(c.getClassInitializer()); - } - this.extendz = ""; - if (c.getClassFile().getSuperclass() != null) { - this.extendz = scrubClassName(Descriptor.toJvmName(c.getClassFile().getSuperclass())); - } - this.implementz = HashMultiset.create(); - for (String interfaceName : c.getClassFile().getInterfaces()) { - this.implementz.add(scrubClassName(Descriptor.toJvmName(interfaceName))); - } - - this.stringLiterals = Sets.newHashSet(); - ConstPool constants = c.getClassFile().getConstPool(); - for (int i = 1; i < constants.getSize(); i++) { - if (constants.getTag(i) == ConstPool.CONST_String) { - this.stringLiterals.add(constants.getStringInfo(i)); - } - } - - // stuff from the jar index - - this.implementations = HashMultiset.create(); - ClassImplementationsTreeNode implementationsNode = index.getClassImplementations(null, this.classEntry); - if (implementationsNode != null) { - @SuppressWarnings("unchecked") - Enumeration implementations = implementationsNode.children(); - while (implementations.hasMoreElements()) { - ClassImplementationsTreeNode node = implementations.nextElement(); - this.implementations.add(scrubClassName(node.getClassEntry().getName())); - } - } - - this.references = HashMultiset.create(); - if (useReferences) { - for (CtField field : c.getDeclaredFields()) { - FieldEntry fieldEntry = EntryFactory.getFieldEntry(field); - index.getFieldReferences(fieldEntry).forEach(this::addReference); - } - for (CtBehavior behavior : c.getDeclaredBehaviors()) { - BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); - index.getBehaviorReferences(behaviorEntry).forEach(this::addReference); - } - } - - this.outer = null; - if (this.classEntry.isInnerClass()) { - this.outer = this.classEntry.getOuterClassName(); - } - } - - private void addReference(EntryReference reference) { - if (reference.context.getSignature() != null) { - this.references.add(String.format("%s_%s", - scrubClassName(reference.context.getClassName()), - scrubSignature(reference.context.getSignature()) - )); - } else { - this.references.add(String.format("%s_", - scrubClassName(reference.context.getClassName()) - )); - } - } - - public ClassEntry getClassEntry() { - return this.classEntry; - } - - @Override - public String toString() { - StringBuilder buf = new StringBuilder(); - buf.append("class: "); - buf.append(this.classEntry.getName()); - buf.append(" "); - buf.append(hashCode()); - buf.append("\n"); - for (String field : this.fields) { - buf.append("\tfield "); - buf.append(field); - buf.append("\n"); - } - for (String method : this.methods) { - buf.append("\tmethod "); - buf.append(method); - buf.append("\n"); - } - for (String constructor : this.constructors) { - buf.append("\tconstructor "); - buf.append(constructor); - buf.append("\n"); - } - if (this.staticInitializer.length() > 0) { - buf.append("\tinitializer "); - buf.append(this.staticInitializer); - buf.append("\n"); - } - if (this.extendz.length() > 0) { - buf.append("\textends "); - buf.append(this.extendz); - buf.append("\n"); - } - for (String interfaceName : this.implementz) { - buf.append("\timplements "); - buf.append(interfaceName); - buf.append("\n"); - } - for (String implementation : this.implementations) { - buf.append("\timplemented by "); - buf.append(implementation); - buf.append("\n"); - } - for (String reference : this.references) { - buf.append("\treference "); - buf.append(reference); - buf.append("\n"); - } - buf.append("\touter "); - buf.append(this.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 this.namer != null && this.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) { - return other instanceof ClassIdentity && equals((ClassIdentity) other); - } - - public boolean equals(ClassIdentity other) { - return this.fields.equals(other.fields) - && this.methods.equals(other.methods) - && this.constructors.equals(other.constructors) - && this.staticInitializer.equals(other.staticInitializer) - && this.extendz.equals(other.extendz) - && this.implementz.equals(other.implementz) - && this.implementations.equals(other.implementations) - && this.references.equals(other.references); - } - - @Override - public int hashCode() { - List objs = Lists.newArrayList(); - objs.addAll(this.fields); - objs.addAll(this.methods); - objs.addAll(this.constructors); - objs.add(this.staticInitializer); - objs.add(this.extendz); - objs.addAll(this.implementz); - objs.addAll(this.implementations); - objs.addAll(this.references); - return Util.combineHashesOrdered(objs); - } - - public int getMatchScore(ClassIdentity other) { - return 2 * getNumMatches(this.extendz, other.extendz) - + 2 * getNumMatches(this.outer, other.outer) - + 2 * getNumMatches(this.implementz, other.implementz) - + getNumMatches(this.stringLiterals, other.stringLiterals) - + getNumMatches(this.fields, other.fields) - + getNumMatches(this.methods, other.methods) - + getNumMatches(this.constructors, other.constructors); - } - - public int getMaxMatchScore() { - return 2 + 2 + 2 * this.implementz.size() + this.stringLiterals.size() + this.fields.size() + this.methods.size() + this.constructors.size(); - } - - public boolean matches(CtClass c) { - // just compare declaration counts - return this.fields.size() == c.getDeclaredFields().length - && this.methods.size() == c.getDeclaredMethods().length - && this.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/main/java/cuchaz/enigma/convert/ClassMatch.java b/src/main/java/cuchaz/enigma/convert/ClassMatch.java deleted file mode 100644 index 422529ec..00000000 --- a/src/main/java/cuchaz/enigma/convert/ClassMatch.java +++ /dev/null @@ -1,84 +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 com.google.common.collect.Sets; - -import java.util.Collection; -import java.util.Set; - -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) { - return other instanceof ClassMatch && equals((ClassMatch) other); - } - - public boolean equals(ClassMatch other) { - return this.sourceClasses.equals(other.sourceClasses) && this.destClasses.equals(other.destClasses); - } -} diff --git a/src/main/java/cuchaz/enigma/convert/ClassMatches.java b/src/main/java/cuchaz/enigma/convert/ClassMatches.java deleted file mode 100644 index 851c0829..00000000 --- a/src/main/java/cuchaz/enigma/convert/ClassMatches.java +++ /dev/null @@ -1,149 +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 com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; - -import java.util.*; - -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(); - - matches.forEach(this::indexMatch); - } - - 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 getMatchBySource(ClassEntry sourceClass) { - return m_matchesBySource.get(sourceClass); - } - - 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/main/java/cuchaz/enigma/convert/ClassMatching.java b/src/main/java/cuchaz/enigma/convert/ClassMatching.java deleted file mode 100644 index 194b6c4a..00000000 --- a/src/main/java/cuchaz/enigma/convert/ClassMatching.java +++ /dev/null @@ -1,146 +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 com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map.Entry; -import java.util.Set; - -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/main/java/cuchaz/enigma/convert/ClassNamer.java b/src/main/java/cuchaz/enigma/convert/ClassNamer.java deleted file mode 100644 index e471c7dd..00000000 --- a/src/main/java/cuchaz/enigma/convert/ClassNamer.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.convert; - -import com.google.common.collect.BiMap; -import com.google.common.collect.Maps; - -import java.util.Map; - -import cuchaz.enigma.mapping.ClassEntry; - -public class ClassNamer { - - public interface SidedClassNamer { - String getName(String name); - } - - private Map sourceNames; - private Map destNames; - - public ClassNamer(BiMap mappings) { - // convert the identity mappings to name maps - this.sourceNames = Maps.newHashMap(); - this.destNames = Maps.newHashMap(); - int i = 0; - for (Map.Entry entry : mappings.entrySet()) { - String name = String.format("M%04d", i++); - this.sourceNames.put(entry.getKey().getName(), name); - this.destNames.put(entry.getValue().getName(), name); - } - } - - public String getSourceName(String name) { - return this.sourceNames.get(name); - } - - public String getDestName(String name) { - return this.destNames.get(name); - } - - public SidedClassNamer getSourceNamer() { - return this::getSourceName; - } - - public SidedClassNamer getDestNamer() { - return this::getDestName; - } -} diff --git a/src/main/java/cuchaz/enigma/convert/MappingsConverter.java b/src/main/java/cuchaz/enigma/convert/MappingsConverter.java deleted file mode 100644 index 7739adf2..00000000 --- a/src/main/java/cuchaz/enigma/convert/MappingsConverter.java +++ /dev/null @@ -1,540 +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 com.google.common.collect.*; - -import java.util.*; -import java.util.jar.JarFile; - -import cuchaz.enigma.Constants; -import cuchaz.enigma.Deobfuscator; -import cuchaz.enigma.analysis.JarIndex; -import cuchaz.enigma.convert.ClassNamer.SidedClassNamer; -import cuchaz.enigma.mapping.*; - -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 < destClassChain.size() - 1; i++) { - ClassEntry destChainClassEntry = destClassChain.get(i); - if (destMapping == null) { - destMapping = newMappings.getClassByObf(destChainClassEntry); - if (destMapping == null) { - destMapping = new ClassMapping(destChainClassEntry.getName()); - newMappings.addClassMapping(destMapping); - } - } else { - destMapping = destMapping.getInnerClassByObfSimple(destChainClassEntry.getInnermostClassName()); - if (destMapping == null) { - destMapping = new ClassMapping(destChainClassEntry.getName()); - destMapping.addInnerClassMapping(destMapping); - } - } - } - if (destMapping != null) { - destMapping.addInnerClassMapping(migrateClassMapping(obfDestClassEntry, sourceMapping, matches, true)); - } - } - } - } - return newMappings; - } - - private static ClassMapping migrateClassMapping(ClassEntry newObfClass, ClassMapping oldClassMapping, final ClassMatches matches, boolean useSimpleName) { - - ClassNameReplacer replacer = className -> { - ClassEntry newClassEntry = matches.getUniqueMatches().get(new ClassEntry(className)); - if (newClassEntry != null) { - return newClassEntry.getName(); - } - return null; - }; - - ClassMapping newClassMapping; - String deobfName = oldClassMapping.getDeobfName(); - if (deobfName != null) { - if (useSimpleName) { - deobfName = new ClassEntry(deobfName).getSimpleName(); - } - newClassMapping = new ClassMapping(newObfClass.getName(), deobfName); - } else { - newClassMapping = new ClassMapping(newObfClass.getName()); - } - - // migrate fields - for (FieldMapping oldFieldMapping : oldClassMapping.fields()) { - if (canMigrate(oldFieldMapping.getObfType(), matches)) { - newClassMapping.addFieldMapping(new FieldMapping(oldFieldMapping, replacer)); - } else { - System.out.println(String.format("Can't map field, dropping: %s.%s %s", - oldClassMapping.getDeobfName(), - oldFieldMapping.getDeobfName(), - oldFieldMapping.getObfType() - )); - } - } - - // migrate methods - for (MethodMapping oldMethodMapping : oldClassMapping.methods()) { - if (canMigrate(oldMethodMapping.getObfSignature(), matches)) { - newClassMapping.addMethodMapping(new MethodMapping(oldMethodMapping, replacer)); - } else { - System.out.println(String.format("Can't map method, dropping: %s.%s %s", - oldClassMapping.getDeobfName(), - oldMethodMapping.getDeobfName(), - oldMethodMapping.getObfSignature() - )); - } - } - - return newClassMapping; - } - - private static boolean canMigrate(Signature oldObfSignature, ClassMatches classMatches) { - for (Type oldObfType : oldObfSignature.types()) { - if (!canMigrate(oldObfType, classMatches)) { - return false; - } - } - return true; - } - - private static boolean canMigrate(Type oldObfType, ClassMatches classMatches) { - - // non classes can be migrated - if (!oldObfType.hasClass()) { - return true; - } - - // non obfuscated classes can be migrated - ClassEntry classEntry = oldObfType.getClassEntry(); - if (!classEntry.getPackageName().equals(Constants.NONE_PACKAGE)) { - return true; - } - - // obfuscated classes with mappings can be migrated - return classMatches.getUniqueMatches().containsKey(classEntry); - } - - public 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, 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, 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/main/java/cuchaz/enigma/convert/MatchesReader.java b/src/main/java/cuchaz/enigma/convert/MatchesReader.java deleted file mode 100644 index f7853acf..00000000 --- a/src/main/java/cuchaz/enigma/convert/MatchesReader.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.convert; - -import com.google.common.collect.Lists; - -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 cuchaz.enigma.mapping.*; - - -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; - 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; - 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 { - 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/main/java/cuchaz/enigma/convert/MatchesWriter.java b/src/main/java/cuchaz/enigma/convert/MatchesWriter.java deleted file mode 100644 index baf79293..00000000 --- a/src/main/java/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/main/java/cuchaz/enigma/convert/MemberMatches.java b/src/main/java/cuchaz/enigma/convert/MemberMatches.java deleted file mode 100644 index 662c1db9..00000000 --- a/src/main/java/cuchaz/enigma/convert/MemberMatches.java +++ /dev/null @@ -1,143 +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 com.google.common.collect.*; - -import java.util.Collection; -import java.util.Set; - -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 addUnmatchedDestEntry(T destEntry) { - boolean wasAdded = m_unmatchedDestEntries.put(destEntry.getClassEntry(), destEntry); - assert (wasAdded); - } - - 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/main/java/cuchaz/enigma/gui/BoxHighlightPainter.java b/src/main/java/cuchaz/enigma/gui/BoxHighlightPainter.java deleted file mode 100644 index b66d13da..00000000 --- a/src/main/java/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 fillColor; - private Color borderColor; - - protected BoxHighlightPainter(Color fillColor, Color borderColor) { - this.fillColor = fillColor; - this.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 (this.fillColor != null) { - g.setColor(this.fillColor); - g.fillRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4); - } - - // draw a box around the area - g.setColor(this.borderColor); - g.drawRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4); - } - - public 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/main/java/cuchaz/enigma/gui/BrowserCaret.java b/src/main/java/cuchaz/enigma/gui/BrowserCaret.java index a75db366..f58d0129 100644 --- a/src/main/java/cuchaz/enigma/gui/BrowserCaret.java +++ b/src/main/java/cuchaz/enigma/gui/BrowserCaret.java @@ -15,8 +15,6 @@ import javax.swing.text.Highlighter; public class BrowserCaret extends DefaultCaret { - private static final long serialVersionUID = 1158977422507969940L; - private static final Highlighter.HighlightPainter selectionPainter = (g, p0, p1, bounds, c) -> { }; diff --git a/src/main/java/cuchaz/enigma/gui/ClassMatchingGui.java b/src/main/java/cuchaz/enigma/gui/ClassMatchingGui.java deleted file mode 100644 index e8136881..00000000 --- a/src/main/java/cuchaz/enigma/gui/ClassMatchingGui.java +++ /dev/null @@ -1,521 +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 com.google.common.collect.BiMap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - -import java.awt.BorderLayout; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.event.ActionListener; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import javax.swing.*; - -import cuchaz.enigma.Constants; -import cuchaz.enigma.Deobfuscator; -import cuchaz.enigma.convert.*; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.Mappings; -import cuchaz.enigma.mapping.MappingsChecker; -import de.sciss.syntaxpane.DefaultSyntaxKit; - - -public class ClassMatchingGui { - - private 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 interface SaveListener { - void save(ClassMatches matches); - } - - // controls - private JFrame frame; - private ClassSelector sourceClasses; - private ClassSelector destClasses; - private CodeReader sourceReader; - private CodeReader destReader; - private JLabel sourceClassLabel; - private JLabel destClassLabel; - private JButton matchButton; - private Map sourceTypeButtons; - private JCheckBox advanceCheck; - private JCheckBox top10Matches; - - private ClassMatches classMatches; - private Deobfuscator sourceDeobfuscator; - private Deobfuscator destDeobfuscator; - private ClassEntry sourceClass; - private ClassEntry destClass; - private SourceType sourceType; - private SaveListener saveListener; - - public ClassMatchingGui(ClassMatches matches, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) { - - this.classMatches = matches; - this.sourceDeobfuscator = sourceDeobfuscator; - this.destDeobfuscator = destDeobfuscator; - - // init frame - this.frame = new JFrame(Constants.NAME + " - Class Matcher"); - final Container pane = this.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 = event -> setSourceType(SourceType.valueOf(event.getActionCommand())); - ButtonGroup sourceTypeButtons = new ButtonGroup(); - this.sourceTypeButtons = Maps.newHashMap(); - for (SourceType sourceType : SourceType.values()) { - JRadioButton button = sourceType.newRadio(sourceTypeListener, sourceTypeButtons); - this.sourceTypeButtons.put(sourceType, button); - sourceTypePanel.add(button); - } - - this.sourceClasses = new ClassSelector(ClassSelector.DEOBF_CLASS_COMPARATOR); - this.sourceClasses.setListener(this::setSourceClass); - JScrollPane sourceScroller = new JScrollPane(this.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")); - - this.top10Matches = new JCheckBox("Show only top 10 matches"); - destPanel.add(this.top10Matches); - this.top10Matches.addActionListener(event -> toggleTop10Matches()); - - this.destClasses = new ClassSelector(ClassSelector.DEOBF_CLASS_COMPARATOR); - this.destClasses.setListener(this::setDestClass); - JScrollPane destScroller = new JScrollPane(this.destClasses); - destPanel.add(destScroller); - - JButton autoMatchButton = new JButton("AutoMatch"); - autoMatchButton.addActionListener(event -> autoMatch()); - destPanel.add(autoMatchButton); - - // init source panels - DefaultSyntaxKit.initKit(); - this.sourceReader = new CodeReader(); - this.destReader = new CodeReader(); - - // init all the splits - JSplitPane splitLeft = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, sourcePanel, new JScrollPane(this.sourceReader)); - splitLeft.setResizeWeight(0); // let the right side take all the slack - JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, new JScrollPane(this.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()); - - this.sourceClassLabel = new JLabel(); - this.sourceClassLabel.setHorizontalAlignment(SwingConstants.RIGHT); - this.destClassLabel = new JLabel(); - this.destClassLabel.setHorizontalAlignment(SwingConstants.LEFT); - - this.matchButton = new JButton(); - - this.advanceCheck = new JCheckBox("Advance to next likely match"); - this.advanceCheck.addActionListener(event -> { - if (this.advanceCheck.isSelected()) { - advance(); - } - }); - - bottomPanel.add(this.sourceClassLabel); - bottomPanel.add(this.matchButton); - bottomPanel.add(this.destClassLabel); - bottomPanel.add(this.advanceCheck); - pane.add(bottomPanel, BorderLayout.SOUTH); - - // show the frame - pane.doLayout(); - this.frame.setSize(1024, 576); - this.frame.setMinimumSize(new Dimension(640, 480)); - this.frame.setVisible(true); - this.frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - - // init state - updateDestMappings(); - setSourceType(SourceType.getDefault()); - updateMatchButton(); - this.saveListener = null; - } - - public void setSaveListener(SaveListener val) { - this.saveListener = val; - } - - private void updateDestMappings() { - - Mappings newMappings = MappingsConverter.newMappings(this.classMatches, this.sourceDeobfuscator.getMappings(), this.sourceDeobfuscator, this.destDeobfuscator); - - // look for dropped mappings - MappingsChecker checker = new MappingsChecker(this.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 - )); - - this.destDeobfuscator.setMappings(newMappings); - } - - protected void setSourceType(SourceType val) { - - // show the source classes - this.sourceType = val; - this.sourceClasses.setClasses(deobfuscateClasses(this.sourceType.getSourceClasses(this.classMatches), this.sourceDeobfuscator)); - - // update counts - for (SourceType sourceType : SourceType.values()) { - this.sourceTypeButtons.get(sourceType).setText(String.format("%s (%d)", - sourceType.name(), - sourceType.getSourceClasses(this.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 (this.advanceCheck.isSelected()) { - onGetDestClasses = this::pickBestDestClass; - } - - setSourceClass(classEntry, onGetDestClasses); - } - - protected void setSourceClass(ClassEntry classEntry, final Runnable onGetDestClasses) { - - // update the current source class - this.sourceClass = classEntry; - this.sourceClassLabel.setText(this.sourceClass != null ? this.sourceClass.getName() : ""); - - if (this.sourceClass != null) { - - // show the dest class(es) - ClassMatch match = this.classMatches.getMatchBySource(this.sourceDeobfuscator.obfuscateEntry(this.sourceClass)); - assert (match != null); - if (match.destClasses.isEmpty()) { - - this.destClasses.setClasses(null); - - // run in a separate thread to keep ui responsive - new Thread() { - @Override - public void run() { - destClasses.setClasses(deobfuscateClasses(getLikelyMatches(sourceClass), destDeobfuscator)); - destClasses.expandAll(); - - if (onGetDestClasses != null) { - onGetDestClasses.run(); - } - } - }.start(); - - } else { - - this.destClasses.setClasses(deobfuscateClasses(match.destClasses, this.destDeobfuscator)); - this.destClasses.expandAll(); - - if (onGetDestClasses != null) { - onGetDestClasses.run(); - } - } - } - - setDestClass(null); - this.sourceReader.decompileClass(this.sourceClass, this.sourceDeobfuscator, () -> this.sourceReader.navigateToClassDeclaration(this.sourceClass)); - - updateMatchButton(); - } - - private Collection getLikelyMatches(ClassEntry sourceClass) { - - ClassEntry obfSourceClass = this.sourceDeobfuscator.obfuscateEntry(sourceClass); - - // set up identifiers - ClassNamer namer = new ClassNamer(this.classMatches.getUniqueMatches()); - ClassIdentifier sourceIdentifier = new ClassIdentifier(this.sourceDeobfuscator.getJar(), this.sourceDeobfuscator.getJarIndex(), namer.getSourceNamer(), true); - ClassIdentifier destIdentifier = new ClassIdentifier(this.destDeobfuscator.getJar(), this.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 : this.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 (this.top10Matches.isSelected() && scoredDestClasses.size() > 10) { - Collections.sort(scoredDestClasses, (a, 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 - this.destClass = classEntry; - this.destClassLabel.setText(this.destClass != null ? this.destClass.getName() : ""); - - this.destReader.decompileClass(this.destClass, this.destDeobfuscator, () -> this.destReader.navigateToClassDeclaration(this.destClass)); - - updateMatchButton(); - } - - private void updateMatchButton() { - - ClassEntry obfSource = this.sourceDeobfuscator.obfuscateEntry(this.sourceClass); - ClassEntry obfDest = this.destDeobfuscator.obfuscateEntry(this.destClass); - - BiMap uniqueMatches = this.classMatches.getUniqueMatches(); - boolean twoSelected = this.sourceClass != null && this.destClass != null; - boolean isMatched = uniqueMatches.containsKey(obfSource) && uniqueMatches.containsValue(obfDest); - boolean canMatch = !uniqueMatches.containsKey(obfSource) && !uniqueMatches.containsValue(obfDest); - - GuiTricks.deactivateButton(this.matchButton); - if (twoSelected) { - if (isMatched) { - GuiTricks.activateButton(this.matchButton, "Unmatch", event -> onUnmatchClick()); - } else if (canMatch) { - GuiTricks.activateButton(this.matchButton, "Match", event -> onMatchClick()); - } - } - } - - private void onMatchClick() { - // precondition: source and dest classes are set correctly - - ClassEntry obfSource = this.sourceDeobfuscator.obfuscateEntry(this.sourceClass); - ClassEntry obfDest = this.destDeobfuscator.obfuscateEntry(this.destClass); - - // remove the classes from their match - this.classMatches.removeSource(obfSource); - this.classMatches.removeDest(obfDest); - - // add them as matched classes - this.classMatches.add(new ClassMatch(obfSource, obfDest)); - - ClassEntry nextClass = null; - if (this.advanceCheck.isSelected()) { - nextClass = this.sourceClasses.getNextClass(this.sourceClass); - } - - save(); - updateMatches(); - - if (nextClass != null) { - advance(nextClass); - } - } - - private void onUnmatchClick() { - // precondition: source and dest classes are set to a unique match - - ClassEntry obfSource = this.sourceDeobfuscator.obfuscateEntry(this.sourceClass); - - // remove the source to break the match, then add the source back as unmatched - this.classMatches.removeSource(obfSource); - this.classMatches.add(new ClassMatch(obfSource, null)); - - save(); - updateMatches(); - } - - private void updateMatches() { - updateDestMappings(); - setDestClass(null); - this.destClasses.setClasses(null); - updateMatchButton(); - - // remember where we were in the source tree - String packageName = this.sourceClasses.getSelectedPackage(); - - setSourceType(this.sourceType); - - this.sourceClasses.expandPackage(packageName); - } - - private void save() { - if (this.saveListener != null) { - this.saveListener.save(this.classMatches); - } - } - - private void autoMatch() { - - System.out.println("Automatching..."); - - // compute a new matching - ClassMatching matching = MappingsConverter.computeMatching(this.sourceDeobfuscator.getJar(), this.sourceDeobfuscator.getJarIndex(), - this.destDeobfuscator.getJar(), this.destDeobfuscator.getJarIndex(), this.classMatches.getUniqueMatches()); - ClassMatches newMatches = new ClassMatches(matching.matches()); - System.out.println(String.format("Automatch found %d new matches", newMatches.getUniqueMatches().size() - this.classMatches.getUniqueMatches().size())); - - // update the current matches - this.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 = this.sourceClasses.getSelectedClass(); - if (sourceClass != null) { - sourceClass = this.sourceClasses.getNextClass(sourceClass); - } else { - sourceClass = this.sourceClasses.getFirstClass(); - } - } - - // set the source class - setSourceClass(sourceClass, this::pickBestDestClass); - this.sourceClasses.setSelectionClass(sourceClass); - } - - private void pickBestDestClass() { - - // then, pick the best dest class - ClassEntry firstClass = null; - ScoredClassEntry bestDestClass = null; - for (ClassSelectorPackageNode packageNode : this.destClasses.packageNodes()) { - for (ClassSelectorClassNode classNode : this.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); - this.destClasses.setSelectionClass(destClass); - } - - private void toggleTop10Matches() { - if (this.sourceClass != null) { - this.destClasses.clearSelection(); - this.destClasses.setClasses(deobfuscateClasses(getLikelyMatches(this.sourceClass), this.destDeobfuscator)); - this.destClasses.expandAll(); - } - } -} diff --git a/src/main/java/cuchaz/enigma/gui/ClassSelector.java b/src/main/java/cuchaz/enigma/gui/ClassSelector.java index 2ee3b2ae..27b4d360 100644 --- a/src/main/java/cuchaz/enigma/gui/ClassSelector.java +++ b/src/main/java/cuchaz/enigma/gui/ClassSelector.java @@ -24,17 +24,13 @@ import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; +import cuchaz.enigma.gui.node.ClassSelectorClassNode; +import cuchaz.enigma.gui.node.ClassSelectorPackageNode; import cuchaz.enigma.mapping.ClassEntry; public class ClassSelector extends JTree { - private static final long serialVersionUID = -7632046902384775977L; - public static final Comparator DEOBF_CLASS_COMPARATOR = (a, b) -> { - if (a instanceof ScoredClassEntry && b instanceof ScoredClassEntry) { - return Float.compare(((ScoredClassEntry) b).getScore(), ((ScoredClassEntry) a).getScore()); - } - return a.getName().compareTo(b.getName()); - }; + public static final Comparator DEOBF_CLASS_COMPARATOR = (a, b) -> a.getName().compareTo(b.getName()); public interface ClassSelectionListener { void onSelectClass(ClassEntry classEntry); @@ -75,6 +71,7 @@ public class ClassSelector extends JTree { } public void setClasses(Collection classEntries) { + String state = getExpansionState(this, 0); if (classEntries == null) { setModel(null); return; @@ -137,125 +134,45 @@ public class ClassSelector extends JTree { // 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; + restoreExpanstionState(this, 0, state); } - public void expandPackage(String packageName) { - if (packageName == null) { - return; + public boolean isDescendant(TreePath path1, TreePath path2) { + int count1 = path1.getPathCount(); + int count2 = path2.getPathCount(); + if (count1 <= count2) { + return false; } - for (ClassSelectorPackageNode packageNode : packageNodes()) { - if (packageNode.getPackageName().equals(packageName)) { - expandPath(new TreePath(new Object[]{getModel().getRoot(), packageNode})); - return; - } + while (count1 != count2) { + path1 = path1.getParentPath(); + count1--; } + return path1.equals(path2); } - 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(); - } - } + public String getExpansionState(JTree tree, int row) { + TreePath rowPath = tree.getPathForRow(row); + StringBuffer buf = new StringBuffer(); + int rowCount = tree.getRowCount(); + for (int i = row; i < rowCount; i++) { + TreePath path = tree.getPathForRow(i); + if (i == row || isDescendant(path, rowPath)) { + if (tree.isExpanded(path)) { + buf.append("," + String.valueOf(i - row)); } } else { - // return the next class - for (ClassSelectorClassNode classNode : classNodes(packageNode)) { - return classNode.getClassEntry(); - } + break; } } - return null; + return buf.toString(); } - 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})); - } - } + public void restoreExpanstionState(JTree tree, int row, String expansionState) { + StringTokenizer stok = new StringTokenizer(expansionState, ","); + while (stok.hasMoreTokens()) { + int token = row + Integer.parseInt(stok.nextToken()); + tree.expandRow(token); } } } diff --git a/src/main/java/cuchaz/enigma/gui/ClassSelectorClassNode.java b/src/main/java/cuchaz/enigma/gui/ClassSelectorClassNode.java deleted file mode 100644 index e73340a6..00000000 --- a/src/main/java/cuchaz/enigma/gui/ClassSelectorClassNode.java +++ /dev/null @@ -1,47 +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 classEntry; - - public ClassSelectorClassNode(ClassEntry classEntry) { - this.classEntry = classEntry; - } - - public ClassEntry getClassEntry() { - return this.classEntry; - } - - @Override - public String toString() { - if (this.classEntry instanceof ScoredClassEntry) { - return String.format("%d%% %s", (int) ((ScoredClassEntry) this.classEntry).getScore(), this.classEntry.getSimpleName()); - } - return this.classEntry.getSimpleName(); - } - - @Override - public boolean equals(Object other) { - return other instanceof ClassSelectorClassNode && equals((ClassSelectorClassNode) other); - } - - public boolean equals(ClassSelectorClassNode other) { - return this.classEntry.equals(other.classEntry); - } -} diff --git a/src/main/java/cuchaz/enigma/gui/ClassSelectorPackageNode.java b/src/main/java/cuchaz/enigma/gui/ClassSelectorPackageNode.java deleted file mode 100644 index 3b5ba8ca..00000000 --- a/src/main/java/cuchaz/enigma/gui/ClassSelectorPackageNode.java +++ /dev/null @@ -1,42 +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 packageName; - - public ClassSelectorPackageNode(String packageName) { - this.packageName = packageName; - } - - public String getPackageName() { - return this.packageName; - } - - @Override - public String toString() { - return this.packageName; - } - - @Override - public boolean equals(Object other) { - return other instanceof ClassSelectorPackageNode && equals((ClassSelectorPackageNode) other); - } - - public boolean equals(ClassSelectorPackageNode other) { - return this.packageName.equals(other.packageName); - } -} diff --git a/src/main/java/cuchaz/enigma/gui/CodeReader.java b/src/main/java/cuchaz/enigma/gui/CodeReader.java deleted file mode 100644 index a476fa51..00000000 --- a/src/main/java/cuchaz/enigma/gui/CodeReader.java +++ /dev/null @@ -1,202 +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 com.strobel.decompiler.languages.java.ast.CompilationUnit; - -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.text.BadLocationException; -import javax.swing.text.Highlighter.HighlightPainter; - -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 lock = new Object(); - - public interface SelectionListener { - void onSelect(EntryReference reference); - } - - private SelectionHighlightPainter selectionHighlightPainter; - private SourceIndex sourceIndex; - private SelectionListener 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(event -> { - if (this.selectionListener != null && this.sourceIndex != null) { - Token token = this.sourceIndex.getReferenceToken(event.getDot()); - if (token != null) { - this.selectionListener.onSelect(this.sourceIndex.getDeobfReference(token)); - } else { - this.selectionListener.onSelect(null); - } - } - }); - - this.selectionHighlightPainter = new SelectionHighlightPainter(); - this.sourceIndex = null; - this.selectionListener = null; - } - - public void setSelectionListener(SelectionListener val) { - this.selectionListener = val; - } - - public void setCode(String code) { - // sadly, the java lexer is not thread safe, so we have to serialize all these calls - synchronized (lock) { - setText(code); - } - } - - public SourceIndex getSourceIndex() { - return this.sourceIndex; - } - - 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); - sourceIndex = deobfuscator.getSourceIndex(sourceTree, source, ignoreBadTokens); - - if (callback != null) { - callback.run(); - } - } - }.start(); - } - - public void navigateToClassDeclaration(ClassEntry classEntry) { - - // navigate to the class declaration - Token token = this.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 : this.sourceIndex.declarations()) { - if (entry.getClassEntry().equals(classEntry)) { - token = this.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, this.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(() -> 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 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/main/java/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java b/src/main/java/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java deleted file mode 100644 index d5ad0c8a..00000000 --- a/src/main/java/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.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.gui; - -import java.awt.Color; - -public class DeobfuscatedHighlightPainter extends BoxHighlightPainter { - - public DeobfuscatedHighlightPainter() { - super(new Color(220, 255, 220), new Color(80, 160, 80)); - } -} diff --git a/src/main/java/cuchaz/enigma/gui/Gui.java b/src/main/java/cuchaz/enigma/gui/Gui.java index 623e12ea..d93aa9fc 100644 --- a/src/main/java/cuchaz/enigma/gui/Gui.java +++ b/src/main/java/cuchaz/enigma/gui/Gui.java @@ -36,11 +36,17 @@ import cuchaz.enigma.gui.elements.MenuBar; import cuchaz.enigma.gui.elements.PopupMenuBar; import cuchaz.enigma.gui.filechooser.FileChooserFile; import cuchaz.enigma.gui.filechooser.FileChooserFolder; +import cuchaz.enigma.gui.highlight.DeobfuscatedHighlightPainter; +import cuchaz.enigma.gui.highlight.ObfuscatedHighlightPainter; +import cuchaz.enigma.gui.highlight.OtherHighlightPainter; +import cuchaz.enigma.gui.highlight.SelectionHighlightPainter; import cuchaz.enigma.gui.panels.PanelDeobf; import cuchaz.enigma.gui.panels.PanelEditor; import cuchaz.enigma.gui.panels.PanelIdentifier; import cuchaz.enigma.gui.panels.PanelObf; import cuchaz.enigma.mapping.*; +import cuchaz.enigma.throwables.IllegalNameException; +import cuchaz.enigma.utils.Utils; import de.sciss.syntaxpane.DefaultSyntaxKit; public class Gui { @@ -363,7 +369,7 @@ public class Gui { if (token == null) { throw new IllegalArgumentException("Token cannot be null!"); } - CodeReader.navigateToToken(this.editor, token, m_selectionHighlightPainter); + Utils.navigateToToken(this.editor, token, m_selectionHighlightPainter); redraw(); } @@ -476,7 +482,7 @@ public class Gui { label.setPreferredSize(new Dimension(100, label.getPreferredSize().height)); panel.add(label); - panel.add(GuiTricks.unboldLabel(new JLabel(value, JLabel.LEFT))); + panel.add(Utils.unboldLabel(new JLabel(value, JLabel.LEFT))); } public void onCaretMove(int pos) { @@ -498,13 +504,13 @@ public class Gui { m_infoPanel.clearReference(); } - this.popupMenu.renameMenu.setEnabled(isRenameable && isToken); + this.popupMenu.renameMenu.setEnabled(isRenameable); this.popupMenu.showInheritanceMenu.setEnabled(isClassEntry || isMethodEntry || isConstructorEntry); this.popupMenu.showImplementationsMenu.setEnabled(isClassEntry || isMethodEntry); this.popupMenu.showCallsMenu.setEnabled(isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry); this.popupMenu.openEntryMenu.setEnabled(isInJar && (isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry)); this.popupMenu.openPreviousMenu.setEnabled(this.controller.hasPreviousLocation()); - this.popupMenu.toggleMappingMenu.setEnabled(isRenameable && isToken); + this.popupMenu.toggleMappingMenu.setEnabled(isRenameable); if (isToken && this.controller.entryHasDeobfuscatedName(m_reference.entry)) { this.popupMenu.toggleMappingMenu.setText("Reset to obfuscated"); @@ -526,7 +532,6 @@ public class Gui { private void navigateTo(EntryReference reference) { if (!this.controller.entryIsInJar(reference.getLocationClassEntry())) { - // reference is not in the jar. Ignore it return; } if (m_reference != null) { @@ -574,7 +579,7 @@ public class Gui { } catch (IllegalNameException ex) { text.setBorder(BorderFactory.createLineBorder(Color.red, 1)); text.setToolTipText(ex.getReason()); - GuiTricks.showToolTipNow(text); + Utils.showToolTipNow(text); } return; } @@ -582,7 +587,7 @@ public class Gui { // 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))); + panel.add(Utils.unboldLabel(new JLabel(m_reference.getNamableName(), JLabel.LEFT))); this.editor.grabFocus(); @@ -704,6 +709,7 @@ public class Gui { if (!this.controller.isDirty()) { // everything is saved, we can exit safely this.frame.dispose(); + System.exit(0); } else { // ask to save before closing String[] options = {"Save and exit", "Discard changes", "Cancel"}; diff --git a/src/main/java/cuchaz/enigma/gui/GuiController.java b/src/main/java/cuchaz/enigma/gui/GuiController.java index 37244ff5..c3015948 100644 --- a/src/main/java/cuchaz/enigma/gui/GuiController.java +++ b/src/main/java/cuchaz/enigma/gui/GuiController.java @@ -27,6 +27,8 @@ import cuchaz.enigma.Deobfuscator; import cuchaz.enigma.analysis.*; import cuchaz.enigma.gui.dialog.ProgressDialog; import cuchaz.enigma.mapping.*; +import cuchaz.enigma.throwables.MappingParseException; +import cuchaz.enigma.utils.ReadableToken; public class GuiController { @@ -72,7 +74,7 @@ public class GuiController { refreshCurrentClass(); } - public void openMappings(File file) throws IOException, MappingParseException { + public void openMappings(File file) throws IOException { this.deobfuscator.setMappings(new MappingsReader().read(file)); this.isDirty = false; this.gui.setMappingsFile(file); diff --git a/src/main/java/cuchaz/enigma/gui/GuiTricks.java b/src/main/java/cuchaz/enigma/gui/GuiTricks.java deleted file mode 100644 index ffacfecf..00000000 --- a/src/main/java/cuchaz/enigma/gui/GuiTricks.java +++ /dev/null @@ -1,52 +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(""); - Arrays.asList(button.getActionListeners()).forEach(button::removeActionListener); - } - - public static void activateButton(JButton button, String text, ActionListener newListener) { - button.setText(text); - button.setEnabled(true); - Arrays.asList(button.getActionListeners()).forEach(button::removeActionListener); - button.addActionListener(newListener); - } -} diff --git a/src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java b/src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java deleted file mode 100644 index 0713ad58..00000000 --- a/src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java +++ /dev/null @@ -1,442 +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 com.google.common.collect.Lists; -import com.google.common.collect.Maps; - -import java.awt.BorderLayout; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.FlowLayout; -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.*; -import javax.swing.text.Highlighter.HighlightPainter; - -import cuchaz.enigma.Constants; -import cuchaz.enigma.Deobfuscator; -import cuchaz.enigma.analysis.SourceIndex; -import cuchaz.enigma.analysis.Token; -import cuchaz.enigma.convert.ClassMatches; -import cuchaz.enigma.convert.MemberMatches; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.Entry; -import de.sciss.syntaxpane.DefaultSyntaxKit; - - -public class MemberMatchingGui { - - private 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 interface SaveListener { - 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 = 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.DEOBF_CLASS_COMPARATOR); - m_sourceClasses.setListener(this::setSourceClass); - JScrollPane sourceScroller = new JScrollPane(m_sourceClasses); - classesPanel.add(sourceScroller); - - // init readers - DefaultSyntaxKit.initKit(); - m_sourceReader = new CodeReader(); - m_sourceReader.setSelectionListener(reference -> { - if (reference != null) { - onSelectSource(reference.entry); - } else { - onSelectSource(null); - } - }); - m_destReader = new CodeReader(); - m_destReader.setSelectionListener(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, this::updateSourceHighlights); - m_destReader.decompileClass(m_obfDestClass, m_destDeobfuscator, false, this::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) { - m_obfSourceEntry = obfEntry; - if (obfEntry == null) { - m_sourceLabel.setText(""); - } else { - m_sourceLabel.setText(getEntryLabel(obfEntry, m_sourceDeobfuscator)); - } - } - - private void setDest(T obfEntry) { - m_obfDestEntry = obfEntry; - if (obfEntry == null) { - m_destLabel.setText(""); - } else { - 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", event -> unmatch()); - } else if (!m_memberMatches.isMatchedSourceEntry(m_obfSourceEntry) && !m_memberMatches.isMatchedDestEntry(m_obfDestEntry)) { - GuiTricks.activateButton(m_matchButton, "Match", event -> match()); - } - } else if (m_obfSourceEntry != null) { - GuiTricks.activateButton(m_unmatchableButton, "Set Unmatchable", 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/main/java/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java b/src/main/java/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java deleted file mode 100644 index 5afc767f..00000000 --- a/src/main/java/cuchaz/enigma/gui/ObfuscatedHighlightPainter.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.gui; - -import java.awt.Color; - -public class ObfuscatedHighlightPainter extends BoxHighlightPainter { - - public ObfuscatedHighlightPainter() { - super(new Color(255, 220, 220), new Color(160, 80, 80)); - } -} diff --git a/src/main/java/cuchaz/enigma/gui/OtherHighlightPainter.java b/src/main/java/cuchaz/enigma/gui/OtherHighlightPainter.java deleted file mode 100644 index 256f69eb..00000000 --- a/src/main/java/cuchaz/enigma/gui/OtherHighlightPainter.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.gui; - -import java.awt.Color; - -public class OtherHighlightPainter extends BoxHighlightPainter { - - public OtherHighlightPainter() { - super(null, new Color(180, 180, 180)); - } -} diff --git a/src/main/java/cuchaz/enigma/gui/ReadableToken.java b/src/main/java/cuchaz/enigma/gui/ReadableToken.java deleted file mode 100644 index feec8c06..00000000 --- a/src/main/java/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/main/java/cuchaz/enigma/gui/ScoredClassEntry.java b/src/main/java/cuchaz/enigma/gui/ScoredClassEntry.java deleted file mode 100644 index 359ec7ae..00000000 --- a/src/main/java/cuchaz/enigma/gui/ScoredClassEntry.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.gui; - -import cuchaz.enigma.mapping.ClassEntry; - -public class ScoredClassEntry extends ClassEntry { - - private static final long serialVersionUID = -8798725308554217105L; - - private float score; - - public ScoredClassEntry(ClassEntry other, float score) { - super(other); - this.score = score; - } - - public float getScore() { - return this.score; - } -} diff --git a/src/main/java/cuchaz/enigma/gui/SelectionHighlightPainter.java b/src/main/java/cuchaz/enigma/gui/SelectionHighlightPainter.java deleted file mode 100644 index fcad07cd..00000000 --- a/src/main/java/cuchaz/enigma/gui/SelectionHighlightPainter.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.gui; - -import java.awt.*; - -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/main/java/cuchaz/enigma/gui/dialog/AboutDialog.java b/src/main/java/cuchaz/enigma/gui/dialog/AboutDialog.java index da4f5fb5..f690b159 100644 --- a/src/main/java/cuchaz/enigma/gui/dialog/AboutDialog.java +++ b/src/main/java/cuchaz/enigma/gui/dialog/AboutDialog.java @@ -19,7 +19,7 @@ import java.io.IOException; import javax.swing.*; import cuchaz.enigma.Constants; -import cuchaz.enigma.Util; +import cuchaz.enigma.utils.Utils; public class AboutDialog { @@ -31,7 +31,7 @@ public class AboutDialog { // load the content try { - String html = Util.readResourceToString("/about.html"); + String html = Utils.readResourceToString("/about.html"); html = String.format(html, Constants.NAME, Constants.VERSION); JLabel label = new JLabel(html); label.setHorizontalAlignment(JLabel.CENTER); @@ -44,7 +44,7 @@ public class AboutDialog { String html = "%s"; html = String.format(html, Constants.URL, Constants.URL); JButton link = new JButton(html); - link.addActionListener(event -> Util.openUrl(Constants.URL)); + link.addActionListener(event -> Utils.openUrl(Constants.URL)); link.setBorderPainted(false); link.setOpaque(false); link.setBackground(Color.WHITE); diff --git a/src/main/java/cuchaz/enigma/gui/dialog/CrashDialog.java b/src/main/java/cuchaz/enigma/gui/dialog/CrashDialog.java index 71aab015..8d3df47b 100644 --- a/src/main/java/cuchaz/enigma/gui/dialog/CrashDialog.java +++ b/src/main/java/cuchaz/enigma/gui/dialog/CrashDialog.java @@ -19,7 +19,7 @@ import java.io.StringWriter; import javax.swing.*; import cuchaz.enigma.Constants; -import cuchaz.enigma.gui.GuiTricks; +import cuchaz.enigma.utils.Utils; public class CrashDialog { @@ -48,7 +48,7 @@ public class CrashDialog { 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."))); + buttonsPanel.add(Utils.unboldLabel(new JLabel("If you choose exit, you will lose any unsaved work."))); JButton ignoreButton = new JButton("Ignore"); ignoreButton.addActionListener(event -> { // close (hide) the dialog diff --git a/src/main/java/cuchaz/enigma/gui/dialog/ProgressDialog.java b/src/main/java/cuchaz/enigma/gui/dialog/ProgressDialog.java index dc4d91e8..c752c868 100644 --- a/src/main/java/cuchaz/enigma/gui/dialog/ProgressDialog.java +++ b/src/main/java/cuchaz/enigma/gui/dialog/ProgressDialog.java @@ -19,7 +19,7 @@ import javax.swing.*; import cuchaz.enigma.Constants; import cuchaz.enigma.Deobfuscator.ProgressListener; -import cuchaz.enigma.gui.GuiTricks; +import cuchaz.enigma.utils.Utils; public class ProgressDialog implements ProgressListener, AutoCloseable { @@ -44,7 +44,7 @@ public class ProgressDialog implements ProgressListener, AutoCloseable { JPanel panel = new JPanel(); pane.add(panel); panel.setLayout(new BorderLayout()); - this.labelText = GuiTricks.unboldLabel(new JLabel()); + this.labelText = Utils.unboldLabel(new JLabel()); this.progress = new JProgressBar(); this.labelText.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0)); panel.add(this.labelText, BorderLayout.NORTH); diff --git a/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java b/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java index 233d55e2..e8703340 100644 --- a/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java +++ b/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java @@ -9,7 +9,7 @@ import javax.swing.*; import cuchaz.enigma.gui.Gui; import cuchaz.enigma.gui.dialog.AboutDialog; -import cuchaz.enigma.mapping.MappingParseException; +import cuchaz.enigma.throwables.MappingParseException; public class MenuBar extends JMenuBar { @@ -69,8 +69,6 @@ public class MenuBar extends JMenuBar { this.gui.getController().openMappings(this.gui.mappingsFileChooser.getSelectedFile()); } catch (IOException ex) { throw new Error(ex); - } catch (MappingParseException ex) { - JOptionPane.showMessageDialog(this.gui.getFrame(), ex.getMessage()); } } }); diff --git a/src/main/java/cuchaz/enigma/gui/filechooser/FileChooserFolder.java b/src/main/java/cuchaz/enigma/gui/filechooser/FileChooserFolder.java index bd8f0f0b..93ca5d68 100644 --- a/src/main/java/cuchaz/enigma/gui/filechooser/FileChooserFolder.java +++ b/src/main/java/cuchaz/enigma/gui/filechooser/FileChooserFolder.java @@ -2,7 +2,7 @@ package cuchaz.enigma.gui.filechooser; import javax.swing.JFileChooser; -public class FileChooserFolder extends JFileChooser{ +public class FileChooserFolder extends JFileChooser { public FileChooserFolder() { this.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); diff --git a/src/main/java/cuchaz/enigma/gui/highlight/BoxHighlightPainter.java b/src/main/java/cuchaz/enigma/gui/highlight/BoxHighlightPainter.java new file mode 100644 index 00000000..0a730880 --- /dev/null +++ b/src/main/java/cuchaz/enigma/gui/highlight/BoxHighlightPainter.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * 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.highlight; + +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 fillColor; + private Color borderColor; + + protected BoxHighlightPainter(Color fillColor, Color borderColor) { + this.fillColor = fillColor; + this.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 (this.fillColor != null) { + g.setColor(this.fillColor); + g.fillRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4); + } + + // draw a box around the area + g.setColor(this.borderColor); + g.drawRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4); + } + + public 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/main/java/cuchaz/enigma/gui/highlight/DeobfuscatedHighlightPainter.java b/src/main/java/cuchaz/enigma/gui/highlight/DeobfuscatedHighlightPainter.java new file mode 100644 index 00000000..5d572030 --- /dev/null +++ b/src/main/java/cuchaz/enigma/gui/highlight/DeobfuscatedHighlightPainter.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * 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.highlight; + +import java.awt.Color; + +public class DeobfuscatedHighlightPainter extends BoxHighlightPainter { + + public DeobfuscatedHighlightPainter() { + super(new Color(220, 255, 220), new Color(80, 160, 80)); + } +} diff --git a/src/main/java/cuchaz/enigma/gui/highlight/ObfuscatedHighlightPainter.java b/src/main/java/cuchaz/enigma/gui/highlight/ObfuscatedHighlightPainter.java new file mode 100644 index 00000000..ee64d86a --- /dev/null +++ b/src/main/java/cuchaz/enigma/gui/highlight/ObfuscatedHighlightPainter.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * 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.highlight; + +import java.awt.Color; + +public class ObfuscatedHighlightPainter extends BoxHighlightPainter { + + public ObfuscatedHighlightPainter() { + super(new Color(255, 220, 220), new Color(160, 80, 80)); + } +} diff --git a/src/main/java/cuchaz/enigma/gui/highlight/OtherHighlightPainter.java b/src/main/java/cuchaz/enigma/gui/highlight/OtherHighlightPainter.java new file mode 100644 index 00000000..43d8352e --- /dev/null +++ b/src/main/java/cuchaz/enigma/gui/highlight/OtherHighlightPainter.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * 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.highlight; + +import java.awt.Color; + +public class OtherHighlightPainter extends BoxHighlightPainter { + + public OtherHighlightPainter() { + super(null, new Color(180, 180, 180)); + } +} diff --git a/src/main/java/cuchaz/enigma/gui/highlight/SelectionHighlightPainter.java b/src/main/java/cuchaz/enigma/gui/highlight/SelectionHighlightPainter.java new file mode 100644 index 00000000..f772284f --- /dev/null +++ b/src/main/java/cuchaz/enigma/gui/highlight/SelectionHighlightPainter.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * 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.highlight; + +import java.awt.*; + +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/main/java/cuchaz/enigma/gui/node/ClassSelectorClassNode.java b/src/main/java/cuchaz/enigma/gui/node/ClassSelectorClassNode.java new file mode 100644 index 00000000..e0835725 --- /dev/null +++ b/src/main/java/cuchaz/enigma/gui/node/ClassSelectorClassNode.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * 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.node; + +import javax.swing.tree.DefaultMutableTreeNode; + +import cuchaz.enigma.mapping.ClassEntry; + +public class ClassSelectorClassNode extends DefaultMutableTreeNode { + + private ClassEntry classEntry; + + public ClassSelectorClassNode(ClassEntry classEntry) { + this.classEntry = classEntry; + } + + public ClassEntry getClassEntry() { + return this.classEntry; + } + + @Override + public String toString() { + return this.classEntry.getSimpleName(); + } + + @Override + public boolean equals(Object other) { + return other instanceof ClassSelectorClassNode && equals((ClassSelectorClassNode) other); + } + + public boolean equals(ClassSelectorClassNode other) { + return this.classEntry.equals(other.classEntry); + } +} diff --git a/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java b/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java new file mode 100644 index 00000000..805b3a8e --- /dev/null +++ b/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * 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.node; + +import javax.swing.tree.DefaultMutableTreeNode; + +public class ClassSelectorPackageNode extends DefaultMutableTreeNode { + + private String packageName; + + public ClassSelectorPackageNode(String packageName) { + this.packageName = packageName; + } + + @Override + public String toString() { + return this.packageName; + } + + @Override + public boolean equals(Object other) { + return other instanceof ClassSelectorPackageNode && equals((ClassSelectorPackageNode) other); + } + + public boolean equals(ClassSelectorPackageNode other) { + return this.packageName.equals(other.packageName); + } +} diff --git a/src/main/java/cuchaz/enigma/gui/panels/PanelDeobf.java b/src/main/java/cuchaz/enigma/gui/panels/PanelDeobf.java index 2cc8b76a..bba71327 100644 --- a/src/main/java/cuchaz/enigma/gui/panels/PanelDeobf.java +++ b/src/main/java/cuchaz/enigma/gui/panels/PanelDeobf.java @@ -23,6 +23,5 @@ public class PanelDeobf extends JPanel { this.setLayout(new BorderLayout()); this.add(new JLabel("De-obfuscated Classes"), BorderLayout.NORTH); this.add(new JScrollPane(this.deobfClasses), BorderLayout.CENTER); - } } diff --git a/src/main/java/cuchaz/enigma/gui/panels/PanelIdentifier.java b/src/main/java/cuchaz/enigma/gui/panels/PanelIdentifier.java index 4261eb5a..faa023bd 100644 --- a/src/main/java/cuchaz/enigma/gui/panels/PanelIdentifier.java +++ b/src/main/java/cuchaz/enigma/gui/panels/PanelIdentifier.java @@ -8,7 +8,7 @@ import javax.swing.JLabel; import javax.swing.JPanel; import cuchaz.enigma.gui.Gui; -import cuchaz.enigma.gui.GuiTricks; +import cuchaz.enigma.utils.Utils; public class PanelIdentifier extends JPanel { @@ -25,7 +25,7 @@ public class PanelIdentifier extends JPanel { public void clearReference() { this.removeAll(); JLabel label = new JLabel("No identifier selected"); - GuiTricks.unboldLabel(label); + Utils.unboldLabel(label); label.setHorizontalAlignment(JLabel.CENTER); this.add(label); diff --git a/src/main/java/cuchaz/enigma/gui/panels/PanelObf.java b/src/main/java/cuchaz/enigma/gui/panels/PanelObf.java index 3e0374e7..94b384fd 100644 --- a/src/main/java/cuchaz/enigma/gui/panels/PanelObf.java +++ b/src/main/java/cuchaz/enigma/gui/panels/PanelObf.java @@ -19,7 +19,7 @@ public class PanelObf extends JPanel { public PanelObf(Gui gui) { this.gui = gui; - Comparator obfClassComparator = (a, b) -> { + Comparator obfClassComparator = (a, b) -> { String aname = a.getName(); String bname = b.getName(); if (aname.length() != bname.length()) { diff --git a/src/main/java/cuchaz/enigma/mapping/ArgumentEntry.java b/src/main/java/cuchaz/enigma/mapping/ArgumentEntry.java index 83033bc5..1409fc43 100644 --- a/src/main/java/cuchaz/enigma/mapping/ArgumentEntry.java +++ b/src/main/java/cuchaz/enigma/mapping/ArgumentEntry.java @@ -10,17 +10,13 @@ ******************************************************************************/ package cuchaz.enigma.mapping; -import java.io.Serializable; +import cuchaz.enigma.utils.Utils; -import cuchaz.enigma.Util; +public class ArgumentEntry implements Entry { -public class ArgumentEntry implements Entry, Serializable { - - private static final long serialVersionUID = 4472172468162696006L; - - private BehaviorEntry m_behaviorEntry; - private int m_index; - private String m_name; + private BehaviorEntry behaviorEntry; + private int index; + private String name; public ArgumentEntry(BehaviorEntry behaviorEntry, int index, String name) { if (behaviorEntry == null) { @@ -33,44 +29,38 @@ public class ArgumentEntry implements Entry, Serializable { 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; + this.behaviorEntry = behaviorEntry; + this.index = index; + this.name = 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; + this.behaviorEntry = (BehaviorEntry) other.behaviorEntry.cloneToNewClass(new ClassEntry(newClassName)); + this.index = other.index; + this.name = other.name; } public BehaviorEntry getBehaviorEntry() { - return m_behaviorEntry; + return this.behaviorEntry; } public int getIndex() { - return m_index; + return this.index; } @Override public String getName() { - return m_name; + return this.name; } @Override public ClassEntry getClassEntry() { - return m_behaviorEntry.getClassEntry(); + return this.behaviorEntry.getClassEntry(); } @Override public String getClassName() { - return m_behaviorEntry.getClassName(); + return this.behaviorEntry.getClassName(); } @Override @@ -79,20 +69,16 @@ public class ArgumentEntry implements Entry, Serializable { } public String getMethodName() { - return m_behaviorEntry.getName(); + return this.behaviorEntry.getName(); } public Signature getMethodSignature() { - return m_behaviorEntry.getSignature(); + return this.behaviorEntry.getSignature(); } @Override public int hashCode() { - return Util.combineHashesOrdered( - m_behaviorEntry, - Integer.valueOf(m_index).hashCode(), - m_name.hashCode() - ); + return Utils.combineHashesOrdered(this.behaviorEntry, Integer.valueOf(this.index).hashCode(), this.name.hashCode()); } @Override @@ -101,11 +87,11 @@ public class ArgumentEntry implements Entry, Serializable { } public boolean equals(ArgumentEntry other) { - return m_behaviorEntry.equals(other.m_behaviorEntry) && m_index == other.m_index && m_name.equals(other.m_name); + return this.behaviorEntry.equals(other.behaviorEntry) && this.index == other.index && this.name.equals(other.name); } @Override public String toString() { - return m_behaviorEntry.toString() + "(" + m_index + ":" + m_name + ")"; + return this.behaviorEntry.toString() + "(" + this.index + ":" + this.name + ")"; } } diff --git a/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java b/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java index 2b77d6ea..918395f9 100644 --- a/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java +++ b/src/main/java/cuchaz/enigma/mapping/ArgumentMapping.java @@ -10,40 +10,31 @@ ******************************************************************************/ package cuchaz.enigma.mapping; -import java.io.Serializable; +public class ArgumentMapping implements Comparable { -public class ArgumentMapping implements Serializable, Comparable { - - private static final long serialVersionUID = 8610742471440861315L; - - private int m_index; - private String m_name; + private int index; + private String 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; + this.index = index; + this.name = NameValidator.validateArgumentName(name); } public int getIndex() { - return m_index; + return this.index; } public String getName() { - return m_name; + return this.name; } public void setName(String val) { - m_name = NameValidator.validateArgumentName(val); + this.name = NameValidator.validateArgumentName(val); } @Override public int compareTo(ArgumentMapping other) { - return Integer.compare(m_index, other.m_index); + return Integer.compare(this.index, other.index); } } diff --git a/src/main/java/cuchaz/enigma/mapping/ClassEntry.java b/src/main/java/cuchaz/enigma/mapping/ClassEntry.java index c9304d45..a58d0548 100644 --- a/src/main/java/cuchaz/enigma/mapping/ClassEntry.java +++ b/src/main/java/cuchaz/enigma/mapping/ClassEntry.java @@ -12,14 +12,11 @@ package cuchaz.enigma.mapping; import com.google.common.collect.Lists; -import java.io.Serializable; import java.util.List; -public class ClassEntry implements Entry, Serializable { +public class ClassEntry implements Entry { - private static final long serialVersionUID = 4235460580973955811L; - - private String m_name; + private String name; public ClassEntry(String className) { if (className == null) { @@ -29,7 +26,7 @@ public class ClassEntry implements Entry, Serializable { throw new IllegalArgumentException("Class name must be in JVM format. ie, path/to/package/class$inner : " + className); } - m_name = className; + this.name = className; if (isInnerClass() && getInnermostClassName().indexOf('/') >= 0) { throw new IllegalArgumentException("Inner class must not have a package: " + className); @@ -37,17 +34,17 @@ public class ClassEntry implements Entry, Serializable { } public ClassEntry(ClassEntry other) { - m_name = other.m_name; + this.name = other.name; } @Override public String getName() { - return m_name; + return this.name; } @Override public String getClassName() { - return m_name; + return this.name; } @Override @@ -62,7 +59,7 @@ public class ClassEntry implements Entry, Serializable { @Override public int hashCode() { - return m_name.hashCode(); + return this.name.hashCode(); } @Override @@ -71,20 +68,20 @@ public class ClassEntry implements Entry, Serializable { } public boolean equals(ClassEntry other) { - return m_name.equals(other.m_name); + return this.name.equals(other.name); } @Override public String toString() { - return m_name; + return this.name; } public boolean isInnerClass() { - return m_name.lastIndexOf('$') >= 0; + return this.name.lastIndexOf('$') >= 0; } public List getClassChainNames() { - return Lists.newArrayList(m_name.split("\\$")); + return Lists.newArrayList(this.name.split("\\$")); } public List getClassChain() { @@ -102,9 +99,9 @@ public class ClassEntry implements Entry, Serializable { public String getOutermostClassName() { if (isInnerClass()) { - return m_name.substring(0, m_name.indexOf('$')); + return this.name.substring(0, this.name.indexOf('$')); } - return m_name; + return this.name; } public ClassEntry getOutermostClassEntry() { @@ -115,7 +112,7 @@ public class ClassEntry implements Entry, Serializable { if (!isInnerClass()) { throw new Error("This is not an inner class!"); } - return m_name.substring(0, m_name.lastIndexOf('$')); + return this.name.substring(0, this.name.lastIndexOf('$')); } public ClassEntry getOuterClassEntry() { @@ -126,27 +123,27 @@ public class ClassEntry implements Entry, Serializable { if (!isInnerClass()) { throw new Error("This is not an inner class!"); } - return m_name.substring(m_name.lastIndexOf('$') + 1); + return this.name.substring(this.name.lastIndexOf('$') + 1); } public boolean isInDefaultPackage() { - return m_name.indexOf('/') < 0; + return this.name.indexOf('/') < 0; } public String getPackageName() { - int pos = m_name.lastIndexOf('/'); + int pos = this.name.lastIndexOf('/'); if (pos > 0) { - return m_name.substring(0, pos); + return this.name.substring(0, pos); } return null; } public String getSimpleName() { - int pos = m_name.lastIndexOf('/'); + int pos = this.name.lastIndexOf('/'); if (pos > 0) { - return m_name.substring(pos + 1); + return this.name.substring(pos + 1); } - return m_name; + return this.name; } public ClassEntry buildClassEntry(List classChain) { diff --git a/src/main/java/cuchaz/enigma/mapping/ClassMapping.java b/src/main/java/cuchaz/enigma/mapping/ClassMapping.java index f831a3b8..b2c076a3 100644 --- a/src/main/java/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/main/java/cuchaz/enigma/mapping/ClassMapping.java @@ -12,13 +12,11 @@ package cuchaz.enigma.mapping; import com.google.common.collect.Maps; -import java.io.Serializable; -import java.util.ArrayList; import java.util.Map; -public class ClassMapping implements Serializable, Comparable { +import cuchaz.enigma.throwables.MappingConflict; - private static final long serialVersionUID = -5148491146902340107L; +public class ClassMapping implements Comparable { private String m_obfFullName; private String m_obfSimpleName; @@ -70,13 +68,17 @@ public class ClassMapping implements Serializable, Comparable { return m_innerClassesByObfSimple.values(); } - public void addInnerClassMapping(ClassMapping classMapping) { - boolean obfWasAdded = m_innerClassesByObfSimple.put(classMapping.getObfSimpleName(), classMapping) == null; - assert (obfWasAdded); + public void addInnerClassMapping(ClassMapping classMapping) throws MappingConflict { + if (this.m_innerClassesByObfSimple.containsKey(classMapping.getObfSimpleName())) { + throw new MappingConflict("classes", classMapping.getObfSimpleName(), this.m_innerClassesByObfSimple.get(classMapping.getObfSimpleName()).getObfSimpleName()); + } + m_innerClassesByObfSimple.put(classMapping.getObfSimpleName(), classMapping); + if (classMapping.getDeobfName() != null) { - assert (isSimpleClassName(classMapping.getDeobfName())); - boolean deobfWasAdded = m_innerClassesByDeobf.put(classMapping.getDeobfName(), classMapping) == null; - assert (deobfWasAdded); + if (this.m_innerClassesByDeobf.containsKey(classMapping.getDeobfName())) { + throw new MappingConflict("classes", classMapping.getDeobfName(), this.m_innerClassesByDeobf.get(classMapping.getDeobfName()).getDeobfName()); + } + m_innerClassesByDeobf.put(classMapping.getDeobfName(), classMapping); } } @@ -225,17 +227,6 @@ public class ClassMapping implements Serializable, Comparable { } } - 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() { @@ -307,16 +298,6 @@ public class ClassMapping implements Serializable, Comparable { } } - 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) { @@ -388,7 +369,4 @@ public class ClassMapping implements Serializable, Comparable { return name.indexOf('/') < 0 && name.indexOf('$') < 0; } - public ClassEntry getObfEntry() { - return new ClassEntry(m_obfFullName); - } } diff --git a/src/main/java/cuchaz/enigma/mapping/ConstructorEntry.java b/src/main/java/cuchaz/enigma/mapping/ConstructorEntry.java index ac1a7f2b..4c798204 100644 --- a/src/main/java/cuchaz/enigma/mapping/ConstructorEntry.java +++ b/src/main/java/cuchaz/enigma/mapping/ConstructorEntry.java @@ -10,16 +10,12 @@ ******************************************************************************/ package cuchaz.enigma.mapping; -import java.io.Serializable; +import cuchaz.enigma.utils.Utils; -import cuchaz.enigma.Util; +public class ConstructorEntry implements BehaviorEntry { -public class ConstructorEntry implements BehaviorEntry, Serializable { - - private static final long serialVersionUID = -868346075317366758L; - - private ClassEntry m_classEntry; - private Signature m_signature; + private ClassEntry classEntry; + private Signature signature; public ConstructorEntry(ClassEntry classEntry) { this(classEntry, null); @@ -30,23 +26,18 @@ public class ConstructorEntry implements BehaviorEntry, Serializable { 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; + this.classEntry = classEntry; + this.signature = signature; } public ConstructorEntry(ConstructorEntry other, String newClassName) { - m_classEntry = new ClassEntry(newClassName); - m_signature = other.m_signature; + this.classEntry = new ClassEntry(newClassName); + this.signature = other.signature; } @Override public ClassEntry getClassEntry() { - return m_classEntry; + return this.classEntry; } @Override @@ -58,17 +49,17 @@ public class ConstructorEntry implements BehaviorEntry, Serializable { } public boolean isStatic() { - return m_signature == null; + return this.signature == null; } @Override public Signature getSignature() { - return m_signature; + return this.signature; } @Override public String getClassName() { - return m_classEntry.getName(); + return this.classEntry.getName(); } @Override @@ -79,9 +70,9 @@ public class ConstructorEntry implements BehaviorEntry, Serializable { @Override public int hashCode() { if (isStatic()) { - return Util.combineHashesOrdered(m_classEntry); + return Utils.combineHashesOrdered(this.classEntry); } else { - return Util.combineHashesOrdered(m_classEntry, m_signature); + return Utils.combineHashesOrdered(this.classEntry, this.signature); } } @@ -96,18 +87,18 @@ public class ConstructorEntry implements BehaviorEntry, Serializable { } if (isStatic()) { - return m_classEntry.equals(other.m_classEntry); + return this.classEntry.equals(other.classEntry); } else { - return m_classEntry.equals(other.m_classEntry) && m_signature.equals(other.m_signature); + return this.classEntry.equals(other.classEntry) && this.signature.equals(other.signature); } } @Override public String toString() { if (isStatic()) { - return m_classEntry.getName() + "." + getName(); + return this.classEntry.getName() + "." + getName(); } else { - return m_classEntry.getName() + "." + getName() + m_signature; + return this.classEntry.getName() + "." + getName() + this.signature; } } } diff --git a/src/main/java/cuchaz/enigma/mapping/EntryFactory.java b/src/main/java/cuchaz/enigma/mapping/EntryFactory.java index 3584ebbf..2351dcfb 100644 --- a/src/main/java/cuchaz/enigma/mapping/EntryFactory.java +++ b/src/main/java/cuchaz/enigma/mapping/EntryFactory.java @@ -38,19 +38,11 @@ public class EntryFactory { } public static FieldEntry getFieldEntry(CtField field) { - return new FieldEntry( - getClassEntry(field.getDeclaringClass()), - field.getName(), - new Type(field.getFieldInfo().getDescriptor()) - ); + 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()) - ); + 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) { @@ -58,19 +50,11 @@ public class EntryFactory { } public static FieldEntry getObfFieldEntry(ClassMapping classMapping, FieldMapping fieldMapping) { - return new FieldEntry( - getObfClassEntry(classMapping), - fieldMapping.getObfName(), - fieldMapping.getObfType() - ); + 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()) - ); + return new MethodEntry(getClassEntry(method.getDeclaringClass()), method.getName(), new Signature(method.getMethodInfo().getDescriptor())); } public static MethodEntry getMethodEntry(MethodCall call) { @@ -106,10 +90,6 @@ public class EntryFactory { 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)); } @@ -125,14 +105,6 @@ public class EntryFactory { } } - 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()); } diff --git a/src/main/java/cuchaz/enigma/mapping/FieldEntry.java b/src/main/java/cuchaz/enigma/mapping/FieldEntry.java index bebc5045..9980e8e6 100644 --- a/src/main/java/cuchaz/enigma/mapping/FieldEntry.java +++ b/src/main/java/cuchaz/enigma/mapping/FieldEntry.java @@ -10,17 +10,13 @@ ******************************************************************************/ package cuchaz.enigma.mapping; -import java.io.Serializable; +import cuchaz.enigma.utils.Utils; -import cuchaz.enigma.Util; +public class FieldEntry implements Entry { -public class FieldEntry implements Entry, Serializable { - - private static final long serialVersionUID = 3004663582802885451L; - - private ClassEntry m_classEntry; - private String m_name; - private Type m_type; + private ClassEntry classEntry; + private String name; + private Type type; // NOTE: this argument order is important for the MethodReader/MethodWriter public FieldEntry(ClassEntry classEntry, String name, Type type) { @@ -34,38 +30,34 @@ public class FieldEntry implements Entry, Serializable { 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)); + this.classEntry = classEntry; + this.name = name; + this.type = type; } public FieldEntry(FieldEntry other, ClassEntry newClassEntry) { - m_classEntry = newClassEntry; - m_name = other.m_name; - m_type = other.m_type; + this.classEntry = newClassEntry; + this.name = other.name; + this.type = other.type; } @Override public ClassEntry getClassEntry() { - return m_classEntry; + return this.classEntry; } @Override public String getName() { - return m_name; + return this.name; } @Override public String getClassName() { - return m_classEntry.getName(); + return this.classEntry.getName(); } public Type getType() { - return m_type; + return this.type; } @Override @@ -75,7 +67,7 @@ public class FieldEntry implements Entry, Serializable { @Override public int hashCode() { - return Util.combineHashesOrdered(m_classEntry, m_name, m_type); + return Utils.combineHashesOrdered(this.classEntry, this.name, this.type); } @Override @@ -84,13 +76,11 @@ public class FieldEntry implements Entry, Serializable { } public boolean equals(FieldEntry other) { - return m_classEntry.equals(other.m_classEntry) - && m_name.equals(other.m_name) - && m_type.equals(other.m_type); + return this.classEntry.equals(other.classEntry) && this.name.equals(other.name) && this.type.equals(other.type); } @Override public String toString() { - return m_classEntry.getName() + "." + m_name + ":" + m_type; + return this.classEntry.getName() + "." + this.name + ":" + this.type; } } diff --git a/src/main/java/cuchaz/enigma/mapping/FieldMapping.java b/src/main/java/cuchaz/enigma/mapping/FieldMapping.java index 19d68a97..3ec1af0d 100644 --- a/src/main/java/cuchaz/enigma/mapping/FieldMapping.java +++ b/src/main/java/cuchaz/enigma/mapping/FieldMapping.java @@ -10,11 +10,7 @@ ******************************************************************************/ package cuchaz.enigma.mapping; -import java.io.Serializable; - -public class FieldMapping implements Serializable, Comparable, MemberMapping { - - private static final long serialVersionUID = 8610742471440861315L; +public class FieldMapping implements Comparable, MemberMapping { private String obfName; private String deobfName; @@ -26,21 +22,11 @@ public class FieldMapping implements Serializable, Comparable, Mem this.obfType = obfType; } - public FieldMapping(FieldMapping other, ClassNameReplacer obfClassNameReplacer) { - this.obfName = other.obfName; - this.deobfName = other.deobfName; - this.obfType = new Type(other.obfType, obfClassNameReplacer); - } - @Override public String getObfName() { return this.obfName; } - public void setObfName(String val) { - this.obfName = NameValidator.validateFieldName(val); - } - public String getDeobfName() { return this.deobfName; } @@ -53,34 +39,8 @@ public class FieldMapping implements Serializable, Comparable, Mem return this.obfType; } - public void setObfType(Type val) { - this.obfType = val; - } - @Override public int compareTo(FieldMapping other) { return (this.obfName + this.obfType).compareTo(other.obfName + other.obfType); } - - public boolean renameObfClass(final String oldObfClassName, final String newObfClassName) { - - // rename obf classes in the type - Type newType = new Type(this.obfType, className -> { - if (className.equals(oldObfClassName)) { - return newObfClassName; - } - return null; - }); - - if (!newType.equals(this.obfType)) { - this.obfType = newType; - return true; - } - return false; - } - - @Override - public FieldEntry getObfEntry(ClassEntry classEntry) { - return new FieldEntry(classEntry, this.obfName, new Type(this.obfType)); - } } diff --git a/src/main/java/cuchaz/enigma/mapping/IllegalNameException.java b/src/main/java/cuchaz/enigma/mapping/IllegalNameException.java deleted file mode 100644 index f2119d8d..00000000 --- a/src/main/java/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/main/java/cuchaz/enigma/mapping/MappingParseException.java b/src/main/java/cuchaz/enigma/mapping/MappingParseException.java deleted file mode 100644 index 3c25ea58..00000000 --- a/src/main/java/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/main/java/cuchaz/enigma/mapping/Mappings.java b/src/main/java/cuchaz/enigma/mapping/Mappings.java index ee4c3023..b51e1a4c 100644 --- a/src/main/java/cuchaz/enigma/mapping/Mappings.java +++ b/src/main/java/cuchaz/enigma/mapping/Mappings.java @@ -12,85 +12,64 @@ package cuchaz.enigma.mapping; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import java.io.Serializable; -import java.util.*; +import java.util.Collection; +import java.util.List; +import java.util.Map; import cuchaz.enigma.analysis.TranslationIndex; +import cuchaz.enigma.throwables.MappingConflict; -public class Mappings implements Serializable { +public class Mappings { - private static final long serialVersionUID = 4649790259460259026L; - - protected Map m_classesByObf; - protected Map m_classesByDeobf; + protected Map classesByObf; + protected Map 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); - } - } + this.classesByObf = Maps.newHashMap(); + this.classesByDeobf = Maps.newHashMap(); } public Collection classes() { - assert (m_classesByObf.size() >= m_classesByDeobf.size()); - return m_classesByObf.values(); + assert (this.classesByObf.size() >= this.classesByDeobf.size()); + return this.classesByObf.values(); } - public void addClassMapping(ClassMapping classMapping) { - if (m_classesByObf.containsKey(classMapping.getObfFullName())) { - throw new Error("Already have mapping for " + classMapping.getObfFullName()); + public void addClassMapping(ClassMapping classMapping) throws MappingConflict { + if (this.classesByObf.containsKey(classMapping.getObfFullName())) { + throw new MappingConflict("class", classMapping.getObfFullName(), this.classesByObf.get(classMapping.getObfFullName()).getObfFullName()); } - boolean obfWasAdded = m_classesByObf.put(classMapping.getObfFullName(), classMapping) == null; - assert (obfWasAdded); + this.classesByObf.put(classMapping.getObfFullName(), classMapping); + if (classMapping.getDeobfName() != null) { - if (m_classesByDeobf.containsKey(classMapping.getDeobfName())) { - throw new Error("Already have mapping for " + classMapping.getDeobfName()); + if (this.classesByDeobf.containsKey(classMapping.getDeobfName())) { + throw new MappingConflict("class", classMapping.getDeobfName(), this.classesByDeobf.get(classMapping.getDeobfName()).getDeobfName()); } - boolean deobfWasAdded = m_classesByDeobf.put(classMapping.getDeobfName(), classMapping) == null; - assert (deobfWasAdded); + this.classesByDeobf.put(classMapping.getDeobfName(), classMapping); } } public void removeClassMapping(ClassMapping classMapping) { - boolean obfWasRemoved = m_classesByObf.remove(classMapping.getObfFullName()) != null; + boolean obfWasRemoved = this.classesByObf.remove(classMapping.getObfFullName()) != null; assert (obfWasRemoved); if (classMapping.getDeobfName() != null) { - boolean deobfWasRemoved = m_classesByDeobf.remove(classMapping.getDeobfName()) != null; + boolean deobfWasRemoved = this.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(String deobfName) { - return m_classesByDeobf.get(deobfName); + return this.classesByObf.get(obfName); } public void setClassDeobfName(ClassMapping classMapping, String deobfName) { if (classMapping.getDeobfName() != null) { - boolean wasRemoved = m_classesByDeobf.remove(classMapping.getDeobfName()) != null; + boolean wasRemoved = this.classesByDeobf.remove(classMapping.getDeobfName()) != null; assert (wasRemoved); } classMapping.setDeobfName(deobfName); if (deobfName != null) { - boolean wasAdded = m_classesByDeobf.put(deobfName, classMapping) == null; + boolean wasAdded = this.classesByDeobf.put(deobfName, classMapping) == null; assert (wasAdded); } } @@ -99,7 +78,7 @@ public class Mappings implements Serializable { switch (direction) { case Deobfuscating: - return new Translator(direction, m_classesByObf, index); + return new Translator(direction, this.classesByObf, index); case Obfuscating: @@ -127,7 +106,7 @@ public class Mappings implements Serializable { @Override public String toString() { StringBuilder buf = new StringBuilder(); - for (ClassMapping classMapping : m_classesByObf.values()) { + for (ClassMapping classMapping : this.classesByObf.values()) { buf.append(classMapping.toString()); buf.append("\n"); } @@ -135,21 +114,21 @@ public class Mappings implements Serializable { } public boolean containsDeobfClass(String deobfName) { - return m_classesByDeobf.containsKey(deobfName); + return this.classesByDeobf.containsKey(deobfName); } public boolean containsDeobfField(ClassEntry obfClassEntry, String deobfName, Type obfType) { - ClassMapping classMapping = m_classesByObf.get(obfClassEntry.getName()); + ClassMapping classMapping = this.classesByObf.get(obfClassEntry.getName()); return classMapping != null && classMapping.containsDeobfField(deobfName, obfType); } public boolean containsDeobfMethod(ClassEntry obfClassEntry, String deobfName, Signature deobfSignature) { - ClassMapping classMapping = m_classesByObf.get(obfClassEntry.getName()); + ClassMapping classMapping = this.classesByObf.get(obfClassEntry.getName()); return classMapping != null && classMapping.containsDeobfMethod(deobfName, deobfSignature); } public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) { - ClassMapping classMapping = m_classesByObf.get(obfBehaviorEntry.getClassName()); + ClassMapping classMapping = this.classesByObf.get(obfBehaviorEntry.getClassName()); return classMapping != null && classMapping.containsArgument(obfBehaviorEntry, name); } @@ -158,7 +137,7 @@ public class Mappings implements Serializable { ClassMapping classMapping = null; for (ClassEntry obfClassEntry : obfClass.getClassChain()) { if (mappingChain.isEmpty()) { - classMapping = m_classesByObf.get(obfClassEntry.getName()); + classMapping = this.classesByObf.get(obfClassEntry.getName()); } else if (classMapping != null) { classMapping = classMapping.getInnerClassByObfSimple(obfClassEntry.getInnermostClassName()); } diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsChecker.java b/src/main/java/cuchaz/enigma/mapping/MappingsChecker.java index d8507877..6cf279d1 100644 --- a/src/main/java/cuchaz/enigma/mapping/MappingsChecker.java +++ b/src/main/java/cuchaz/enigma/mapping/MappingsChecker.java @@ -20,41 +20,41 @@ import cuchaz.enigma.analysis.JarIndex; public class MappingsChecker { - private JarIndex m_index; - private Map m_droppedClassMappings; - private Map m_droppedInnerClassMappings; - private Map m_droppedFieldMappings; - private Map m_droppedMethodMappings; + private JarIndex index; + private Map droppedClassMappings; + private Map droppedInnerClassMappings; + private Map droppedFieldMappings; + private Map droppedMethodMappings; public MappingsChecker(JarIndex index) { - m_index = index; - m_droppedClassMappings = Maps.newHashMap(); - m_droppedInnerClassMappings = Maps.newHashMap(); - m_droppedFieldMappings = Maps.newHashMap(); - m_droppedMethodMappings = Maps.newHashMap(); + this.index = index; + this.droppedClassMappings = Maps.newHashMap(); + this.droppedInnerClassMappings = Maps.newHashMap(); + this.droppedFieldMappings = Maps.newHashMap(); + this.droppedMethodMappings = Maps.newHashMap(); } public Map getDroppedClassMappings() { - return m_droppedClassMappings; + return this.droppedClassMappings; } public Map getDroppedInnerClassMappings() { - return m_droppedInnerClassMappings; + return this.droppedInnerClassMappings; } public Map getDroppedFieldMappings() { - return m_droppedFieldMappings; + return this.droppedFieldMappings; } public Map getDroppedMethodMappings() { - return m_droppedMethodMappings; + return this.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); + this.droppedClassMappings.put(EntryFactory.getObfClassEntry(this.index, classMapping), classMapping); } } } @@ -62,26 +62,26 @@ public class MappingsChecker { private boolean checkClassMapping(ClassMapping classMapping) { // check the class - ClassEntry classEntry = EntryFactory.getObfClassEntry(m_index, classMapping); - if (!m_index.getObfClassEntries().contains(classEntry)) { + ClassEntry classEntry = EntryFactory.getObfClassEntry(this.index, classMapping); + if (!this.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)) { + if (!this.index.containsObfField(obfFieldEntry)) { classMapping.removeFieldMapping(fieldMapping); - m_droppedFieldMappings.put(obfFieldEntry, fieldMapping); + this.droppedFieldMappings.put(obfFieldEntry, fieldMapping); } } // check methods for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) { BehaviorEntry obfBehaviorEntry = EntryFactory.getObfBehaviorEntry(classEntry, methodMapping); - if (!m_index.containsObfBehavior(obfBehaviorEntry)) { + if (!this.index.containsObfBehavior(obfBehaviorEntry)) { classMapping.removeMethodMapping(methodMapping); - m_droppedMethodMappings.put(obfBehaviorEntry, methodMapping); + this.droppedMethodMappings.put(obfBehaviorEntry, methodMapping); } } @@ -89,7 +89,7 @@ public class MappingsChecker { for (ClassMapping innerClassMapping : Lists.newArrayList(classMapping.innerClasses())) { if (!checkClassMapping(innerClassMapping)) { classMapping.removeInnerClassMapping(innerClassMapping); - m_droppedInnerClassMappings.put(EntryFactory.getObfClassEntry(m_index, innerClassMapping), innerClassMapping); + this.droppedInnerClassMappings.put(EntryFactory.getObfClassEntry(this.index, innerClassMapping), innerClassMapping); } } diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsReader.java b/src/main/java/cuchaz/enigma/mapping/MappingsReader.java index 7aedc5b1..b2b6d09c 100644 --- a/src/main/java/cuchaz/enigma/mapping/MappingsReader.java +++ b/src/main/java/cuchaz/enigma/mapping/MappingsReader.java @@ -20,17 +20,17 @@ import java.io.FileReader; import java.io.IOException; import cuchaz.enigma.json.JsonClass; +import cuchaz.enigma.throwables.MappingConflict; public class MappingsReader { - public Mappings read(File in) throws IOException, MappingParseException { + public Mappings read(File in) throws IOException { Mappings mappings = new Mappings(); readDirectory(mappings, in); return mappings; } - public void readDirectory(Mappings mappings, File in) throws IOException, MappingParseException { - + public void readDirectory(Mappings mappings, File in) throws IOException { File[] fList = in.listFiles(); if (fList != null) { for (File file : fList) { @@ -43,8 +43,7 @@ public class MappingsReader { } } - public void readFile(Mappings mappings, BufferedReader in) throws IOException, MappingParseException { - + public void readFile(Mappings mappings, BufferedReader in) throws IOException { StringBuilder buf = new StringBuilder(); String line; while ((line = in.readLine()) != null) { @@ -53,11 +52,15 @@ public class MappingsReader { Gson gson = new GsonBuilder().setPrettyPrinting().create(); JsonClass jsonClass = gson.fromJson(buf.toString(), JsonClass.class); - load(null, jsonClass, mappings); + try { + load(null, jsonClass, mappings); + } catch (MappingConflict e) { + e.printStackTrace(); + } in.close(); } - public void load(ClassMapping parent, JsonClass jsonClass, Mappings mappings) { + public void load(ClassMapping parent, JsonClass jsonClass, Mappings mappings) throws MappingConflict { ClassMapping classMapping = readClass(jsonClass.getObf(), jsonClass.getName()); if (parent != null) { parent.addInnerClassMapping(classMapping); @@ -68,17 +71,35 @@ public class MappingsReader { jsonClass.getConstructors().forEach(jsonConstructor -> { MethodMapping methodMapping = readMethod(jsonConstructor.isStatics() ? "" : "", null, jsonConstructor.getSignature()); - jsonConstructor.getArgs().forEach(jsonArgument -> methodMapping.addArgumentMapping(readArgument(jsonArgument.getIndex(), jsonArgument.getName()))); + jsonConstructor.getArgs().forEach(jsonArgument -> { + try { + methodMapping.addArgumentMapping(readArgument(jsonArgument.getIndex(), jsonArgument.getName())); + } catch (MappingConflict e) { + e.printStackTrace(); + } + }); classMapping.addMethodMapping(methodMapping); }); jsonClass.getMethod().forEach(jsonMethod -> { MethodMapping methodMapping = readMethod(jsonMethod.getObf(), jsonMethod.getName(), jsonMethod.getSignature()); - jsonMethod.getArgs().forEach(jsonArgument -> methodMapping.addArgumentMapping(readArgument(jsonArgument.getIndex(), jsonArgument.getName()))); + jsonMethod.getArgs().forEach(jsonArgument -> { + try { + methodMapping.addArgumentMapping(readArgument(jsonArgument.getIndex(), jsonArgument.getName())); + } catch (MappingConflict e) { + e.printStackTrace(); + } + }); classMapping.addMethodMapping(methodMapping); }); - jsonClass.getInnerClass().forEach(jsonInnerClasses -> load(classMapping, jsonInnerClasses, mappings)); + jsonClass.getInnerClass().forEach(jsonInnerClasses -> { + try { + load(classMapping, jsonInnerClasses, mappings); + } catch (MappingConflict e) { + e.printStackTrace(); + } + }); } private ArgumentMapping readArgument(int index, String name) { diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsReaderOld.java b/src/main/java/cuchaz/enigma/mapping/MappingsReaderOld.java index ed36d423..776d9083 100644 --- a/src/main/java/cuchaz/enigma/mapping/MappingsReaderOld.java +++ b/src/main/java/cuchaz/enigma/mapping/MappingsReaderOld.java @@ -7,6 +7,9 @@ import java.io.IOException; import java.io.Reader; import java.util.Deque; +import cuchaz.enigma.throwables.MappingConflict; +import cuchaz.enigma.throwables.MappingParseException; + public class MappingsReaderOld { public Mappings read(Reader in) throws IOException, MappingParseException { @@ -89,6 +92,8 @@ public class MappingsReaderOld { } } catch (ArrayIndexOutOfBoundsException | IllegalArgumentException ex) { throw new MappingParseException(lineNumber, "Malformed line:\n" + line); + } catch (MappingConflict e) { + e.printStackTrace(); } } diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java b/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java index 3050da6b..afb8c978 100644 --- a/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java +++ b/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java @@ -10,14 +10,12 @@ ******************************************************************************/ 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; +import cuchaz.enigma.throwables.IllegalNameException; +import cuchaz.enigma.throwables.MappingConflict; public class MappingsRenamer { @@ -167,14 +165,6 @@ public class MappingsRenamer { classMapping.setArgumentName(obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), obf.getName()); } - 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); @@ -193,10 +183,14 @@ public class MappingsRenamer { mappingChain.set(i, classMapping); // add it to the right parent - if (i == 0) { - m_mappings.addClassMapping(classMapping); - } else { - mappingChain.get(i - 1).addInnerClassMapping(classMapping); + try { + if (i == 0) { + m_mappings.addClassMapping(classMapping); + } else { + mappingChain.get(i - 1).addInnerClassMapping(classMapping); + } + } catch (MappingConflict mappingConflict) { + mappingConflict.printStackTrace(); } } } diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsWriter.java b/src/main/java/cuchaz/enigma/mapping/MappingsWriter.java index 4b2db9dc..47931662 100644 --- a/src/main/java/cuchaz/enigma/mapping/MappingsWriter.java +++ b/src/main/java/cuchaz/enigma/mapping/MappingsWriter.java @@ -51,7 +51,7 @@ public class MappingsWriter { } } - private void write(JsonClass jsonClass, ClassMapping classMapping) throws IOException { + private void write(JsonClass jsonClass, ClassMapping classMapping) { for (ClassMapping innerClassMapping : sorted(classMapping.innerClasses())) { JsonClass innerClass = new JsonClass(classMapping.getObfSimpleName() + "$" + innerClassMapping.getObfSimpleName().replace("nome/", ""), innerClassMapping.getDeobfName()); write(innerClass, innerClassMapping); @@ -85,19 +85,18 @@ public class MappingsWriter { } public static boolean deleteDirectory(File directory) { - if(directory.exists()){ + if (directory.exists()) { File[] files = directory.listFiles(); - if(null!=files){ - for(int i=0; i { - T getObfEntry(ClassEntry classEntry); - String getObfName(); } diff --git a/src/main/java/cuchaz/enigma/mapping/MethodEntry.java b/src/main/java/cuchaz/enigma/mapping/MethodEntry.java index 7df4dd86..4d7ed8f0 100644 --- a/src/main/java/cuchaz/enigma/mapping/MethodEntry.java +++ b/src/main/java/cuchaz/enigma/mapping/MethodEntry.java @@ -10,17 +10,13 @@ ******************************************************************************/ package cuchaz.enigma.mapping; -import java.io.Serializable; +import cuchaz.enigma.utils.Utils; -import cuchaz.enigma.Util; +public class MethodEntry implements BehaviorEntry { -public class MethodEntry implements BehaviorEntry, Serializable { - - private static final long serialVersionUID = 4770915224467247458L; - - private ClassEntry m_classEntry; - private String m_name; - private Signature m_signature; + private ClassEntry classEntry; + private String name; + private Signature signature; public MethodEntry(ClassEntry classEntry, String name, Signature signature) { if (classEntry == null) { @@ -36,41 +32,35 @@ public class MethodEntry implements BehaviorEntry, Serializable { 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; + this.classEntry = classEntry; + this.name = name; + this.signature = signature; } public MethodEntry(MethodEntry other, String newClassName) { - m_classEntry = new ClassEntry(newClassName); - m_name = other.m_name; - m_signature = other.m_signature; + this.classEntry = new ClassEntry(newClassName); + this.name = other.name; + this.signature = other.signature; } @Override public ClassEntry getClassEntry() { - return m_classEntry; + return this.classEntry; } @Override public String getName() { - return m_name; + return this.name; } @Override public Signature getSignature() { - return m_signature; + return this.signature; } @Override public String getClassName() { - return m_classEntry.getName(); + return this.classEntry.getName(); } @Override @@ -80,7 +70,7 @@ public class MethodEntry implements BehaviorEntry, Serializable { @Override public int hashCode() { - return Util.combineHashesOrdered(m_classEntry, m_name, m_signature); + return Utils.combineHashesOrdered(this.classEntry, this.name, this.signature); } @Override @@ -89,11 +79,11 @@ public class MethodEntry implements BehaviorEntry, Serializable { } public boolean equals(MethodEntry other) { - return m_classEntry.equals(other.m_classEntry) && m_name.equals(other.m_name) && m_signature.equals(other.m_signature); + return this.classEntry.equals(other.classEntry) && this.name.equals(other.name) && this.signature.equals(other.signature); } @Override public String toString() { - return m_classEntry.getName() + "." + m_name + m_signature; + return this.classEntry.getName() + "." + this.name + this.signature; } } diff --git a/src/main/java/cuchaz/enigma/mapping/MethodMapping.java b/src/main/java/cuchaz/enigma/mapping/MethodMapping.java index fbd97bd1..6e7c1ef9 100644 --- a/src/main/java/cuchaz/enigma/mapping/MethodMapping.java +++ b/src/main/java/cuchaz/enigma/mapping/MethodMapping.java @@ -12,18 +12,16 @@ package cuchaz.enigma.mapping; import com.google.common.collect.Maps; -import java.io.Serializable; import java.util.Map; -import java.util.Map.Entry; -public class MethodMapping implements Serializable, Comparable, MemberMapping { +import cuchaz.enigma.throwables.MappingConflict; - private static final long serialVersionUID = -4409570216084263978L; +public class MethodMapping implements Comparable, MemberMapping { - private String m_obfName; - private String m_deobfName; - private Signature m_obfSignature; - private Map m_arguments; + private String obfName; + private String deobfName; + private Signature obfSignature; + private Map arguments; public MethodMapping(String obfName, Signature obfSignature) { this(obfName, obfSignature, null); @@ -36,62 +34,42 @@ public class MethodMapping implements Serializable, Comparable, M if (obfSignature == null) { throw new IllegalArgumentException("obf signature cannot be null!"); } - this.m_obfName = obfName; - this.m_deobfName = NameValidator.validateMethodName(deobfName); - this.m_obfSignature = obfSignature; - this.m_arguments = Maps.newTreeMap(); - } - - public MethodMapping(MethodMapping other, ClassNameReplacer obfClassNameReplacer) { - this.m_obfName = other.m_obfName; - this.m_deobfName = other.m_deobfName; - this.m_obfSignature = new Signature(other.m_obfSignature, obfClassNameReplacer); - this.m_arguments = Maps.newTreeMap(); - for (Entry entry : other.m_arguments.entrySet()) { - this.m_arguments.put(entry.getKey(), new ArgumentMapping(entry.getValue())); - } + this.obfName = obfName; + this.deobfName = NameValidator.validateMethodName(deobfName); + this.obfSignature = obfSignature; + this.arguments = Maps.newTreeMap(); } @Override public String getObfName() { - return this.m_obfName; - } - - public void setObfName(String val) { - this.m_obfName = NameValidator.validateMethodName(val); + return this.obfName; } public String getDeobfName() { - return this.m_deobfName; + return this.deobfName; } public void setDeobfName(String val) { - this.m_deobfName = NameValidator.validateMethodName(val); + this.deobfName = NameValidator.validateMethodName(val); } public Signature getObfSignature() { - return this.m_obfSignature; - } - - public void setObfSignature(Signature val) { - this.m_obfSignature = val; + return this.obfSignature; } public Iterable arguments() { - return this.m_arguments.values(); + return this.arguments.values(); } - public boolean isConstructor() { - return this.m_obfName.startsWith("<"); - } - - public void addArgumentMapping(ArgumentMapping argumentMapping) { - boolean wasAdded = this.m_arguments.put(argumentMapping.getIndex(), argumentMapping) == null; - assert (wasAdded); + public void addArgumentMapping(ArgumentMapping argumentMapping) throws MappingConflict { + if (this.arguments.containsKey(argumentMapping.getIndex())) { + throw new MappingConflict("argument", argumentMapping.getName(), this.arguments.get(argumentMapping.getIndex()).getName()); + } + this.arguments.put(argumentMapping.getIndex(), argumentMapping); } public String getObfArgumentName(int index) { - ArgumentMapping argumentMapping = this.m_arguments.get(index); + ArgumentMapping argumentMapping = this.arguments.get(index); if (argumentMapping != null) { return argumentMapping.getName(); } @@ -100,7 +78,7 @@ public class MethodMapping implements Serializable, Comparable, M } public String getDeobfArgumentName(int index) { - ArgumentMapping argumentMapping = this.m_arguments.get(index); + ArgumentMapping argumentMapping = this.arguments.get(index); if (argumentMapping != null) { return argumentMapping.getName(); } @@ -109,10 +87,10 @@ public class MethodMapping implements Serializable, Comparable, M } public void setArgumentName(int index, String name) { - ArgumentMapping argumentMapping = this.m_arguments.get(index); + ArgumentMapping argumentMapping = this.arguments.get(index); if (argumentMapping == null) { argumentMapping = new ArgumentMapping(index, name); - boolean wasAdded = this.m_arguments.put(index, argumentMapping) == null; + boolean wasAdded = this.arguments.put(index, argumentMapping) == null; assert (wasAdded); } else { argumentMapping.setName(name); @@ -120,7 +98,7 @@ public class MethodMapping implements Serializable, Comparable, M } public void removeArgumentName(int index) { - boolean wasRemoved = this.m_arguments.remove(index) != null; + boolean wasRemoved = this.arguments.remove(index) != null; assert (wasRemoved); } @@ -128,15 +106,15 @@ public class MethodMapping implements Serializable, Comparable, M public String toString() { StringBuilder buf = new StringBuilder(); buf.append("\t"); - buf.append(m_obfName); + buf.append(this.obfName); buf.append(" <-> "); - buf.append(m_deobfName); + buf.append(this.deobfName); buf.append("\n"); buf.append("\t"); - buf.append(m_obfSignature); + buf.append(this.obfSignature); buf.append("\n"); buf.append("\tArguments:\n"); - for (ArgumentMapping argumentMapping : this.m_arguments.values()) { + for (ArgumentMapping argumentMapping : this.arguments.values()) { buf.append("\t\t"); buf.append(argumentMapping.getIndex()); buf.append(" -> "); @@ -148,24 +126,15 @@ public class MethodMapping implements Serializable, Comparable, M @Override public int compareTo(MethodMapping other) { - return (this.m_obfName + this.m_obfSignature).compareTo(other.m_obfName + other.m_obfSignature); + return (this.obfName + this.obfSignature).compareTo(other.obfName + other.obfSignature); } public boolean containsArgument(String name) { - for (ArgumentMapping argumentMapping : this.m_arguments.values()) { + for (ArgumentMapping argumentMapping : this.arguments.values()) { if (argumentMapping.getName().equals(name)) { return true; } } return false; } - - @Override - public BehaviorEntry getObfEntry(ClassEntry classEntry) { - if (isConstructor()) { - return new ConstructorEntry(classEntry, this.m_obfSignature); - } else { - return new MethodEntry(classEntry, this.m_obfName, this.m_obfSignature); - } - } } diff --git a/src/main/java/cuchaz/enigma/mapping/NameValidator.java b/src/main/java/cuchaz/enigma/mapping/NameValidator.java index f416322b..15b0314c 100644 --- a/src/main/java/cuchaz/enigma/mapping/NameValidator.java +++ b/src/main/java/cuchaz/enigma/mapping/NameValidator.java @@ -14,6 +14,7 @@ import java.util.Arrays; import java.util.List; import java.util.regex.Pattern; +import cuchaz.enigma.throwables.IllegalNameException; import javassist.bytecode.Descriptor; public class NameValidator { diff --git a/src/main/java/cuchaz/enigma/mapping/ProcyonEntryFactory.java b/src/main/java/cuchaz/enigma/mapping/ProcyonEntryFactory.java index ac424996..26e554b9 100644 --- a/src/main/java/cuchaz/enigma/mapping/ProcyonEntryFactory.java +++ b/src/main/java/cuchaz/enigma/mapping/ProcyonEntryFactory.java @@ -13,35 +13,21 @@ 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()) - ); + 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()) - ); + 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()) - ); + return new ConstructorEntry(new ClassEntry(def.getDeclaringType().getInternalName())); } else { - return new ConstructorEntry( - new ClassEntry(def.getDeclaringType().getInternalName()), - new Signature(def.getErasedSignature()) - ); + return new ConstructorEntry(new ClassEntry(def.getDeclaringType().getInternalName()), new Signature(def.getErasedSignature())); } } diff --git a/src/main/java/cuchaz/enigma/mapping/Signature.java b/src/main/java/cuchaz/enigma/mapping/Signature.java index e2f9f091..f30b6069 100644 --- a/src/main/java/cuchaz/enigma/mapping/Signature.java +++ b/src/main/java/cuchaz/enigma/mapping/Signature.java @@ -12,80 +12,72 @@ package cuchaz.enigma.mapping; import com.google.common.collect.Lists; -import java.io.Serializable; import java.util.List; -import cuchaz.enigma.Util; +import cuchaz.enigma.utils.Utils; -public class Signature implements Serializable { +public class Signature { - private static final long serialVersionUID = -5843719505729497539L; - - private List m_argumentTypes; - private Type m_returnType; + private List argumentTypes; + private Type returnType; public Signature(String signature) { try { - m_argumentTypes = Lists.newArrayList(); + this.argumentTypes = Lists.newArrayList(); int i = 0; while (i < signature.length()) { char c = signature.charAt(i); if (c == '(') { - assert (m_argumentTypes.isEmpty()); - assert (m_returnType == null); + assert (this.argumentTypes.isEmpty()); + assert (this.returnType == null); i++; } else if (c == ')') { i++; break; } else { String type = Type.parseFirst(signature.substring(i)); - m_argumentTypes.add(new Type(type)); + this.argumentTypes.add(new Type(type)); i += type.length(); } } - m_returnType = new Type(Type.parseFirst(signature.substring(i))); + this.returnType = new Type(Type.parseFirst(signature.substring(i))); } catch (Exception ex) { throw new IllegalArgumentException("Unable to parse signature: " + signature, ex); } } - public Signature(Signature other) { - m_argumentTypes = Lists.newArrayList(other.m_argumentTypes); - m_returnType = new Type(other.m_returnType); - } - public Signature(Signature other, ClassNameReplacer replacer) { - m_argumentTypes = Lists.newArrayList(other.m_argumentTypes); - for (int i = 0; i < m_argumentTypes.size(); i++) { - m_argumentTypes.set(i, new Type(m_argumentTypes.get(i), replacer)); + this.argumentTypes = Lists.newArrayList(other.argumentTypes); + for (int i = 0; i < this.argumentTypes.size(); i++) { + this.argumentTypes.set(i, new Type(this.argumentTypes.get(i), replacer)); } - m_returnType = new Type(other.m_returnType, replacer); + this.returnType = new Type(other.returnType, replacer); } public List getArgumentTypes() { - return m_argumentTypes; + return this.argumentTypes; } public Type getReturnType() { - return m_returnType; + return this.returnType; } @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append("("); - for (Type type : m_argumentTypes) { + for (Type type : this.argumentTypes) { buf.append(type.toString()); } buf.append(")"); - buf.append(m_returnType.toString()); + buf.append(this.returnType.toString()); return buf.toString(); } public Iterable types() { List types = Lists.newArrayList(); - types.addAll(m_argumentTypes); - types.add(m_returnType); + types.addAll(this.argumentTypes); + types.add(this.returnType); return types; } @@ -95,12 +87,12 @@ public class Signature implements Serializable { } public boolean equals(Signature other) { - return m_argumentTypes.equals(other.m_argumentTypes) && m_returnType.equals(other.m_returnType); + return this.argumentTypes.equals(other.argumentTypes) && this.returnType.equals(other.returnType); } @Override public int hashCode() { - return Util.combineHashesOrdered(m_argumentTypes.hashCode(), m_returnType.hashCode()); + return Utils.combineHashesOrdered(this.argumentTypes.hashCode(), this.returnType.hashCode()); } public boolean hasClass(ClassEntry classEntry) { diff --git a/src/main/java/cuchaz/enigma/mapping/SignatureUpdater.java b/src/main/java/cuchaz/enigma/mapping/SignatureUpdater.java deleted file mode 100644 index ec300fed..00000000 --- a/src/main/java/cuchaz/enigma/mapping/SignatureUpdater.java +++ /dev/null @@ -1,82 +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.google.common.collect.Lists; - -import java.io.IOException; -import java.io.StringReader; -import java.util.List; - -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; - 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; - 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; - } -} diff --git a/src/main/java/cuchaz/enigma/mapping/Translator.java b/src/main/java/cuchaz/enigma/mapping/Translator.java index b0107ce8..eb6a1892 100644 --- a/src/main/java/cuchaz/enigma/mapping/Translator.java +++ b/src/main/java/cuchaz/enigma/mapping/Translator.java @@ -20,22 +20,22 @@ import cuchaz.enigma.analysis.TranslationIndex; public class Translator { - private TranslationDirection m_direction; - private Map m_classes; - private TranslationIndex m_index; + private TranslationDirection direction; + private Map classes; + private TranslationIndex index; - private ClassNameReplacer m_classNameReplacer = className -> translateEntry(new ClassEntry(className)).getName(); + private ClassNameReplacer classNameReplacer = className -> translateEntry(new ClassEntry(className)).getName(); public Translator() { - m_direction = null; - m_classes = Maps.newHashMap(); - m_index = new TranslationIndex(); + this.direction = null; + this.classes = Maps.newHashMap(); + this.index = new TranslationIndex(); } public Translator(TranslationDirection direction, Map classes, TranslationIndex index) { - m_direction = direction; - m_classes = classes; - m_index = index; + this.direction = direction; + this.classes = classes; + this.index = index; } @SuppressWarnings("unchecked") @@ -96,7 +96,7 @@ public class Translator { String className = null; ClassMapping classMapping = mappingsChain.get(i); if (classMapping != null) { - className = m_direction.choose( + className = this.direction.choose( classMapping.getDeobfName(), isFirstClass ? classMapping.getObfFullName() : classMapping.getObfSimpleName() ); @@ -114,11 +114,11 @@ public class Translator { } else { // normal classes are easy - ClassMapping classMapping = m_classes.get(in.getName()); + ClassMapping classMapping = this.classes.get(in.getName()); if (classMapping == null) { return in; } - return m_direction.choose( + return this.direction.choose( classMapping.getDeobfName() != null ? new ClassEntry(classMapping.getDeobfName()) : in, new ClassEntry(classMapping.getObfFullName()) ); @@ -128,7 +128,7 @@ public class Translator { public String translate(FieldEntry in) { // resolve the class entry - ClassEntry resolvedClassEntry = m_index.resolveEntryClass(in); + ClassEntry resolvedClassEntry = this.index.resolveEntryClass(in); if (resolvedClassEntry != null) { // look for the class @@ -136,7 +136,7 @@ public class Translator { if (classMapping != null) { // look for the field - String translatedName = m_direction.choose( + String translatedName = this.direction.choose( classMapping.getDeobfFieldName(in.getName(), in.getType()), classMapping.getObfFieldName(in.getName(), translateType(in.getType())) ); @@ -159,7 +159,7 @@ public class Translator { public String translate(MethodEntry in) { // resolve the class entry - ClassEntry resolvedClassEntry = m_index.resolveEntryClass(in); + ClassEntry resolvedClassEntry = this.index.resolveEntryClass(in); if (resolvedClassEntry != null) { // look for class @@ -167,12 +167,12 @@ public class Translator { if (classMapping != null) { // look for the method - MethodMapping methodMapping = m_direction.choose( + MethodMapping methodMapping = this.direction.choose( classMapping.getMethodByObf(in.getName(), in.getSignature()), classMapping.getMethodByDeobf(in.getName(), translateSignature(in.getSignature())) ); if (methodMapping != null) { - return m_direction.choose(methodMapping.getDeobfName(), methodMapping.getObfName()); + return this.direction.choose(methodMapping.getDeobfName(), methodMapping.getObfName()); } } } @@ -211,12 +211,12 @@ public class Translator { if (classMapping != null) { // look for the method - MethodMapping methodMapping = m_direction.choose( + MethodMapping methodMapping = this.direction.choose( classMapping.getMethodByObf(in.getMethodName(), in.getMethodSignature()), classMapping.getMethodByDeobf(in.getMethodName(), translateSignature(in.getMethodSignature())) ); if (methodMapping != null) { - return m_direction.choose( + return this.direction.choose( methodMapping.getDeobfArgumentName(in.getIndex()), methodMapping.getObfArgumentName(in.getIndex()) ); @@ -234,11 +234,11 @@ public class Translator { } public Type translateType(Type type) { - return new Type(type, m_classNameReplacer); + return new Type(type, this.classNameReplacer); } public Signature translateSignature(Signature signature) { - return new Signature(signature, m_classNameReplacer); + return new Signature(signature, this.classNameReplacer); } private ClassMapping findClassMapping(ClassEntry in) { @@ -253,7 +253,7 @@ public class Translator { List mappingsChain = Lists.newArrayList(); // get mappings for the outer class - ClassMapping outerClassMapping = m_classes.get(parts[0]); + ClassMapping outerClassMapping = this.classes.get(parts[0]); mappingsChain.add(outerClassMapping); for (int i = 1; i < parts.length; i++) { @@ -261,7 +261,7 @@ public class Translator { // get mappings for the inner class ClassMapping innerClassMapping = null; if (outerClassMapping != null) { - innerClassMapping = m_direction.choose( + innerClassMapping = this.direction.choose( outerClassMapping.getInnerClassByObfSimple(parts[i]), outerClassMapping.getInnerClassByDeobfThenObfSimple(parts[i]) ); diff --git a/src/main/java/cuchaz/enigma/mapping/Type.java b/src/main/java/cuchaz/enigma/mapping/Type.java index ec159415..34ddc059 100644 --- a/src/main/java/cuchaz/enigma/mapping/Type.java +++ b/src/main/java/cuchaz/enigma/mapping/Type.java @@ -12,12 +12,9 @@ package cuchaz.enigma.mapping; import com.google.common.collect.Maps; -import java.io.Serializable; import java.util.Map; -public class Type implements Serializable { - - private static final long serialVersionUID = 7862257669347104063L; +public class Type { public enum Primitive { Byte('B'), @@ -29,27 +26,27 @@ public class Type implements Serializable { Double('D'), Boolean('Z'); - private static final Map m_lookup; + private static final Map lookup; static { - m_lookup = Maps.newTreeMap(); + lookup = Maps.newTreeMap(); for (Primitive val : values()) { - m_lookup.put(val.getCode(), val); + lookup.put(val.getCode(), val); } } public static Primitive get(char code) { - return m_lookup.get(code); + return lookup.get(code); } - private char m_code; + private char code; Primitive(char code) { - m_code = code; + this.code = code; } public char getCode() { - return m_code; + return this.code; } } @@ -94,7 +91,7 @@ public class Type implements Serializable { throw new IllegalArgumentException("don't know how to parse: " + in); } - protected String m_name; + protected String name; public Type(String name) { @@ -104,59 +101,51 @@ public class Type implements Serializable { 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() + ";"; + this.name = name; } public Type(Type other, ClassNameReplacer replacer) { - m_name = other.m_name; + this.name = other.name; if (other.isClass()) { String replacedName = replacer.replace(other.getClassEntry().getClassName()); if (replacedName != null) { - m_name = "L" + replacedName + ";"; + this.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 + ";"; + this.name = Type.getArrayPrefix(other.getArrayDimension()) + "L" + replacedName + ";"; } } } @Override public String toString() { - return m_name; + return this.name; } public boolean isVoid() { - return m_name.length() == 1 && m_name.charAt(0) == 'V'; + return this.name.length() == 1 && this.name.charAt(0) == 'V'; } public boolean isPrimitive() { - return m_name.length() == 1 && Primitive.get(m_name.charAt(0)) != null; + return this.name.length() == 1 && Primitive.get(this.name.charAt(0)) != null; } public Primitive getPrimitive() { if (!isPrimitive()) { throw new IllegalStateException("not a primitive"); } - return Primitive.get(m_name.charAt(0)); + return Primitive.get(this.name.charAt(0)); } public boolean isClass() { - return m_name.charAt(0) == 'L' && m_name.charAt(m_name.length() - 1) == ';'; + return this.name.charAt(0) == 'L' && this.name.charAt(this.name.length() - 1) == ';'; } public ClassEntry getClassEntry() { if (isClass()) { - String name = m_name.substring(1, m_name.length() - 1); + String name = this.name.substring(1, this.name.length() - 1); int pos = name.indexOf('<'); if (pos >= 0) { @@ -174,21 +163,21 @@ public class Type implements Serializable { } public boolean isArray() { - return m_name.charAt(0) == '['; + return this.name.charAt(0) == '['; } public int getArrayDimension() { if (!isArray()) { throw new IllegalStateException("not an array"); } - return countArrayDimension(m_name); + return countArrayDimension(this.name); } public Type getArrayType() { if (!isArray()) { throw new IllegalStateException("not an array"); } - return new Type(m_name.substring(getArrayDimension(), m_name.length())); + return new Type(this.name.substring(getArrayDimension(), this.name.length())); } private static String getArrayPrefix(int dimension) { @@ -209,16 +198,17 @@ public class Type implements Serializable { } public boolean equals(Type other) { - return m_name.equals(other.m_name); + return this.name.equals(other.name); } public int hashCode() { - return m_name.hashCode(); + return this.name.hashCode(); } private static int countArrayDimension(String in) { int i = 0; - for (; i < in.length() && in.charAt(i) == '['; i++) {} + for (; i < in.length() && in.charAt(i) == '['; i++) { + } return i; } diff --git a/src/main/java/cuchaz/enigma/throwables/IllegalNameException.java b/src/main/java/cuchaz/enigma/throwables/IllegalNameException.java new file mode 100644 index 00000000..fa21a9e5 --- /dev/null +++ b/src/main/java/cuchaz/enigma/throwables/IllegalNameException.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * 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.throwables; + +public class IllegalNameException extends RuntimeException { + + private String name; + private String reason; + + public IllegalNameException(String name, String reason) { + this.name = name; + this.reason = reason; + } + + public String getReason() { + return this.reason; + } + + @Override + public String getMessage() { + StringBuilder buf = new StringBuilder(); + buf.append("Illegal name: "); + buf.append(this.name); + if (this.reason != null) { + buf.append(" because "); + buf.append(this.reason); + } + return buf.toString(); + } +} diff --git a/src/main/java/cuchaz/enigma/throwables/MappingConflict.java b/src/main/java/cuchaz/enigma/throwables/MappingConflict.java new file mode 100644 index 00000000..5924f32a --- /dev/null +++ b/src/main/java/cuchaz/enigma/throwables/MappingConflict.java @@ -0,0 +1,7 @@ +package cuchaz.enigma.throwables; + +public class MappingConflict extends Exception { + public MappingConflict(String clazz, String name, String nameExisting) { + super(String.format("Conflicting mappings found for %s. The mapping file is %s and the second is %s", clazz, name, nameExisting)); + } +} diff --git a/src/main/java/cuchaz/enigma/throwables/MappingParseException.java b/src/main/java/cuchaz/enigma/throwables/MappingParseException.java new file mode 100644 index 00000000..93ae2fda --- /dev/null +++ b/src/main/java/cuchaz/enigma/throwables/MappingParseException.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * 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.throwables; + +public class MappingParseException extends Exception { + + 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/main/java/cuchaz/enigma/utils/ReadableToken.java b/src/main/java/cuchaz/enigma/utils/ReadableToken.java new file mode 100644 index 00000000..81193935 --- /dev/null +++ b/src/main/java/cuchaz/enigma/utils/ReadableToken.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * 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.utils; + +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/main/java/cuchaz/enigma/utils/Utils.java b/src/main/java/cuchaz/enigma/utils/Utils.java new file mode 100644 index 00000000..e391b5ab --- /dev/null +++ b/src/main/java/cuchaz/enigma/utils/Utils.java @@ -0,0 +1,134 @@ +/******************************************************************************* + * 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.utils; + +import com.google.common.io.CharStreams; + +import java.awt.Desktop; +import java.awt.Font; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseEvent; +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 javax.swing.*; +import javax.swing.text.BadLocationException; +import javax.swing.text.Highlighter; + +import cuchaz.enigma.analysis.Token; + +public class Utils { + + 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 String readStreamToString(InputStream in) throws IOException { + return CharStreams.toString(new InputStreamReader(in, "UTF-8")); + } + + public static String readResourceToString(String path) throws IOException { + InputStream in = Utils.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 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 navigateToToken(final JEditorPane editor, final Token token, final Highlighter.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(() -> 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(); + } +} -- cgit v1.2.3