From 61eb14f65e73a9b3d0ea6eca6b04da804a4ff61b Mon Sep 17 00:00:00 2001 From: jeff Date: Sun, 8 Mar 2015 13:49:44 -0400 Subject: lots of small tweaks and improvements --- src/cuchaz/enigma/analysis/SourceIndex.java | 4 + src/cuchaz/enigma/convert/ClassIdentity.java | 19 +- src/cuchaz/enigma/gui/ClassSelector.java | 142 +++++++++++++-- src/cuchaz/enigma/gui/ClassSelectorClassNode.java | 4 +- src/cuchaz/enigma/gui/DecoratedClassEntry.java | 20 --- src/cuchaz/enigma/gui/Gui.java | 50 +----- src/cuchaz/enigma/gui/GuiTricks.java | 58 ++++++ src/cuchaz/enigma/gui/MatchingGui.java | 208 +++++++++++++++------- src/cuchaz/enigma/gui/ScoredClassEntry.java | 20 +++ 9 files changed, 378 insertions(+), 147 deletions(-) delete mode 100644 src/cuchaz/enigma/gui/DecoratedClassEntry.java create mode 100644 src/cuchaz/enigma/gui/ScoredClassEntry.java diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index e31b803..b3fb751 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java @@ -146,6 +146,10 @@ public class SourceIndex { return m_declarationToToken.values(); } + public Iterable declarations() { + return m_declarationToToken.keySet(); + } + public Token getDeclarationToken(Entry deobfEntry) { return m_declarationToToken.get(deobfEntry); } diff --git a/src/cuchaz/enigma/convert/ClassIdentity.java b/src/cuchaz/enigma/convert/ClassIdentity.java index 3736a53..d07e0a4 100644 --- a/src/cuchaz/enigma/convert/ClassIdentity.java +++ b/src/cuchaz/enigma/convert/ClassIdentity.java @@ -69,6 +69,7 @@ public class ClassIdentity { private Multiset m_implements; private Multiset m_implementations; private Multiset m_references; + private String m_outer; private final ClassNameReplacer m_classNameReplacer = new ClassNameReplacer() { @@ -167,6 +168,8 @@ public class ClassIdentity { } } } + + m_outer = EntryFactory.getClassEntry(c).getOuterClassName(); } private void addReference(EntryReference reference) { @@ -234,6 +237,9 @@ public class ClassIdentity { buf.append(reference); buf.append("\n"); } + buf.append("\touter "); + buf.append(m_outer); + buf.append("\n"); return buf.toString(); } @@ -402,13 +408,15 @@ public class ClassIdentity { } public int getMatchScore(ClassIdentity other) { - return getNumMatches(m_fields, other.m_fields) + return 2*getNumMatches(m_extends, other.m_extends) + + 2*getNumMatches(m_outer, other.m_outer) + + getNumMatches(m_fields, other.m_fields) + getNumMatches(m_methods, other.m_methods) + getNumMatches(m_constructors, other.m_constructors); } public int getMaxMatchScore() { - return m_fields.size() + m_methods.size() + m_constructors.size(); + return 2 + 2 + m_fields.size() + m_methods.size() + m_constructors.size(); } public boolean matches(CtClass c) { @@ -427,4 +435,11 @@ public class ClassIdentity { } return numMatches; } + + private int getNumMatches(String a, String b) { + if (a.equals(b)) { + return 1; + } + return 0; + } } diff --git a/src/cuchaz/enigma/gui/ClassSelector.java b/src/cuchaz/enigma/gui/ClassSelector.java index e5f550b..2a63675 100644 --- a/src/cuchaz/enigma/gui/ClassSelector.java +++ b/src/cuchaz/enigma/gui/ClassSelector.java @@ -15,6 +15,7 @@ import java.awt.event.MouseEvent; import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.Enumeration; import java.util.List; import java.util.Map; @@ -41,19 +42,12 @@ public class ClassSelector extends JTree { public static Comparator ObfuscatedClassEntryComparator; public static Comparator DeobfuscatedClassEntryComparator; - private static String getClassEntryDisplayName(ClassEntry entry) { - if (entry instanceof DecoratedClassEntry) { - return ((DecoratedClassEntry)entry).getDecoration() + entry.getName(); - } - return entry.getName(); - } - static { ObfuscatedClassEntryComparator = new Comparator() { @Override public int compare(ClassEntry a, ClassEntry b) { - String aname = getClassEntryDisplayName(a); - String bname = getClassEntryDisplayName(b); + String aname = a.getName(); + String bname = a.getName(); if (aname.length() != bname.length()) { return aname.length() - bname.length(); } @@ -64,9 +58,13 @@ public class ClassSelector extends JTree { DeobfuscatedClassEntryComparator = new Comparator() { @Override public int compare(ClassEntry a, ClassEntry b) { - String aname = getClassEntryDisplayName(a); - String bname = getClassEntryDisplayName(b); - return aname.compareTo(bname); + if (a instanceof ScoredClassEntry && b instanceof ScoredClassEntry) { + return Float.compare( + ((ScoredClassEntry)b).getScore(), + ((ScoredClassEntry)a).getScore() + ); + } + return a.getName().compareTo(b.getName()); } }; } @@ -172,4 +170,124 @@ 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; + } + + public void expandPackage(String packageName) { + if (packageName == null) { + return; + } + for (ClassSelectorPackageNode packageNode : packageNodes()) { + if (packageNode.getPackageName().equals(packageName)) { + expandPath(new TreePath(new Object[] {getModel().getRoot(), packageNode})); + return; + } + } + } + + public void expandAll() { + for (ClassSelectorPackageNode packageNode : packageNodes()) { + expandPath(new TreePath(new Object[] {getModel().getRoot(), packageNode})); + } + } + + public ClassEntry getFirstClass() { + for (ClassSelectorPackageNode packageNode : packageNodes()) { + for (ClassSelectorClassNode classNode : classNodes(packageNode)) { + return classNode.getClassEntry(); + } + } + return null; + } + + public ClassSelectorPackageNode getPackageNode(ClassEntry entry) { + for (ClassSelectorPackageNode packageNode : packageNodes()) { + if (packageNode.getPackageName().equals(entry.getPackageName())) { + return packageNode; + } + } + return null; + } + + public ClassEntry getNextClass(ClassEntry entry) { + boolean foundIt = false; + for (ClassSelectorPackageNode packageNode : packageNodes()) { + if (!foundIt) { + // skip to the package with our target in it + if (packageNode.getPackageName().equals(entry.getPackageName())) { + for (ClassSelectorClassNode classNode : classNodes(packageNode)) { + if (!foundIt) { + if (classNode.getClassEntry().equals(entry)) { + foundIt = true; + } + } else { + // return the next class + return classNode.getClassEntry(); + } + } + } + } else { + // return the next class + for (ClassSelectorClassNode classNode : classNodes(packageNode)) { + return classNode.getClassEntry(); + } + } + } + return null; + } + + public void setSelectionClass(ClassEntry classEntry) { + expandPackage(classEntry.getPackageName()); + for (ClassSelectorPackageNode packageNode : packageNodes()) { + for (ClassSelectorClassNode classNode : classNodes(packageNode)) { + if (classNode.getClassEntry().equals(classEntry)) { + setSelectionPath(new TreePath(new Object[] {getModel().getRoot(), packageNode, classNode})); + } + } + } + } } diff --git a/src/cuchaz/enigma/gui/ClassSelectorClassNode.java b/src/cuchaz/enigma/gui/ClassSelectorClassNode.java index f054188..6c1c9a0 100644 --- a/src/cuchaz/enigma/gui/ClassSelectorClassNode.java +++ b/src/cuchaz/enigma/gui/ClassSelectorClassNode.java @@ -30,8 +30,8 @@ public class ClassSelectorClassNode extends DefaultMutableTreeNode { @Override public String toString() { - if (m_classEntry instanceof DecoratedClassEntry) { - return ((DecoratedClassEntry)m_classEntry).getDecoration() + m_classEntry.getSimpleName(); + if (m_classEntry instanceof ScoredClassEntry) { + return String.format("%d%% %s", (int)((ScoredClassEntry)m_classEntry).getScore(), m_classEntry.getSimpleName()); } return m_classEntry.getSimpleName(); } diff --git a/src/cuchaz/enigma/gui/DecoratedClassEntry.java b/src/cuchaz/enigma/gui/DecoratedClassEntry.java deleted file mode 100644 index dd8b4fa..0000000 --- a/src/cuchaz/enigma/gui/DecoratedClassEntry.java +++ /dev/null @@ -1,20 +0,0 @@ -package cuchaz.enigma.gui; - -import cuchaz.enigma.mapping.ClassEntry; - - -public class DecoratedClassEntry extends ClassEntry { - - private static final long serialVersionUID = -8798725308554217105L; - - private String m_decoration; - - public DecoratedClassEntry(ClassEntry other, String decoration) { - super(other); - m_decoration = decoration; - } - - public String getDecoration() { - return m_decoration; - } -} diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index a214243..38a6ee9 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -16,7 +16,6 @@ import java.awt.Container; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.GridLayout; -import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; @@ -54,8 +53,6 @@ import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; -import javax.swing.SwingUtilities; -import javax.swing.Timer; import javax.swing.WindowConstants; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; @@ -740,52 +737,7 @@ public class Gui { if (token == null) { throw new IllegalArgumentException("Token cannot be null!"); } - - // set the caret position to the token - m_editor.setCaretPosition(token.start); - m_editor.grabFocus(); - - try { - // make sure the token is visible in the scroll window - Rectangle start = m_editor.modelToView(token.start); - Rectangle end = m_editor.modelToView(token.end); - final Rectangle show = start.union(end); - show.grow(start.width * 10, start.height * 6); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - m_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 = m_editor.getHighlighter().addHighlight(token.start, token.end, m_selectionHighlightPainter); - } catch (BadLocationException ex) { - // don't care - } - } else if (m_highlight != null) { - m_editor.getHighlighter().removeHighlight(m_highlight); - } - - if (m_counter++ > 6) { - Timer timer = (Timer)event.getSource(); - timer.stop(); - } - } - }); - timer.start(); - + GuiTricks.navigateToToken(m_editor, token, m_selectionHighlightPainter); redraw(); } diff --git a/src/cuchaz/enigma/gui/GuiTricks.java b/src/cuchaz/enigma/gui/GuiTricks.java index df9e221..5a3a01d 100644 --- a/src/cuchaz/enigma/gui/GuiTricks.java +++ b/src/cuchaz/enigma/gui/GuiTricks.java @@ -11,11 +11,21 @@ package cuchaz.enigma.gui; import java.awt.Font; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import javax.swing.JComponent; +import javax.swing.JEditorPane; import javax.swing.JLabel; +import javax.swing.SwingUtilities; +import javax.swing.Timer; import javax.swing.ToolTipManager; +import javax.swing.text.BadLocationException; +import javax.swing.text.Highlighter.HighlightPainter; + +import cuchaz.enigma.analysis.Token; public class GuiTricks { @@ -33,4 +43,52 @@ public class GuiTricks { 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 HighlightPainter highlightPainter) { + + // set the caret position to the token + editor.setCaretPosition(token.start); + editor.grabFocus(); + + try { + // make sure the token is visible in the scroll window + Rectangle start = editor.modelToView(token.start); + Rectangle end = editor.modelToView(token.end); + final Rectangle show = start.union(end); + show.grow(start.width * 10, start.height * 6); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + editor.scrollRectToVisible(show); + } + }); + } catch (BadLocationException ex) { + throw new Error(ex); + } + + // highlight the token momentarily + final Timer timer = new Timer(200, new ActionListener() { + private int m_counter = 0; + private Object m_highlight = null; + + @Override + public void actionPerformed(ActionEvent event) { + if (m_counter % 2 == 0) { + try { + m_highlight = editor.getHighlighter().addHighlight(token.start, token.end, highlightPainter); + } catch (BadLocationException ex) { + // don't care + } + } else if (m_highlight != null) { + editor.getHighlighter().removeHighlight(m_highlight); + } + + if (m_counter++ > 6) { + Timer timer = (Timer)event.getSource(); + timer.stop(); + } + } + }); + timer.start(); + } } diff --git a/src/cuchaz/enigma/gui/MatchingGui.java b/src/cuchaz/enigma/gui/MatchingGui.java index f1da25a..1e618d0 100644 --- a/src/cuchaz/enigma/gui/MatchingGui.java +++ b/src/cuchaz/enigma/gui/MatchingGui.java @@ -10,7 +10,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Enumeration; import java.util.List; import java.util.Map; @@ -27,17 +26,18 @@ import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.SwingConstants; import javax.swing.WindowConstants; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.TreePath; import com.beust.jcommander.internal.Lists; import com.beust.jcommander.internal.Maps; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.BiMap; import com.google.common.collect.Multimap; +import com.strobel.decompiler.languages.java.ast.CompilationUnit; import cuchaz.enigma.Constants; import cuchaz.enigma.Deobfuscator; +import cuchaz.enigma.analysis.SourceIndex; +import cuchaz.enigma.analysis.Token; import cuchaz.enigma.convert.ClassIdentifier; import cuchaz.enigma.convert.ClassIdentity; import cuchaz.enigma.convert.ClassMatch; @@ -47,6 +47,7 @@ import cuchaz.enigma.convert.MappingsConverter; import cuchaz.enigma.convert.Matches; import cuchaz.enigma.gui.ClassSelector.ClassSelectionListener; import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.Entry; import de.sciss.syntaxpane.DefaultSyntaxKit; @@ -105,6 +106,7 @@ public class MatchingGui { private JButton m_matchButton; private Map m_sourceTypeButtons; private JCheckBox m_advanceCheck; + private SelectionHighlightPainter m_selectionHighlightPainter; private Matches m_matches; private Deobfuscator m_sourceDeobfuscator; @@ -188,12 +190,8 @@ public class MatchingGui { // init source panels DefaultSyntaxKit.initKit(); - m_sourceReader = new JEditorPane(); - m_sourceReader.setEditable(false); - m_sourceReader.setContentType("text/java"); - m_destReader = new JEditorPane(); - m_destReader.setEditable(false); - m_destReader.setContentType("text/java"); + m_sourceReader = makeReader(); + m_destReader = makeReader(); // init all the splits JSplitPane splitLeft = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, sourcePanel, new JScrollPane(m_sourceReader)); @@ -220,6 +218,14 @@ public class MatchingGui { m_matchButton.setPreferredSize(new Dimension(140, 24)); m_advanceCheck = new JCheckBox("Advance to next likely match"); + m_advanceCheck.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent event) { + if (m_advanceCheck.isSelected()) { + advance(); + } + } + }); bottomPanel.add(m_sourceClassLabel); bottomPanel.add(m_matchButton); @@ -234,6 +240,8 @@ public class MatchingGui { m_frame.setVisible(true); m_frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + m_selectionHighlightPainter = new SelectionHighlightPainter(); + // init state updateDestMappings(); setSourceType(SourceType.getDefault()); @@ -241,6 +249,19 @@ public class MatchingGui { m_saveListener = null; } + private JEditorPane makeReader() { + + JEditorPane reader = new JEditorPane(); + reader.setEditable(false); + reader.setContentType("text/java"); + + // turn off token highlighting (it's wrong most of the time anyway...) + DefaultSyntaxKit kit = (DefaultSyntaxKit)reader.getEditorKit(); + kit.toggleComponent(reader, "de.sciss.syntaxpane.components.TokenMarker"); + + return reader; + } + public void setSaveListener(SaveListener val) { m_saveListener = val; } @@ -272,12 +293,24 @@ public class MatchingGui { private Collection deobfuscateClasses(Collection in, Deobfuscator deobfuscator) { List out = Lists.newArrayList(); for (ClassEntry entry : in) { - out.add(deobfuscator.deobfuscateEntry(entry)); + + 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) { + setSourceClass(classEntry, null); + } + + protected void setSourceClass(ClassEntry classEntry, final Runnable onGetDestClasses) { // update the current source class m_sourceClass = classEntry; @@ -297,20 +330,27 @@ public class MatchingGui { @Override public void run() { m_destClasses.setClasses(deobfuscateClasses(getLikelyMatches(m_sourceClass), m_destDeobfuscator)); - m_destClasses.expandRow(0); + m_destClasses.expandAll(); + + if (onGetDestClasses != null) { + onGetDestClasses.run(); + } } }.start(); } else { m_destClasses.setClasses(deobfuscateClasses(match.destClasses, m_destDeobfuscator)); - m_destClasses.expandRow(0); + m_destClasses.expandAll(); + if (onGetDestClasses != null) { + onGetDestClasses.run(); + } } } setDestClass(null); - readSource(m_sourceClass, m_sourceDeobfuscator, m_sourceReader); + decompileClass(m_sourceClass, m_sourceDeobfuscator, m_sourceReader); updateMatchButton(); } @@ -334,29 +374,14 @@ public class MatchingGui { // rank all the unmatched dest classes against the source class ClassIdentity sourceIdentity = sourceIdentifier.identify(obfSourceClass); - Multimap scoredDestClasses = ArrayListMultimap.create(); + List scoredDestClasses = Lists.newArrayList(); for (ClassEntry unmatchedDestClass : m_matches.getUnmatchedDestClasses()) { ClassIdentity destIdentity = destIdentifier.identify(unmatchedDestClass); float score = 100.0f*(sourceIdentity.getMatchScore(destIdentity) + destIdentity.getMatchScore(sourceIdentity)) /(sourceIdentity.getMaxMatchScore() + destIdentity.getMaxMatchScore()); - scoredDestClasses.put(score, unmatchedDestClass); - } - - // sort by scores - List scores = new ArrayList(scoredDestClasses.keySet()); - Collections.sort(scores, Collections.reverseOrder()); - - // collect the scored classes in order - List scoredClasses = Lists.newArrayList(); - for (float score : scores) { - for (ClassEntry classEntry : scoredDestClasses.get(score)) { - scoredClasses.add(new DecoratedClassEntry(classEntry, String.format("%2.0f%% ", score))); - if (scoredClasses.size() > 10) { - return scoredClasses; - } - } + scoredDestClasses.add(new ScoredClassEntry(unmatchedDestClass, score)); } - return scoredClasses; + return scoredDestClasses; } catch (ClassNotFoundException ex) { throw new Error("Unable to find class " + ex.getMessage()); @@ -369,12 +394,12 @@ public class MatchingGui { m_destClass = classEntry; m_destClassLabel.setText(m_destClass != null ? m_destClass.getName() : ""); - readSource(m_destClass, m_destDeobfuscator, m_destReader); + decompileClass(m_destClass, m_destDeobfuscator, m_destReader); updateMatchButton(); } - protected void readSource(final ClassEntry classEntry, final Deobfuscator deobfuscator, final JEditorPane reader) { + protected void decompileClass(final ClassEntry classEntry, final Deobfuscator deobfuscator, final JEditorPane reader) { if (classEntry == null) { reader.setText(null); @@ -389,12 +414,37 @@ public class MatchingGui { public void run() { // get the outermost class - ClassEntry obfClassEntry = deobfuscator.obfuscateEntry(classEntry); - List classChain = deobfuscator.getJarIndex().getObfClassChain(obfClassEntry); - ClassEntry obfOutermostClassEntry = classChain.get(0); + ClassEntry outermostClassEntry = classEntry; + while (outermostClassEntry.isInnerClass()) { + outermostClassEntry = outermostClassEntry.getOuterClassEntry(); + } // decompile it - reader.setText(deobfuscator.getSource(deobfuscator.getSourceTree(obfOutermostClassEntry.getName()))); + CompilationUnit sourceTree = deobfuscator.getSourceTree(outermostClassEntry.getName()); + String source = deobfuscator.getSource(sourceTree); + reader.setText(source); + SourceIndex sourceIndex = deobfuscator.getSourceIndex(sourceTree, source); + + // navigate to the class declaration + Token token = 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 : sourceIndex.declarations()) { + if (entry.getClassEntry().equals(classEntry)) { + token = sourceIndex.getDeclarationToken(entry); + break; + } + } + } + + if (token != null) { + GuiTricks.navigateToToken(reader, token, m_selectionHighlightPainter); + } else { + // couldn't find anything =( + System.out.println("Unable to find declaration in source for " + classEntry); + } + } }.start(); } @@ -459,11 +509,16 @@ public class MatchingGui { // add them as matched classes m_matches.add(new ClassMatch(obfSource, obfDest)); + ClassEntry nextClass = null; + if (m_advanceCheck.isSelected()) { + nextClass = m_sourceClasses.getNextClass(m_sourceClass); + } + save(); updateMatches(); - if (m_advanceCheck.isSelected()) { - advance(); + if (nextClass != null) { + advance(nextClass); } } @@ -487,31 +542,11 @@ public class MatchingGui { updateMatchButton(); // remember where we were in the source tree - String packageName = null; - if (!m_sourceClasses.isSelectionEmpty()) { - packageName = m_sourceClasses.getSelectionPath().getParentPath().getLastPathComponent().toString(); - } + String packageName = m_sourceClasses.getSelectedPackage(); setSourceType(m_sourceType); - if (packageName != null) { - // find the corresponding path in the new tree - TreePath path = null; - DefaultMutableTreeNode root = (DefaultMutableTreeNode)m_sourceClasses.getModel().getRoot(); - Enumeration children = root.children(); - while (children.hasMoreElements()) { - Object child = children.nextElement(); - if (child.toString().equals(packageName)) { - path = new TreePath(new Object[] {root, child}); - break; - } - } - - if (path != null) { - // put the tree back to where it was - m_sourceClasses.expandPath(path); - } - } + m_sourceClasses.expandPackage(packageName); } private void save() { @@ -542,6 +577,55 @@ public class MatchingGui { } private void advance() { - // TODO: find a likely match + advance(null); + } + + private void advance(ClassEntry sourceClass) { + + // make sure we have a source class + if (sourceClass == null) { + sourceClass = m_sourceClasses.getSelectedClass(); + if (sourceClass != null) { + sourceClass = m_sourceClasses.getNextClass(sourceClass); + } else { + sourceClass = m_sourceClasses.getFirstClass(); + } + } + + // set the source class + setSourceClass(sourceClass, new Runnable() { + @Override + public void run() { + + // then, pick the best dest class + ClassEntry firstClass = null; + ScoredClassEntry bestDestClass = null; + for (ClassSelectorPackageNode packageNode : m_destClasses.packageNodes()) { + for (ClassSelectorClassNode classNode : m_destClasses.classNodes(packageNode)) { + if (firstClass == null) { + firstClass = classNode.getClassEntry(); + } + if (classNode.getClassEntry() instanceof ScoredClassEntry) { + ScoredClassEntry scoredClass = (ScoredClassEntry)classNode.getClassEntry(); + if (bestDestClass == null || bestDestClass.getScore() < scoredClass.getScore()) { + bestDestClass = scoredClass; + } + } + } + } + + // pick the entry to show + ClassEntry destClass = null; + if (bestDestClass != null) { + destClass = bestDestClass; + } else if (firstClass != null) { + destClass = firstClass; + } + + setDestClass(destClass); + m_destClasses.setSelectionClass(destClass); + } + }); + m_sourceClasses.setSelectionClass(sourceClass); } } diff --git a/src/cuchaz/enigma/gui/ScoredClassEntry.java b/src/cuchaz/enigma/gui/ScoredClassEntry.java new file mode 100644 index 0000000..dd7ba61 --- /dev/null +++ b/src/cuchaz/enigma/gui/ScoredClassEntry.java @@ -0,0 +1,20 @@ +package cuchaz.enigma.gui; + +import cuchaz.enigma.mapping.ClassEntry; + + +public class ScoredClassEntry extends ClassEntry { + + private static final long serialVersionUID = -8798725308554217105L; + + private float m_score; + + public ScoredClassEntry(ClassEntry other, float score) { + super(other); + m_score = score; + } + + public float getScore() { + return m_score; + } +} -- cgit v1.2.3