summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cuchaz/enigma/analysis/SourceIndex.java4
-rw-r--r--src/cuchaz/enigma/convert/ClassIdentity.java19
-rw-r--r--src/cuchaz/enigma/gui/ClassSelector.java142
-rw-r--r--src/cuchaz/enigma/gui/ClassSelectorClassNode.java4
-rw-r--r--src/cuchaz/enigma/gui/DecoratedClassEntry.java20
-rw-r--r--src/cuchaz/enigma/gui/Gui.java50
-rw-r--r--src/cuchaz/enigma/gui/GuiTricks.java58
-rw-r--r--src/cuchaz/enigma/gui/MatchingGui.java208
-rw-r--r--src/cuchaz/enigma/gui/ScoredClassEntry.java20
9 files changed, 378 insertions, 147 deletions
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 {
146 return m_declarationToToken.values(); 146 return m_declarationToToken.values();
147 } 147 }
148 148
149 public Iterable<Entry> declarations() {
150 return m_declarationToToken.keySet();
151 }
152
149 public Token getDeclarationToken(Entry deobfEntry) { 153 public Token getDeclarationToken(Entry deobfEntry) {
150 return m_declarationToToken.get(deobfEntry); 154 return m_declarationToToken.get(deobfEntry);
151 } 155 }
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 {
69 private Multiset<String> m_implements; 69 private Multiset<String> m_implements;
70 private Multiset<String> m_implementations; 70 private Multiset<String> m_implementations;
71 private Multiset<String> m_references; 71 private Multiset<String> m_references;
72 private String m_outer;
72 73
73 private final ClassNameReplacer m_classNameReplacer = new ClassNameReplacer() { 74 private final ClassNameReplacer m_classNameReplacer = new ClassNameReplacer() {
74 75
@@ -167,6 +168,8 @@ public class ClassIdentity {
167 } 168 }
168 } 169 }
169 } 170 }
171
172 m_outer = EntryFactory.getClassEntry(c).getOuterClassName();
170 } 173 }
171 174
172 private void addReference(EntryReference<? extends Entry,BehaviorEntry> reference) { 175 private void addReference(EntryReference<? extends Entry,BehaviorEntry> reference) {
@@ -234,6 +237,9 @@ public class ClassIdentity {
234 buf.append(reference); 237 buf.append(reference);
235 buf.append("\n"); 238 buf.append("\n");
236 } 239 }
240 buf.append("\touter ");
241 buf.append(m_outer);
242 buf.append("\n");
237 return buf.toString(); 243 return buf.toString();
238 } 244 }
239 245
@@ -402,13 +408,15 @@ public class ClassIdentity {
402 } 408 }
403 409
404 public int getMatchScore(ClassIdentity other) { 410 public int getMatchScore(ClassIdentity other) {
405 return getNumMatches(m_fields, other.m_fields) 411 return 2*getNumMatches(m_extends, other.m_extends)
412 + 2*getNumMatches(m_outer, other.m_outer)
413 + getNumMatches(m_fields, other.m_fields)
406 + getNumMatches(m_methods, other.m_methods) 414 + getNumMatches(m_methods, other.m_methods)
407 + getNumMatches(m_constructors, other.m_constructors); 415 + getNumMatches(m_constructors, other.m_constructors);
408 } 416 }
409 417
410 public int getMaxMatchScore() { 418 public int getMaxMatchScore() {
411 return m_fields.size() + m_methods.size() + m_constructors.size(); 419 return 2 + 2 + m_fields.size() + m_methods.size() + m_constructors.size();
412 } 420 }
413 421
414 public boolean matches(CtClass c) { 422 public boolean matches(CtClass c) {
@@ -427,4 +435,11 @@ public class ClassIdentity {
427 } 435 }
428 return numMatches; 436 return numMatches;
429 } 437 }
438
439 private int getNumMatches(String a, String b) {
440 if (a.equals(b)) {
441 return 1;
442 }
443 return 0;
444 }
430} 445}
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;
15import java.util.Collection; 15import java.util.Collection;
16import java.util.Collections; 16import java.util.Collections;
17import java.util.Comparator; 17import java.util.Comparator;
18import java.util.Enumeration;
18import java.util.List; 19import java.util.List;
19import java.util.Map; 20import java.util.Map;
20 21
@@ -41,19 +42,12 @@ public class ClassSelector extends JTree {
41 public static Comparator<ClassEntry> ObfuscatedClassEntryComparator; 42 public static Comparator<ClassEntry> ObfuscatedClassEntryComparator;
42 public static Comparator<ClassEntry> DeobfuscatedClassEntryComparator; 43 public static Comparator<ClassEntry> DeobfuscatedClassEntryComparator;
43 44
44 private static String getClassEntryDisplayName(ClassEntry entry) {
45 if (entry instanceof DecoratedClassEntry) {
46 return ((DecoratedClassEntry)entry).getDecoration() + entry.getName();
47 }
48 return entry.getName();
49 }
50
51 static { 45 static {
52 ObfuscatedClassEntryComparator = new Comparator<ClassEntry>() { 46 ObfuscatedClassEntryComparator = new Comparator<ClassEntry>() {
53 @Override 47 @Override
54 public int compare(ClassEntry a, ClassEntry b) { 48 public int compare(ClassEntry a, ClassEntry b) {
55 String aname = getClassEntryDisplayName(a); 49 String aname = a.getName();
56 String bname = getClassEntryDisplayName(b); 50 String bname = a.getName();
57 if (aname.length() != bname.length()) { 51 if (aname.length() != bname.length()) {
58 return aname.length() - bname.length(); 52 return aname.length() - bname.length();
59 } 53 }
@@ -64,9 +58,13 @@ public class ClassSelector extends JTree {
64 DeobfuscatedClassEntryComparator = new Comparator<ClassEntry>() { 58 DeobfuscatedClassEntryComparator = new Comparator<ClassEntry>() {
65 @Override 59 @Override
66 public int compare(ClassEntry a, ClassEntry b) { 60 public int compare(ClassEntry a, ClassEntry b) {
67 String aname = getClassEntryDisplayName(a); 61 if (a instanceof ScoredClassEntry && b instanceof ScoredClassEntry) {
68 String bname = getClassEntryDisplayName(b); 62 return Float.compare(
69 return aname.compareTo(bname); 63 ((ScoredClassEntry)b).getScore(),
64 ((ScoredClassEntry)a).getScore()
65 );
66 }
67 return a.getName().compareTo(b.getName());
70 } 68 }
71 }; 69 };
72 } 70 }
@@ -172,4 +170,124 @@ public class ClassSelector extends JTree {
172 // finally, update the tree control 170 // finally, update the tree control
173 setModel(new DefaultTreeModel(root)); 171 setModel(new DefaultTreeModel(root));
174 } 172 }
173
174 public ClassEntry getSelectedClass() {
175 if (!isSelectionEmpty()) {
176 Object selectedNode = getSelectionPath().getLastPathComponent();
177 if (selectedNode instanceof ClassSelectorClassNode) {
178 ClassSelectorClassNode classNode = (ClassSelectorClassNode)selectedNode;
179 return classNode.getClassEntry();
180 }
181 }
182 return null;
183 }
184
185 public String getSelectedPackage() {
186 if (!isSelectionEmpty()) {
187 Object selectedNode = getSelectionPath().getLastPathComponent();
188 if (selectedNode instanceof ClassSelectorPackageNode) {
189 ClassSelectorPackageNode packageNode = (ClassSelectorPackageNode)selectedNode;
190 return packageNode.getPackageName();
191 } else if (selectedNode instanceof ClassSelectorClassNode) {
192 ClassSelectorClassNode classNode = (ClassSelectorClassNode)selectedNode;
193 return classNode.getClassEntry().getPackageName();
194 }
195 }
196 return null;
197 }
198
199 public Iterable<ClassSelectorPackageNode> packageNodes() {
200 List<ClassSelectorPackageNode> nodes = Lists.newArrayList();
201 DefaultMutableTreeNode root = (DefaultMutableTreeNode)getModel().getRoot();
202 Enumeration<?> children = root.children();
203 while (children.hasMoreElements()) {
204 ClassSelectorPackageNode packageNode = (ClassSelectorPackageNode)children.nextElement();
205 nodes.add(packageNode);
206 }
207 return nodes;
208 }
209
210 public Iterable<ClassSelectorClassNode> classNodes(ClassSelectorPackageNode packageNode) {
211 List<ClassSelectorClassNode> nodes = Lists.newArrayList();
212 Enumeration<?> children = packageNode.children();
213 while (children.hasMoreElements()) {
214 ClassSelectorClassNode classNode = (ClassSelectorClassNode)children.nextElement();
215 nodes.add(classNode);
216 }
217 return nodes;
218 }
219
220 public void expandPackage(String packageName) {
221 if (packageName == null) {
222 return;
223 }
224 for (ClassSelectorPackageNode packageNode : packageNodes()) {
225 if (packageNode.getPackageName().equals(packageName)) {
226 expandPath(new TreePath(new Object[] {getModel().getRoot(), packageNode}));
227 return;
228 }
229 }
230 }
231
232 public void expandAll() {
233 for (ClassSelectorPackageNode packageNode : packageNodes()) {
234 expandPath(new TreePath(new Object[] {getModel().getRoot(), packageNode}));
235 }
236 }
237
238 public ClassEntry getFirstClass() {
239 for (ClassSelectorPackageNode packageNode : packageNodes()) {
240 for (ClassSelectorClassNode classNode : classNodes(packageNode)) {
241 return classNode.getClassEntry();
242 }
243 }
244 return null;
245 }
246
247 public ClassSelectorPackageNode getPackageNode(ClassEntry entry) {
248 for (ClassSelectorPackageNode packageNode : packageNodes()) {
249 if (packageNode.getPackageName().equals(entry.getPackageName())) {
250 return packageNode;
251 }
252 }
253 return null;
254 }
255
256 public ClassEntry getNextClass(ClassEntry entry) {
257 boolean foundIt = false;
258 for (ClassSelectorPackageNode packageNode : packageNodes()) {
259 if (!foundIt) {
260 // skip to the package with our target in it
261 if (packageNode.getPackageName().equals(entry.getPackageName())) {
262 for (ClassSelectorClassNode classNode : classNodes(packageNode)) {
263 if (!foundIt) {
264 if (classNode.getClassEntry().equals(entry)) {
265 foundIt = true;
266 }
267 } else {
268 // return the next class
269 return classNode.getClassEntry();
270 }
271 }
272 }
273 } else {
274 // return the next class
275 for (ClassSelectorClassNode classNode : classNodes(packageNode)) {
276 return classNode.getClassEntry();
277 }
278 }
279 }
280 return null;
281 }
282
283 public void setSelectionClass(ClassEntry classEntry) {
284 expandPackage(classEntry.getPackageName());
285 for (ClassSelectorPackageNode packageNode : packageNodes()) {
286 for (ClassSelectorClassNode classNode : classNodes(packageNode)) {
287 if (classNode.getClassEntry().equals(classEntry)) {
288 setSelectionPath(new TreePath(new Object[] {getModel().getRoot(), packageNode, classNode}));
289 }
290 }
291 }
292 }
175} 293}
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 {
30 30
31 @Override 31 @Override
32 public String toString() { 32 public String toString() {
33 if (m_classEntry instanceof DecoratedClassEntry) { 33 if (m_classEntry instanceof ScoredClassEntry) {
34 return ((DecoratedClassEntry)m_classEntry).getDecoration() + m_classEntry.getSimpleName(); 34 return String.format("%d%% %s", (int)((ScoredClassEntry)m_classEntry).getScore(), m_classEntry.getSimpleName());
35 } 35 }
36 return m_classEntry.getSimpleName(); 36 return m_classEntry.getSimpleName();
37 } 37 }
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 @@
1package cuchaz.enigma.gui;
2
3import cuchaz.enigma.mapping.ClassEntry;
4
5
6public class DecoratedClassEntry extends ClassEntry {
7
8 private static final long serialVersionUID = -8798725308554217105L;
9
10 private String m_decoration;
11
12 public DecoratedClassEntry(ClassEntry other, String decoration) {
13 super(other);
14 m_decoration = decoration;
15 }
16
17 public String getDecoration() {
18 return m_decoration;
19 }
20}
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;
16import java.awt.Dimension; 16import java.awt.Dimension;
17import java.awt.FlowLayout; 17import java.awt.FlowLayout;
18import java.awt.GridLayout; 18import java.awt.GridLayout;
19import java.awt.Rectangle;
20import java.awt.event.ActionEvent; 19import java.awt.event.ActionEvent;
21import java.awt.event.ActionListener; 20import java.awt.event.ActionListener;
22import java.awt.event.InputEvent; 21import java.awt.event.InputEvent;
@@ -54,8 +53,6 @@ import javax.swing.JTextField;
54import javax.swing.JTree; 53import javax.swing.JTree;
55import javax.swing.KeyStroke; 54import javax.swing.KeyStroke;
56import javax.swing.ListSelectionModel; 55import javax.swing.ListSelectionModel;
57import javax.swing.SwingUtilities;
58import javax.swing.Timer;
59import javax.swing.WindowConstants; 56import javax.swing.WindowConstants;
60import javax.swing.event.CaretEvent; 57import javax.swing.event.CaretEvent;
61import javax.swing.event.CaretListener; 58import javax.swing.event.CaretListener;
@@ -740,52 +737,7 @@ public class Gui {
740 if (token == null) { 737 if (token == null) {
741 throw new IllegalArgumentException("Token cannot be null!"); 738 throw new IllegalArgumentException("Token cannot be null!");
742 } 739 }
743 740 GuiTricks.navigateToToken(m_editor, token, m_selectionHighlightPainter);
744 // set the caret position to the token
745 m_editor.setCaretPosition(token.start);
746 m_editor.grabFocus();
747
748 try {
749 // make sure the token is visible in the scroll window
750 Rectangle start = m_editor.modelToView(token.start);
751 Rectangle end = m_editor.modelToView(token.end);
752 final Rectangle show = start.union(end);
753 show.grow(start.width * 10, start.height * 6);
754 SwingUtilities.invokeLater(new Runnable() {
755 @Override
756 public void run() {
757 m_editor.scrollRectToVisible(show);
758 }
759 });
760 } catch (BadLocationException ex) {
761 throw new Error(ex);
762 }
763
764 // highlight the token momentarily
765 final Timer timer = new Timer(200, new ActionListener() {
766 private int m_counter = 0;
767 private Object m_highlight = null;
768
769 @Override
770 public void actionPerformed(ActionEvent event) {
771 if (m_counter % 2 == 0) {
772 try {
773 m_highlight = m_editor.getHighlighter().addHighlight(token.start, token.end, m_selectionHighlightPainter);
774 } catch (BadLocationException ex) {
775 // don't care
776 }
777 } else if (m_highlight != null) {
778 m_editor.getHighlighter().removeHighlight(m_highlight);
779 }
780
781 if (m_counter++ > 6) {
782 Timer timer = (Timer)event.getSource();
783 timer.stop();
784 }
785 }
786 });
787 timer.start();
788
789 redraw(); 741 redraw();
790 } 742 }
791 743
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 @@
11package cuchaz.enigma.gui; 11package cuchaz.enigma.gui;
12 12
13import java.awt.Font; 13import java.awt.Font;
14import java.awt.Rectangle;
15import java.awt.event.ActionEvent;
16import java.awt.event.ActionListener;
14import java.awt.event.MouseEvent; 17import java.awt.event.MouseEvent;
15 18
16import javax.swing.JComponent; 19import javax.swing.JComponent;
20import javax.swing.JEditorPane;
17import javax.swing.JLabel; 21import javax.swing.JLabel;
22import javax.swing.SwingUtilities;
23import javax.swing.Timer;
18import javax.swing.ToolTipManager; 24import javax.swing.ToolTipManager;
25import javax.swing.text.BadLocationException;
26import javax.swing.text.Highlighter.HighlightPainter;
27
28import cuchaz.enigma.analysis.Token;
19 29
20public class GuiTricks { 30public class GuiTricks {
21 31
@@ -33,4 +43,52 @@ public class GuiTricks {
33 manager.mouseMoved(new MouseEvent(component, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, 0, 0, 0, false)); 43 manager.mouseMoved(new MouseEvent(component, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, 0, 0, 0, false));
34 manager.setInitialDelay(oldDelay); 44 manager.setInitialDelay(oldDelay);
35 } 45 }
46
47 public static void navigateToToken(final JEditorPane editor, final Token token, final HighlightPainter highlightPainter) {
48
49 // set the caret position to the token
50 editor.setCaretPosition(token.start);
51 editor.grabFocus();
52
53 try {
54 // make sure the token is visible in the scroll window
55 Rectangle start = editor.modelToView(token.start);
56 Rectangle end = editor.modelToView(token.end);
57 final Rectangle show = start.union(end);
58 show.grow(start.width * 10, start.height * 6);
59 SwingUtilities.invokeLater(new Runnable() {
60 @Override
61 public void run() {
62 editor.scrollRectToVisible(show);
63 }
64 });
65 } catch (BadLocationException ex) {
66 throw new Error(ex);
67 }
68
69 // highlight the token momentarily
70 final Timer timer = new Timer(200, new ActionListener() {
71 private int m_counter = 0;
72 private Object m_highlight = null;
73
74 @Override
75 public void actionPerformed(ActionEvent event) {
76 if (m_counter % 2 == 0) {
77 try {
78 m_highlight = editor.getHighlighter().addHighlight(token.start, token.end, highlightPainter);
79 } catch (BadLocationException ex) {
80 // don't care
81 }
82 } else if (m_highlight != null) {
83 editor.getHighlighter().removeHighlight(m_highlight);
84 }
85
86 if (m_counter++ > 6) {
87 Timer timer = (Timer)event.getSource();
88 timer.stop();
89 }
90 }
91 });
92 timer.start();
93 }
36} 94}
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;
10import java.util.Arrays; 10import java.util.Arrays;
11import java.util.Collection; 11import java.util.Collection;
12import java.util.Collections; 12import java.util.Collections;
13import java.util.Enumeration;
14import java.util.List; 13import java.util.List;
15import java.util.Map; 14import java.util.Map;
16 15
@@ -27,17 +26,18 @@ import javax.swing.JScrollPane;
27import javax.swing.JSplitPane; 26import javax.swing.JSplitPane;
28import javax.swing.SwingConstants; 27import javax.swing.SwingConstants;
29import javax.swing.WindowConstants; 28import javax.swing.WindowConstants;
30import javax.swing.tree.DefaultMutableTreeNode;
31import javax.swing.tree.TreePath;
32 29
33import com.beust.jcommander.internal.Lists; 30import com.beust.jcommander.internal.Lists;
34import com.beust.jcommander.internal.Maps; 31import com.beust.jcommander.internal.Maps;
35import com.google.common.collect.ArrayListMultimap; 32import com.google.common.collect.ArrayListMultimap;
36import com.google.common.collect.BiMap; 33import com.google.common.collect.BiMap;
37import com.google.common.collect.Multimap; 34import com.google.common.collect.Multimap;
35import com.strobel.decompiler.languages.java.ast.CompilationUnit;
38 36
39import cuchaz.enigma.Constants; 37import cuchaz.enigma.Constants;
40import cuchaz.enigma.Deobfuscator; 38import cuchaz.enigma.Deobfuscator;
39import cuchaz.enigma.analysis.SourceIndex;
40import cuchaz.enigma.analysis.Token;
41import cuchaz.enigma.convert.ClassIdentifier; 41import cuchaz.enigma.convert.ClassIdentifier;
42import cuchaz.enigma.convert.ClassIdentity; 42import cuchaz.enigma.convert.ClassIdentity;
43import cuchaz.enigma.convert.ClassMatch; 43import cuchaz.enigma.convert.ClassMatch;
@@ -47,6 +47,7 @@ import cuchaz.enigma.convert.MappingsConverter;
47import cuchaz.enigma.convert.Matches; 47import cuchaz.enigma.convert.Matches;
48import cuchaz.enigma.gui.ClassSelector.ClassSelectionListener; 48import cuchaz.enigma.gui.ClassSelector.ClassSelectionListener;
49import cuchaz.enigma.mapping.ClassEntry; 49import cuchaz.enigma.mapping.ClassEntry;
50import cuchaz.enigma.mapping.Entry;
50import de.sciss.syntaxpane.DefaultSyntaxKit; 51import de.sciss.syntaxpane.DefaultSyntaxKit;
51 52
52 53
@@ -105,6 +106,7 @@ public class MatchingGui {
105 private JButton m_matchButton; 106 private JButton m_matchButton;
106 private Map<SourceType,JRadioButton> m_sourceTypeButtons; 107 private Map<SourceType,JRadioButton> m_sourceTypeButtons;
107 private JCheckBox m_advanceCheck; 108 private JCheckBox m_advanceCheck;
109 private SelectionHighlightPainter m_selectionHighlightPainter;
108 110
109 private Matches m_matches; 111 private Matches m_matches;
110 private Deobfuscator m_sourceDeobfuscator; 112 private Deobfuscator m_sourceDeobfuscator;
@@ -188,12 +190,8 @@ public class MatchingGui {
188 190
189 // init source panels 191 // init source panels
190 DefaultSyntaxKit.initKit(); 192 DefaultSyntaxKit.initKit();
191 m_sourceReader = new JEditorPane(); 193 m_sourceReader = makeReader();
192 m_sourceReader.setEditable(false); 194 m_destReader = makeReader();
193 m_sourceReader.setContentType("text/java");
194 m_destReader = new JEditorPane();
195 m_destReader.setEditable(false);
196 m_destReader.setContentType("text/java");
197 195
198 // init all the splits 196 // init all the splits
199 JSplitPane splitLeft = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, sourcePanel, new JScrollPane(m_sourceReader)); 197 JSplitPane splitLeft = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, sourcePanel, new JScrollPane(m_sourceReader));
@@ -220,6 +218,14 @@ public class MatchingGui {
220 m_matchButton.setPreferredSize(new Dimension(140, 24)); 218 m_matchButton.setPreferredSize(new Dimension(140, 24));
221 219
222 m_advanceCheck = new JCheckBox("Advance to next likely match"); 220 m_advanceCheck = new JCheckBox("Advance to next likely match");
221 m_advanceCheck.addActionListener(new ActionListener() {
222 @Override
223 public void actionPerformed(ActionEvent event) {
224 if (m_advanceCheck.isSelected()) {
225 advance();
226 }
227 }
228 });
223 229
224 bottomPanel.add(m_sourceClassLabel); 230 bottomPanel.add(m_sourceClassLabel);
225 bottomPanel.add(m_matchButton); 231 bottomPanel.add(m_matchButton);
@@ -234,6 +240,8 @@ public class MatchingGui {
234 m_frame.setVisible(true); 240 m_frame.setVisible(true);
235 m_frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 241 m_frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
236 242
243 m_selectionHighlightPainter = new SelectionHighlightPainter();
244
237 // init state 245 // init state
238 updateDestMappings(); 246 updateDestMappings();
239 setSourceType(SourceType.getDefault()); 247 setSourceType(SourceType.getDefault());
@@ -241,6 +249,19 @@ public class MatchingGui {
241 m_saveListener = null; 249 m_saveListener = null;
242 } 250 }
243 251
252 private JEditorPane makeReader() {
253
254 JEditorPane reader = new JEditorPane();
255 reader.setEditable(false);
256 reader.setContentType("text/java");
257
258 // turn off token highlighting (it's wrong most of the time anyway...)
259 DefaultSyntaxKit kit = (DefaultSyntaxKit)reader.getEditorKit();
260 kit.toggleComponent(reader, "de.sciss.syntaxpane.components.TokenMarker");
261
262 return reader;
263 }
264
244 public void setSaveListener(SaveListener val) { 265 public void setSaveListener(SaveListener val) {
245 m_saveListener = val; 266 m_saveListener = val;
246 } 267 }
@@ -272,12 +293,24 @@ public class MatchingGui {
272 private Collection<ClassEntry> deobfuscateClasses(Collection<ClassEntry> in, Deobfuscator deobfuscator) { 293 private Collection<ClassEntry> deobfuscateClasses(Collection<ClassEntry> in, Deobfuscator deobfuscator) {
273 List<ClassEntry> out = Lists.newArrayList(); 294 List<ClassEntry> out = Lists.newArrayList();
274 for (ClassEntry entry : in) { 295 for (ClassEntry entry : in) {
275 out.add(deobfuscator.deobfuscateEntry(entry)); 296
297 ClassEntry deobf = deobfuscator.deobfuscateEntry(entry);
298
299 // make sure we preserve any scores
300 if (entry instanceof ScoredClassEntry) {
301 deobf = new ScoredClassEntry(deobf, ((ScoredClassEntry)entry).getScore());
302 }
303
304 out.add(deobf);
276 } 305 }
277 return out; 306 return out;
278 } 307 }
279 308
280 protected void setSourceClass(ClassEntry classEntry) { 309 protected void setSourceClass(ClassEntry classEntry) {
310 setSourceClass(classEntry, null);
311 }
312
313 protected void setSourceClass(ClassEntry classEntry, final Runnable onGetDestClasses) {
281 314
282 // update the current source class 315 // update the current source class
283 m_sourceClass = classEntry; 316 m_sourceClass = classEntry;
@@ -297,20 +330,27 @@ public class MatchingGui {
297 @Override 330 @Override
298 public void run() { 331 public void run() {
299 m_destClasses.setClasses(deobfuscateClasses(getLikelyMatches(m_sourceClass), m_destDeobfuscator)); 332 m_destClasses.setClasses(deobfuscateClasses(getLikelyMatches(m_sourceClass), m_destDeobfuscator));
300 m_destClasses.expandRow(0); 333 m_destClasses.expandAll();
334
335 if (onGetDestClasses != null) {
336 onGetDestClasses.run();
337 }
301 } 338 }
302 }.start(); 339 }.start();
303 340
304 } else { 341 } else {
305 342
306 m_destClasses.setClasses(deobfuscateClasses(match.destClasses, m_destDeobfuscator)); 343 m_destClasses.setClasses(deobfuscateClasses(match.destClasses, m_destDeobfuscator));
307 m_destClasses.expandRow(0); 344 m_destClasses.expandAll();
308 345
346 if (onGetDestClasses != null) {
347 onGetDestClasses.run();
348 }
309 } 349 }
310 } 350 }
311 351
312 setDestClass(null); 352 setDestClass(null);
313 readSource(m_sourceClass, m_sourceDeobfuscator, m_sourceReader); 353 decompileClass(m_sourceClass, m_sourceDeobfuscator, m_sourceReader);
314 354
315 updateMatchButton(); 355 updateMatchButton();
316 } 356 }
@@ -334,29 +374,14 @@ public class MatchingGui {
334 374
335 // rank all the unmatched dest classes against the source class 375 // rank all the unmatched dest classes against the source class
336 ClassIdentity sourceIdentity = sourceIdentifier.identify(obfSourceClass); 376 ClassIdentity sourceIdentity = sourceIdentifier.identify(obfSourceClass);
337 Multimap<Float,ClassEntry> scoredDestClasses = ArrayListMultimap.create(); 377 List<ClassEntry> scoredDestClasses = Lists.newArrayList();
338 for (ClassEntry unmatchedDestClass : m_matches.getUnmatchedDestClasses()) { 378 for (ClassEntry unmatchedDestClass : m_matches.getUnmatchedDestClasses()) {
339 ClassIdentity destIdentity = destIdentifier.identify(unmatchedDestClass); 379 ClassIdentity destIdentity = destIdentifier.identify(unmatchedDestClass);
340 float score = 100.0f*(sourceIdentity.getMatchScore(destIdentity) + destIdentity.getMatchScore(sourceIdentity)) 380 float score = 100.0f*(sourceIdentity.getMatchScore(destIdentity) + destIdentity.getMatchScore(sourceIdentity))
341 /(sourceIdentity.getMaxMatchScore() + destIdentity.getMaxMatchScore()); 381 /(sourceIdentity.getMaxMatchScore() + destIdentity.getMaxMatchScore());
342 scoredDestClasses.put(score, unmatchedDestClass); 382 scoredDestClasses.add(new ScoredClassEntry(unmatchedDestClass, score));
343 }
344
345 // sort by scores
346 List<Float> scores = new ArrayList<Float>(scoredDestClasses.keySet());
347 Collections.sort(scores, Collections.reverseOrder());
348
349 // collect the scored classes in order
350 List<ClassEntry> scoredClasses = Lists.newArrayList();
351 for (float score : scores) {
352 for (ClassEntry classEntry : scoredDestClasses.get(score)) {
353 scoredClasses.add(new DecoratedClassEntry(classEntry, String.format("%2.0f%% ", score)));
354 if (scoredClasses.size() > 10) {
355 return scoredClasses;
356 }
357 }
358 } 383 }
359 return scoredClasses; 384 return scoredDestClasses;
360 385
361 } catch (ClassNotFoundException ex) { 386 } catch (ClassNotFoundException ex) {
362 throw new Error("Unable to find class " + ex.getMessage()); 387 throw new Error("Unable to find class " + ex.getMessage());
@@ -369,12 +394,12 @@ public class MatchingGui {
369 m_destClass = classEntry; 394 m_destClass = classEntry;
370 m_destClassLabel.setText(m_destClass != null ? m_destClass.getName() : ""); 395 m_destClassLabel.setText(m_destClass != null ? m_destClass.getName() : "");
371 396
372 readSource(m_destClass, m_destDeobfuscator, m_destReader); 397 decompileClass(m_destClass, m_destDeobfuscator, m_destReader);
373 398
374 updateMatchButton(); 399 updateMatchButton();
375 } 400 }
376 401
377 protected void readSource(final ClassEntry classEntry, final Deobfuscator deobfuscator, final JEditorPane reader) { 402 protected void decompileClass(final ClassEntry classEntry, final Deobfuscator deobfuscator, final JEditorPane reader) {
378 403
379 if (classEntry == null) { 404 if (classEntry == null) {
380 reader.setText(null); 405 reader.setText(null);
@@ -389,12 +414,37 @@ public class MatchingGui {
389 public void run() { 414 public void run() {
390 415
391 // get the outermost class 416 // get the outermost class
392 ClassEntry obfClassEntry = deobfuscator.obfuscateEntry(classEntry); 417 ClassEntry outermostClassEntry = classEntry;
393 List<ClassEntry> classChain = deobfuscator.getJarIndex().getObfClassChain(obfClassEntry); 418 while (outermostClassEntry.isInnerClass()) {
394 ClassEntry obfOutermostClassEntry = classChain.get(0); 419 outermostClassEntry = outermostClassEntry.getOuterClassEntry();
420 }
395 421
396 // decompile it 422 // decompile it
397 reader.setText(deobfuscator.getSource(deobfuscator.getSourceTree(obfOutermostClassEntry.getName()))); 423 CompilationUnit sourceTree = deobfuscator.getSourceTree(outermostClassEntry.getName());
424 String source = deobfuscator.getSource(sourceTree);
425 reader.setText(source);
426 SourceIndex sourceIndex = deobfuscator.getSourceIndex(sourceTree, source);
427
428 // navigate to the class declaration
429 Token token = sourceIndex.getDeclarationToken(classEntry);
430 if (token == null) {
431 // couldn't find the class declaration token, might be an anonymous class
432 // look for any declaration in that class instead
433 for (Entry entry : sourceIndex.declarations()) {
434 if (entry.getClassEntry().equals(classEntry)) {
435 token = sourceIndex.getDeclarationToken(entry);
436 break;
437 }
438 }
439 }
440
441 if (token != null) {
442 GuiTricks.navigateToToken(reader, token, m_selectionHighlightPainter);
443 } else {
444 // couldn't find anything =(
445 System.out.println("Unable to find declaration in source for " + classEntry);
446 }
447
398 } 448 }
399 }.start(); 449 }.start();
400 } 450 }
@@ -459,11 +509,16 @@ public class MatchingGui {
459 // add them as matched classes 509 // add them as matched classes
460 m_matches.add(new ClassMatch(obfSource, obfDest)); 510 m_matches.add(new ClassMatch(obfSource, obfDest));
461 511
512 ClassEntry nextClass = null;
513 if (m_advanceCheck.isSelected()) {
514 nextClass = m_sourceClasses.getNextClass(m_sourceClass);
515 }
516
462 save(); 517 save();
463 updateMatches(); 518 updateMatches();
464 519
465 if (m_advanceCheck.isSelected()) { 520 if (nextClass != null) {
466 advance(); 521 advance(nextClass);
467 } 522 }
468 } 523 }
469 524
@@ -487,31 +542,11 @@ public class MatchingGui {
487 updateMatchButton(); 542 updateMatchButton();
488 543
489 // remember where we were in the source tree 544 // remember where we were in the source tree
490 String packageName = null; 545 String packageName = m_sourceClasses.getSelectedPackage();
491 if (!m_sourceClasses.isSelectionEmpty()) {
492 packageName = m_sourceClasses.getSelectionPath().getParentPath().getLastPathComponent().toString();
493 }
494 546
495 setSourceType(m_sourceType); 547 setSourceType(m_sourceType);
496 548
497 if (packageName != null) { 549 m_sourceClasses.expandPackage(packageName);
498 // find the corresponding path in the new tree
499 TreePath path = null;
500 DefaultMutableTreeNode root = (DefaultMutableTreeNode)m_sourceClasses.getModel().getRoot();
501 Enumeration<?> children = root.children();
502 while (children.hasMoreElements()) {
503 Object child = children.nextElement();
504 if (child.toString().equals(packageName)) {
505 path = new TreePath(new Object[] {root, child});
506 break;
507 }
508 }
509
510 if (path != null) {
511 // put the tree back to where it was
512 m_sourceClasses.expandPath(path);
513 }
514 }
515 } 550 }
516 551
517 private void save() { 552 private void save() {
@@ -542,6 +577,55 @@ public class MatchingGui {
542 } 577 }
543 578
544 private void advance() { 579 private void advance() {
545 // TODO: find a likely match 580 advance(null);
581 }
582
583 private void advance(ClassEntry sourceClass) {
584
585 // make sure we have a source class
586 if (sourceClass == null) {
587 sourceClass = m_sourceClasses.getSelectedClass();
588 if (sourceClass != null) {
589 sourceClass = m_sourceClasses.getNextClass(sourceClass);
590 } else {
591 sourceClass = m_sourceClasses.getFirstClass();
592 }
593 }
594
595 // set the source class
596 setSourceClass(sourceClass, new Runnable() {
597 @Override
598 public void run() {
599
600 // then, pick the best dest class
601 ClassEntry firstClass = null;
602 ScoredClassEntry bestDestClass = null;
603 for (ClassSelectorPackageNode packageNode : m_destClasses.packageNodes()) {
604 for (ClassSelectorClassNode classNode : m_destClasses.classNodes(packageNode)) {
605 if (firstClass == null) {
606 firstClass = classNode.getClassEntry();
607 }
608 if (classNode.getClassEntry() instanceof ScoredClassEntry) {
609 ScoredClassEntry scoredClass = (ScoredClassEntry)classNode.getClassEntry();
610 if (bestDestClass == null || bestDestClass.getScore() < scoredClass.getScore()) {
611 bestDestClass = scoredClass;
612 }
613 }
614 }
615 }
616
617 // pick the entry to show
618 ClassEntry destClass = null;
619 if (bestDestClass != null) {
620 destClass = bestDestClass;
621 } else if (firstClass != null) {
622 destClass = firstClass;
623 }
624
625 setDestClass(destClass);
626 m_destClasses.setSelectionClass(destClass);
627 }
628 });
629 m_sourceClasses.setSelectionClass(sourceClass);
546 } 630 }
547} 631}
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 @@
1package cuchaz.enigma.gui;
2
3import cuchaz.enigma.mapping.ClassEntry;
4
5
6public class ScoredClassEntry extends ClassEntry {
7
8 private static final long serialVersionUID = -8798725308554217105L;
9
10 private float m_score;
11
12 public ScoredClassEntry(ClassEntry other, float score) {
13 super(other);
14 m_score = score;
15 }
16
17 public float getScore() {
18 return m_score;
19 }
20}