summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/gui
diff options
context:
space:
mode:
authorGravatar jeff2015-03-09 12:53:11 -0400
committerGravatar jeff2015-03-09 12:53:11 -0400
commitd6b2a223a7973941e5e4fb45c8ceec4885891496 (patch)
tree5728ab513d0b4ed85a720da7eb48c6591dd3f8b0 /src/cuchaz/enigma/gui
parentadd tracking for mismatched fields/methods (diff)
downloadenigma-fork-d6b2a223a7973941e5e4fb45c8ceec4885891496.tar.gz
enigma-fork-d6b2a223a7973941e5e4fb45c8ceec4885891496.tar.xz
enigma-fork-d6b2a223a7973941e5e4fb45c8ceec4885891496.zip
starting on field matching gui
Diffstat (limited to 'src/cuchaz/enigma/gui')
-rw-r--r--src/cuchaz/enigma/gui/ClassMatchingGui.java145
-rw-r--r--src/cuchaz/enigma/gui/CodeReader.java164
-rw-r--r--src/cuchaz/enigma/gui/FieldMatchingGui.java131
-rw-r--r--src/cuchaz/enigma/gui/Gui.java2
-rw-r--r--src/cuchaz/enigma/gui/GuiTricks.java58
5 files changed, 338 insertions, 162 deletions
diff --git a/src/cuchaz/enigma/gui/ClassMatchingGui.java b/src/cuchaz/enigma/gui/ClassMatchingGui.java
index ff7cda9..b674451 100644
--- a/src/cuchaz/enigma/gui/ClassMatchingGui.java
+++ b/src/cuchaz/enigma/gui/ClassMatchingGui.java
@@ -15,7 +15,6 @@ import javax.swing.BoxLayout;
15import javax.swing.ButtonGroup; 15import javax.swing.ButtonGroup;
16import javax.swing.JButton; 16import javax.swing.JButton;
17import javax.swing.JCheckBox; 17import javax.swing.JCheckBox;
18import javax.swing.JEditorPane;
19import javax.swing.JFrame; 18import javax.swing.JFrame;
20import javax.swing.JLabel; 19import javax.swing.JLabel;
21import javax.swing.JPanel; 20import javax.swing.JPanel;
@@ -28,22 +27,18 @@ import javax.swing.WindowConstants;
28import com.beust.jcommander.internal.Lists; 27import com.beust.jcommander.internal.Lists;
29import com.beust.jcommander.internal.Maps; 28import com.beust.jcommander.internal.Maps;
30import com.google.common.collect.BiMap; 29import com.google.common.collect.BiMap;
31import com.strobel.decompiler.languages.java.ast.CompilationUnit;
32 30
33import cuchaz.enigma.Constants; 31import cuchaz.enigma.Constants;
34import cuchaz.enigma.Deobfuscator; 32import cuchaz.enigma.Deobfuscator;
35import cuchaz.enigma.analysis.SourceIndex;
36import cuchaz.enigma.analysis.Token;
37import cuchaz.enigma.convert.ClassIdentifier; 33import cuchaz.enigma.convert.ClassIdentifier;
38import cuchaz.enigma.convert.ClassIdentity; 34import cuchaz.enigma.convert.ClassIdentity;
39import cuchaz.enigma.convert.ClassMatch; 35import cuchaz.enigma.convert.ClassMatch;
36import cuchaz.enigma.convert.ClassMatches;
40import cuchaz.enigma.convert.ClassMatching; 37import cuchaz.enigma.convert.ClassMatching;
41import cuchaz.enigma.convert.ClassNamer; 38import cuchaz.enigma.convert.ClassNamer;
42import cuchaz.enigma.convert.MappingsConverter; 39import cuchaz.enigma.convert.MappingsConverter;
43import cuchaz.enigma.convert.Matches;
44import cuchaz.enigma.gui.ClassSelector.ClassSelectionListener; 40import cuchaz.enigma.gui.ClassSelector.ClassSelectionListener;
45import cuchaz.enigma.mapping.ClassEntry; 41import cuchaz.enigma.mapping.ClassEntry;
46import cuchaz.enigma.mapping.Entry;
47import cuchaz.enigma.mapping.Mappings; 42import cuchaz.enigma.mapping.Mappings;
48import cuchaz.enigma.mapping.MappingsChecker; 43import cuchaz.enigma.mapping.MappingsChecker;
49import de.sciss.syntaxpane.DefaultSyntaxKit; 44import de.sciss.syntaxpane.DefaultSyntaxKit;
@@ -55,21 +50,21 @@ public class ClassMatchingGui {
55 Matched { 50 Matched {
56 51
57 @Override 52 @Override
58 public Collection<ClassEntry> getSourceClasses(Matches matches) { 53 public Collection<ClassEntry> getSourceClasses(ClassMatches matches) {
59 return matches.getUniqueMatches().keySet(); 54 return matches.getUniqueMatches().keySet();
60 } 55 }
61 }, 56 },
62 Unmatched { 57 Unmatched {
63 58
64 @Override 59 @Override
65 public Collection<ClassEntry> getSourceClasses(Matches matches) { 60 public Collection<ClassEntry> getSourceClasses(ClassMatches matches) {
66 return matches.getUnmatchedSourceClasses(); 61 return matches.getUnmatchedSourceClasses();
67 } 62 }
68 }, 63 },
69 Ambiguous { 64 Ambiguous {
70 65
71 @Override 66 @Override
72 public Collection<ClassEntry> getSourceClasses(Matches matches) { 67 public Collection<ClassEntry> getSourceClasses(ClassMatches matches) {
73 return matches.getAmbiguouslyMatchedSourceClasses(); 68 return matches.getAmbiguouslyMatchedSourceClasses();
74 } 69 }
75 }; 70 };
@@ -82,7 +77,7 @@ public class ClassMatchingGui {
82 return button; 77 return button;
83 } 78 }
84 79
85 public abstract Collection<ClassEntry> getSourceClasses(Matches matches); 80 public abstract Collection<ClassEntry> getSourceClasses(ClassMatches matches);
86 81
87 public static SourceType getDefault() { 82 public static SourceType getDefault() {
88 return values()[0]; 83 return values()[0];
@@ -90,23 +85,22 @@ public class ClassMatchingGui {
90 } 85 }
91 86
92 public static interface SaveListener { 87 public static interface SaveListener {
93 public void save(Matches matches); 88 public void save(ClassMatches matches);
94 } 89 }
95 90
96 // controls 91 // controls
97 private JFrame m_frame; 92 private JFrame m_frame;
98 private ClassSelector m_sourceClasses; 93 private ClassSelector m_sourceClasses;
99 private ClassSelector m_destClasses; 94 private ClassSelector m_destClasses;
100 private JEditorPane m_sourceReader; 95 private CodeReader m_sourceReader;
101 private JEditorPane m_destReader; 96 private CodeReader m_destReader;
102 private JLabel m_sourceClassLabel; 97 private JLabel m_sourceClassLabel;
103 private JLabel m_destClassLabel; 98 private JLabel m_destClassLabel;
104 private JButton m_matchButton; 99 private JButton m_matchButton;
105 private Map<SourceType,JRadioButton> m_sourceTypeButtons; 100 private Map<SourceType,JRadioButton> m_sourceTypeButtons;
106 private JCheckBox m_advanceCheck; 101 private JCheckBox m_advanceCheck;
107 private SelectionHighlightPainter m_selectionHighlightPainter;
108 102
109 private Matches m_matches; 103 private ClassMatches m_classMatches;
110 private Deobfuscator m_sourceDeobfuscator; 104 private Deobfuscator m_sourceDeobfuscator;
111 private Deobfuscator m_destDeobfuscator; 105 private Deobfuscator m_destDeobfuscator;
112 private ClassEntry m_sourceClass; 106 private ClassEntry m_sourceClass;
@@ -114,14 +108,14 @@ public class ClassMatchingGui {
114 private SourceType m_sourceType; 108 private SourceType m_sourceType;
115 private SaveListener m_saveListener; 109 private SaveListener m_saveListener;
116 110
117 public ClassMatchingGui(Matches matches, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) { 111 public ClassMatchingGui(ClassMatches matches, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) {
118 112
119 m_matches = matches; 113 m_classMatches = matches;
120 m_sourceDeobfuscator = sourceDeobfuscator; 114 m_sourceDeobfuscator = sourceDeobfuscator;
121 m_destDeobfuscator = destDeobfuscator; 115 m_destDeobfuscator = destDeobfuscator;
122 116
123 // init frame 117 // init frame
124 m_frame = new JFrame(Constants.Name); 118 m_frame = new JFrame(Constants.Name + " - Class Matcher");
125 final Container pane = m_frame.getContentPane(); 119 final Container pane = m_frame.getContentPane();
126 pane.setLayout(new BorderLayout()); 120 pane.setLayout(new BorderLayout());
127 121
@@ -188,8 +182,8 @@ public class ClassMatchingGui {
188 182
189 // init source panels 183 // init source panels
190 DefaultSyntaxKit.initKit(); 184 DefaultSyntaxKit.initKit();
191 m_sourceReader = makeReader(); 185 m_sourceReader = new CodeReader();
192 m_destReader = makeReader(); 186 m_destReader = new CodeReader();
193 187
194 // init all the splits 188 // init all the splits
195 JSplitPane splitLeft = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, sourcePanel, new JScrollPane(m_sourceReader)); 189 JSplitPane splitLeft = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, sourcePanel, new JScrollPane(m_sourceReader));
@@ -238,8 +232,6 @@ public class ClassMatchingGui {
238 m_frame.setVisible(true); 232 m_frame.setVisible(true);
239 m_frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 233 m_frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
240 234
241 m_selectionHighlightPainter = new SelectionHighlightPainter();
242
243 // init state 235 // init state
244 updateDestMappings(); 236 updateDestMappings();
245 setSourceType(SourceType.getDefault()); 237 setSourceType(SourceType.getDefault());
@@ -247,19 +239,6 @@ public class ClassMatchingGui {
247 m_saveListener = null; 239 m_saveListener = null;
248 } 240 }
249 241
250 private JEditorPane makeReader() {
251
252 JEditorPane reader = new JEditorPane();
253 reader.setEditable(false);
254 reader.setContentType("text/java");
255
256 // turn off token highlighting (it's wrong most of the time anyway...)
257 DefaultSyntaxKit kit = (DefaultSyntaxKit)reader.getEditorKit();
258 kit.toggleComponent(reader, "de.sciss.syntaxpane.components.TokenMarker");
259
260 return reader;
261 }
262
263 public void setSaveListener(SaveListener val) { 242 public void setSaveListener(SaveListener val) {
264 m_saveListener = val; 243 m_saveListener = val;
265 } 244 }
@@ -267,7 +246,7 @@ public class ClassMatchingGui {
267 private void updateDestMappings() { 246 private void updateDestMappings() {
268 247
269 Mappings newMappings = MappingsConverter.newMappings( 248 Mappings newMappings = MappingsConverter.newMappings(
270 m_matches, 249 m_classMatches,
271 m_sourceDeobfuscator.getMappings(), 250 m_sourceDeobfuscator.getMappings(),
272 m_sourceDeobfuscator, 251 m_sourceDeobfuscator,
273 m_destDeobfuscator 252 m_destDeobfuscator
@@ -294,13 +273,13 @@ public class ClassMatchingGui {
294 273
295 // show the source classes 274 // show the source classes
296 m_sourceType = val; 275 m_sourceType = val;
297 m_sourceClasses.setClasses(deobfuscateClasses(m_sourceType.getSourceClasses(m_matches), m_sourceDeobfuscator)); 276 m_sourceClasses.setClasses(deobfuscateClasses(m_sourceType.getSourceClasses(m_classMatches), m_sourceDeobfuscator));
298 277
299 // update counts 278 // update counts
300 for (SourceType sourceType : SourceType.values()) { 279 for (SourceType sourceType : SourceType.values()) {
301 m_sourceTypeButtons.get(sourceType).setText(String.format("%s (%d)", 280 m_sourceTypeButtons.get(sourceType).setText(String.format("%s (%d)",
302 sourceType.name(), 281 sourceType.name(),
303 sourceType.getSourceClasses(m_matches).size() 282 sourceType.getSourceClasses(m_classMatches).size()
304 )); 283 ));
305 } 284 }
306 } 285 }
@@ -345,7 +324,7 @@ public class ClassMatchingGui {
345 if (m_sourceClass != null) { 324 if (m_sourceClass != null) {
346 325
347 // show the dest class(es) 326 // show the dest class(es)
348 ClassMatch match = m_matches.getMatchBySource(m_sourceDeobfuscator.obfuscateEntry(m_sourceClass)); 327 ClassMatch match = m_classMatches.getMatchBySource(m_sourceDeobfuscator.obfuscateEntry(m_sourceClass));
349 assert(match != null); 328 assert(match != null);
350 if (match.destClasses.isEmpty()) { 329 if (match.destClasses.isEmpty()) {
351 330
@@ -376,7 +355,12 @@ public class ClassMatchingGui {
376 } 355 }
377 356
378 setDestClass(null); 357 setDestClass(null);
379 decompileClass(m_sourceClass, m_sourceDeobfuscator, m_sourceReader); 358 m_sourceReader.decompileClass(m_sourceClass, m_sourceDeobfuscator, new Runnable() {
359 @Override
360 public void run() {
361 m_sourceReader.navigateToClassDeclaration(m_sourceClass);
362 }
363 });
380 364
381 updateMatchButton(); 365 updateMatchButton();
382 } 366 }
@@ -386,7 +370,7 @@ public class ClassMatchingGui {
386 ClassEntry obfSourceClass = m_sourceDeobfuscator.obfuscateEntry(sourceClass); 370 ClassEntry obfSourceClass = m_sourceDeobfuscator.obfuscateEntry(sourceClass);
387 371
388 // set up identifiers 372 // set up identifiers
389 ClassNamer namer = new ClassNamer(m_matches.getUniqueMatches()); 373 ClassNamer namer = new ClassNamer(m_classMatches.getUniqueMatches());
390 ClassIdentifier sourceIdentifier = new ClassIdentifier( 374 ClassIdentifier sourceIdentifier = new ClassIdentifier(
391 m_sourceDeobfuscator.getJar(), m_sourceDeobfuscator.getJarIndex(), 375 m_sourceDeobfuscator.getJar(), m_sourceDeobfuscator.getJarIndex(),
392 namer.getSourceNamer(), true 376 namer.getSourceNamer(), true
@@ -401,7 +385,7 @@ public class ClassMatchingGui {
401 // rank all the unmatched dest classes against the source class 385 // rank all the unmatched dest classes against the source class
402 ClassIdentity sourceIdentity = sourceIdentifier.identify(obfSourceClass); 386 ClassIdentity sourceIdentity = sourceIdentifier.identify(obfSourceClass);
403 List<ClassEntry> scoredDestClasses = Lists.newArrayList(); 387 List<ClassEntry> scoredDestClasses = Lists.newArrayList();
404 for (ClassEntry unmatchedDestClass : m_matches.getUnmatchedDestClasses()) { 388 for (ClassEntry unmatchedDestClass : m_classMatches.getUnmatchedDestClasses()) {
405 ClassIdentity destIdentity = destIdentifier.identify(unmatchedDestClass); 389 ClassIdentity destIdentity = destIdentifier.identify(unmatchedDestClass);
406 float score = 100.0f*(sourceIdentity.getMatchScore(destIdentity) + destIdentity.getMatchScore(sourceIdentity)) 390 float score = 100.0f*(sourceIdentity.getMatchScore(destIdentity) + destIdentity.getMatchScore(sourceIdentity))
407 /(sourceIdentity.getMaxMatchScore() + destIdentity.getMaxMatchScore()); 391 /(sourceIdentity.getMaxMatchScore() + destIdentity.getMaxMatchScore());
@@ -420,59 +404,14 @@ public class ClassMatchingGui {
420 m_destClass = classEntry; 404 m_destClass = classEntry;
421 m_destClassLabel.setText(m_destClass != null ? m_destClass.getName() : ""); 405 m_destClassLabel.setText(m_destClass != null ? m_destClass.getName() : "");
422 406
423 decompileClass(m_destClass, m_destDeobfuscator, m_destReader); 407 m_destReader.decompileClass(m_destClass, m_destDeobfuscator, new Runnable() {
424
425 updateMatchButton();
426 }
427
428 protected void decompileClass(final ClassEntry classEntry, final Deobfuscator deobfuscator, final JEditorPane reader) {
429
430 if (classEntry == null) {
431 reader.setText(null);
432 return;
433 }
434
435 reader.setText("(decompiling...)");
436
437 // run in a separate thread to keep ui responsive
438 new Thread() {
439 @Override 408 @Override
440 public void run() { 409 public void run() {
441 410 m_destReader.navigateToClassDeclaration(m_destClass);
442 // get the outermost class
443 ClassEntry outermostClassEntry = classEntry;
444 while (outermostClassEntry.isInnerClass()) {
445 outermostClassEntry = outermostClassEntry.getOuterClassEntry();
446 }
447
448 // decompile it
449 CompilationUnit sourceTree = deobfuscator.getSourceTree(outermostClassEntry.getName());
450 String source = deobfuscator.getSource(sourceTree);
451 reader.setText(source);
452 SourceIndex sourceIndex = deobfuscator.getSourceIndex(sourceTree, source);
453
454 // navigate to the class declaration
455 Token token = sourceIndex.getDeclarationToken(classEntry);
456 if (token == null) {
457 // couldn't find the class declaration token, might be an anonymous class
458 // look for any declaration in that class instead
459 for (Entry entry : sourceIndex.declarations()) {
460 if (entry.getClassEntry().equals(classEntry)) {
461 token = sourceIndex.getDeclarationToken(entry);
462 break;
463 }
464 }
465 }
466
467 if (token != null) {
468 GuiTricks.navigateToToken(reader, token, m_selectionHighlightPainter);
469 } else {
470 // couldn't find anything =(
471 System.out.println("Unable to find declaration in source for " + classEntry);
472 }
473
474 } 411 }
475 }.start(); 412 });
413
414 updateMatchButton();
476 } 415 }
477 416
478 private void updateMatchButton() { 417 private void updateMatchButton() {
@@ -480,7 +419,7 @@ public class ClassMatchingGui {
480 ClassEntry obfSource = m_sourceDeobfuscator.obfuscateEntry(m_sourceClass); 419 ClassEntry obfSource = m_sourceDeobfuscator.obfuscateEntry(m_sourceClass);
481 ClassEntry obfDest = m_destDeobfuscator.obfuscateEntry(m_destClass); 420 ClassEntry obfDest = m_destDeobfuscator.obfuscateEntry(m_destClass);
482 421
483 BiMap<ClassEntry,ClassEntry> uniqueMatches = m_matches.getUniqueMatches(); 422 BiMap<ClassEntry,ClassEntry> uniqueMatches = m_classMatches.getUniqueMatches();
484 boolean twoSelected = m_sourceClass != null && m_destClass != null; 423 boolean twoSelected = m_sourceClass != null && m_destClass != null;
485 boolean isMatched = uniqueMatches.containsKey(obfSource) && uniqueMatches.containsValue(obfDest); 424 boolean isMatched = uniqueMatches.containsKey(obfSource) && uniqueMatches.containsValue(obfDest);
486 boolean canMatch = !uniqueMatches.containsKey(obfSource) && ! uniqueMatches.containsValue(obfDest); 425 boolean canMatch = !uniqueMatches.containsKey(obfSource) && ! uniqueMatches.containsValue(obfDest);
@@ -529,11 +468,11 @@ public class ClassMatchingGui {
529 ClassEntry obfDest = m_destDeobfuscator.obfuscateEntry(m_destClass); 468 ClassEntry obfDest = m_destDeobfuscator.obfuscateEntry(m_destClass);
530 469
531 // remove the classes from their match 470 // remove the classes from their match
532 m_matches.removeSource(obfSource); 471 m_classMatches.removeSource(obfSource);
533 m_matches.removeDest(obfDest); 472 m_classMatches.removeDest(obfDest);
534 473
535 // add them as matched classes 474 // add them as matched classes
536 m_matches.add(new ClassMatch(obfSource, obfDest)); 475 m_classMatches.add(new ClassMatch(obfSource, obfDest));
537 476
538 ClassEntry nextClass = null; 477 ClassEntry nextClass = null;
539 if (m_advanceCheck.isSelected()) { 478 if (m_advanceCheck.isSelected()) {
@@ -554,8 +493,8 @@ public class ClassMatchingGui {
554 ClassEntry obfSource = m_sourceDeobfuscator.obfuscateEntry(m_sourceClass); 493 ClassEntry obfSource = m_sourceDeobfuscator.obfuscateEntry(m_sourceClass);
555 494
556 // remove the source to break the match, then add the source back as unmatched 495 // remove the source to break the match, then add the source back as unmatched
557 m_matches.removeSource(obfSource); 496 m_classMatches.removeSource(obfSource);
558 m_matches.add(new ClassMatch(obfSource, null)); 497 m_classMatches.add(new ClassMatch(obfSource, null));
559 498
560 save(); 499 save();
561 updateMatches(); 500 updateMatches();
@@ -577,7 +516,7 @@ public class ClassMatchingGui {
577 516
578 private void save() { 517 private void save() {
579 if (m_saveListener != null) { 518 if (m_saveListener != null) {
580 m_saveListener.save(m_matches); 519 m_saveListener.save(m_classMatches);
581 } 520 }
582 } 521 }
583 522
@@ -589,15 +528,15 @@ public class ClassMatchingGui {
589 ClassMatching matching = MappingsConverter.computeMatching( 528 ClassMatching matching = MappingsConverter.computeMatching(
590 m_sourceDeobfuscator.getJar(), m_sourceDeobfuscator.getJarIndex(), 529 m_sourceDeobfuscator.getJar(), m_sourceDeobfuscator.getJarIndex(),
591 m_destDeobfuscator.getJar(), m_destDeobfuscator.getJarIndex(), 530 m_destDeobfuscator.getJar(), m_destDeobfuscator.getJarIndex(),
592 m_matches.getUniqueMatches() 531 m_classMatches.getUniqueMatches()
593 ); 532 );
594 Matches newMatches = new Matches(matching.matches()); 533 ClassMatches newMatches = new ClassMatches(matching.matches());
595 System.out.println(String.format("Automatch found %d new matches", 534 System.out.println(String.format("Automatch found %d new matches",
596 newMatches.getUniqueMatches().size() - m_matches.getUniqueMatches().size() 535 newMatches.getUniqueMatches().size() - m_classMatches.getUniqueMatches().size()
597 )); 536 ));
598 537
599 // update the current matches 538 // update the current matches
600 m_matches = newMatches; 539 m_classMatches = newMatches;
601 save(); 540 save();
602 updateMatches(); 541 updateMatches();
603 } 542 }
diff --git a/src/cuchaz/enigma/gui/CodeReader.java b/src/cuchaz/enigma/gui/CodeReader.java
new file mode 100644
index 0000000..05feb59
--- /dev/null
+++ b/src/cuchaz/enigma/gui/CodeReader.java
@@ -0,0 +1,164 @@
1package cuchaz.enigma.gui;
2
3import java.awt.Rectangle;
4import java.awt.event.ActionEvent;
5import java.awt.event.ActionListener;
6
7import javax.swing.JEditorPane;
8import javax.swing.SwingUtilities;
9import javax.swing.Timer;
10import javax.swing.text.BadLocationException;
11import javax.swing.text.Highlighter.HighlightPainter;
12
13import com.strobel.decompiler.languages.java.ast.CompilationUnit;
14
15import cuchaz.enigma.Deobfuscator;
16import cuchaz.enigma.analysis.SourceIndex;
17import cuchaz.enigma.analysis.Token;
18import cuchaz.enigma.mapping.ClassEntry;
19import cuchaz.enigma.mapping.Entry;
20import de.sciss.syntaxpane.DefaultSyntaxKit;
21
22
23public class CodeReader extends JEditorPane {
24
25 private static final long serialVersionUID = 3673180950485748810L;
26
27 private static final Object m_lock = new Object();
28
29 private SelectionHighlightPainter m_highlightPainter;
30 private SourceIndex m_sourceIndex;
31
32 public CodeReader() {
33
34 setEditable(false);
35 setContentType("text/java");
36
37 // turn off token highlighting (it's wrong most of the time anyway...)
38 DefaultSyntaxKit kit = (DefaultSyntaxKit)getEditorKit();
39 kit.toggleComponent(this, "de.sciss.syntaxpane.components.TokenMarker");
40
41 m_highlightPainter = new SelectionHighlightPainter();
42 m_sourceIndex = null;
43 }
44
45 public void setCode(String code) {
46 // sadly, the java lexer is not thread safe, so we have to serialize all these calls
47 synchronized (m_lock) {
48 setText(code);
49 }
50 }
51
52 public void decompileClass(ClassEntry classEntry, Deobfuscator deobfuscator) {
53 decompileClass(classEntry, deobfuscator, null);
54 }
55
56 public void decompileClass(final ClassEntry classEntry, final Deobfuscator deobfuscator, final Runnable callback) {
57
58 if (classEntry == null) {
59 setCode(null);
60 return;
61 }
62
63 setCode("(decompiling...)");
64
65 // run decompilation in a separate thread to keep ui responsive
66 new Thread() {
67 @Override
68 public void run() {
69
70 // get the outermost class
71 ClassEntry outermostClassEntry = classEntry;
72 while (outermostClassEntry.isInnerClass()) {
73 outermostClassEntry = outermostClassEntry.getOuterClassEntry();
74 }
75
76 // decompile it
77 CompilationUnit sourceTree = deobfuscator.getSourceTree(outermostClassEntry.getName());
78 String source = deobfuscator.getSource(sourceTree);
79 setCode(source);
80 m_sourceIndex = deobfuscator.getSourceIndex(sourceTree, source);
81
82 if (callback != null) {
83 callback.run();
84 }
85 }
86 }.start();
87 }
88
89 public void navigateToClassDeclaration(ClassEntry classEntry) {
90
91 // navigate to the class declaration
92 Token token = m_sourceIndex.getDeclarationToken(classEntry);
93 if (token == null) {
94 // couldn't find the class declaration token, might be an anonymous class
95 // look for any declaration in that class instead
96 for (Entry entry : m_sourceIndex.declarations()) {
97 if (entry.getClassEntry().equals(classEntry)) {
98 token = m_sourceIndex.getDeclarationToken(entry);
99 break;
100 }
101 }
102 }
103
104 if (token != null) {
105 navigateToToken(token);
106 } else {
107 // couldn't find anything =(
108 System.out.println("Unable to find declaration in source for " + classEntry);
109 }
110 }
111
112 public void navigateToToken(final Token token) {
113 navigateToToken(this, token, m_highlightPainter);
114 }
115
116 // HACKHACK: someday we can update the main GUI to use this code reader
117 public static void navigateToToken(final JEditorPane editor, final Token token, final HighlightPainter highlightPainter) {
118
119 // set the caret position to the token
120 editor.setCaretPosition(token.start);
121 editor.grabFocus();
122
123 try {
124 // make sure the token is visible in the scroll window
125 Rectangle start = editor.modelToView(token.start);
126 Rectangle end = editor.modelToView(token.end);
127 final Rectangle show = start.union(end);
128 show.grow(start.width * 10, start.height * 6);
129 SwingUtilities.invokeLater(new Runnable() {
130 @Override
131 public void run() {
132 editor.scrollRectToVisible(show);
133 }
134 });
135 } catch (BadLocationException ex) {
136 throw new Error(ex);
137 }
138
139 // highlight the token momentarily
140 final Timer timer = new Timer(200, new ActionListener() {
141 private int m_counter = 0;
142 private Object m_highlight = null;
143
144 @Override
145 public void actionPerformed(ActionEvent event) {
146 if (m_counter % 2 == 0) {
147 try {
148 m_highlight = editor.getHighlighter().addHighlight(token.start, token.end, highlightPainter);
149 } catch (BadLocationException ex) {
150 // don't care
151 }
152 } else if (m_highlight != null) {
153 editor.getHighlighter().removeHighlight(m_highlight);
154 }
155
156 if (m_counter++ > 6) {
157 Timer timer = (Timer)event.getSource();
158 timer.stop();
159 }
160 }
161 });
162 timer.start();
163 }
164}
diff --git a/src/cuchaz/enigma/gui/FieldMatchingGui.java b/src/cuchaz/enigma/gui/FieldMatchingGui.java
new file mode 100644
index 0000000..de9ba14
--- /dev/null
+++ b/src/cuchaz/enigma/gui/FieldMatchingGui.java
@@ -0,0 +1,131 @@
1package cuchaz.enigma.gui;
2
3import java.awt.BorderLayout;
4import java.awt.Container;
5import java.awt.Dimension;
6import java.awt.FlowLayout;
7import java.util.Map;
8
9import javax.swing.BoxLayout;
10import javax.swing.JFrame;
11import javax.swing.JLabel;
12import javax.swing.JPanel;
13import javax.swing.JScrollPane;
14import javax.swing.JSplitPane;
15import javax.swing.WindowConstants;
16
17import cuchaz.enigma.Constants;
18import cuchaz.enigma.Deobfuscator;
19import cuchaz.enigma.convert.ClassMatches;
20import cuchaz.enigma.convert.FieldMatches;
21import cuchaz.enigma.gui.ClassSelector.ClassSelectionListener;
22import cuchaz.enigma.mapping.ClassEntry;
23import cuchaz.enigma.mapping.FieldEntry;
24import cuchaz.enigma.mapping.FieldMapping;
25import de.sciss.syntaxpane.DefaultSyntaxKit;
26
27
28public class FieldMatchingGui {
29
30 public static interface SaveListener {
31 public void save(FieldMatches matches);
32 }
33
34 // controls
35 private JFrame m_frame;
36 private ClassSelector m_sourceClasses;
37 private CodeReader m_sourceReader;
38 private CodeReader m_destReader;
39
40 private ClassMatches m_classMatches;
41 private FieldMatches m_fieldMatches;
42 private Map<FieldEntry,FieldMapping> m_droppedFieldMappings;
43 private Deobfuscator m_sourceDeobfuscator;
44 private Deobfuscator m_destDeobfuscator;
45 private SaveListener m_saveListener;
46
47 public FieldMatchingGui(ClassMatches classMatches, FieldMatches fieldMatches, Map<FieldEntry,FieldMapping> droppedFieldMappings, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) {
48
49 m_classMatches = classMatches;
50 m_fieldMatches = fieldMatches;
51 m_droppedFieldMappings = droppedFieldMappings;
52 m_sourceDeobfuscator = sourceDeobfuscator;
53 m_destDeobfuscator = destDeobfuscator;
54
55 // init frame
56 m_frame = new JFrame(Constants.Name + " - Field Matcher");
57 final Container pane = m_frame.getContentPane();
58 pane.setLayout(new BorderLayout());
59
60 // init classes side
61 JPanel classesPanel = new JPanel();
62 classesPanel.setLayout(new BoxLayout(classesPanel, BoxLayout.PAGE_AXIS));
63 classesPanel.setPreferredSize(new Dimension(200, 0));
64 pane.add(classesPanel, BorderLayout.WEST);
65 classesPanel.add(new JLabel("Classes"));
66
67 m_sourceClasses = new ClassSelector(ClassSelector.DeobfuscatedClassEntryComparator);
68 m_sourceClasses.setListener(new ClassSelectionListener() {
69 @Override
70 public void onSelectClass(ClassEntry classEntry) {
71 setSourceClass(classEntry);
72 }
73 });
74 JScrollPane sourceScroller = new JScrollPane(m_sourceClasses);
75 classesPanel.add(sourceScroller);
76
77 // init fields side
78 JPanel fieldsPanel = new JPanel();
79 fieldsPanel.setLayout(new BoxLayout(fieldsPanel, BoxLayout.PAGE_AXIS));
80 fieldsPanel.setPreferredSize(new Dimension(200, 0));
81 pane.add(fieldsPanel, BorderLayout.WEST);
82 fieldsPanel.add(new JLabel("Destination Fields"));
83
84 // init readers
85 DefaultSyntaxKit.initKit();
86 m_sourceReader = new CodeReader();
87 m_destReader = new CodeReader();
88
89 // init all the splits
90 JSplitPane splitLeft = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, classesPanel, new JScrollPane(m_sourceReader));
91 splitLeft.setResizeWeight(0); // let the right side take all the slack
92 JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, new JScrollPane(m_destReader), fieldsPanel);
93 splitRight.setResizeWeight(1); // let the left side take all the slack
94 JSplitPane splitCenter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, splitLeft, splitRight);
95 splitCenter.setResizeWeight(0.5); // resize 50:50
96 pane.add(splitCenter, BorderLayout.CENTER);
97 splitCenter.resetToPreferredSizes();
98
99 // init bottom panel
100 JPanel bottomPanel = new JPanel();
101 bottomPanel.setLayout(new FlowLayout());
102
103 // show the frame
104 pane.doLayout();
105 m_frame.setSize(1024, 576);
106 m_frame.setMinimumSize(new Dimension(640, 480));
107 m_frame.setVisible(true);
108 m_frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
109
110 // init state
111 m_saveListener = null;
112 m_fieldMatches.addUnmatchedSourceFields(droppedFieldMappings.keySet());
113 m_sourceClasses.setClasses(m_fieldMatches.getSourceClassesWithUnmatchedFields());
114 }
115
116 public void setSaveListener(SaveListener val) {
117 m_saveListener = val;
118 }
119
120 protected void setSourceClass(ClassEntry obfSourceClass) {
121
122 // get the matched dest class
123 final ClassEntry obfDestClass = m_classMatches.getUniqueMatches().get(obfSourceClass);
124 if (obfDestClass == null) {
125 throw new Error("No matching dest class for source class: " + obfSourceClass);
126 }
127
128 m_sourceReader.decompileClass(obfSourceClass, m_sourceDeobfuscator);
129 m_destReader.decompileClass(obfDestClass, m_destDeobfuscator);
130 }
131}
diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java
index 38a6ee9..ea05d25 100644
--- a/src/cuchaz/enigma/gui/Gui.java
+++ b/src/cuchaz/enigma/gui/Gui.java
@@ -737,7 +737,7 @@ public class Gui {
737 if (token == null) { 737 if (token == null) {
738 throw new IllegalArgumentException("Token cannot be null!"); 738 throw new IllegalArgumentException("Token cannot be null!");
739 } 739 }
740 GuiTricks.navigateToToken(m_editor, token, m_selectionHighlightPainter); 740 CodeReader.navigateToToken(m_editor, token, m_selectionHighlightPainter);
741 redraw(); 741 redraw();
742 } 742 }
743 743
diff --git a/src/cuchaz/enigma/gui/GuiTricks.java b/src/cuchaz/enigma/gui/GuiTricks.java
index 5a3a01d..df9e221 100644
--- a/src/cuchaz/enigma/gui/GuiTricks.java
+++ b/src/cuchaz/enigma/gui/GuiTricks.java
@@ -11,21 +11,11 @@
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;
17import java.awt.event.MouseEvent; 14import java.awt.event.MouseEvent;
18 15
19import javax.swing.JComponent; 16import javax.swing.JComponent;
20import javax.swing.JEditorPane;
21import javax.swing.JLabel; 17import javax.swing.JLabel;
22import javax.swing.SwingUtilities;
23import javax.swing.Timer;
24import javax.swing.ToolTipManager; 18import javax.swing.ToolTipManager;
25import javax.swing.text.BadLocationException;
26import javax.swing.text.Highlighter.HighlightPainter;
27
28import cuchaz.enigma.analysis.Token;
29 19
30public class GuiTricks { 20public class GuiTricks {
31 21
@@ -43,52 +33,4 @@ public class GuiTricks {
43 manager.mouseMoved(new MouseEvent(component, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, 0, 0, 0, false)); 33 manager.mouseMoved(new MouseEvent(component, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, 0, 0, 0, false));
44 manager.setInitialDelay(oldDelay); 34 manager.setInitialDelay(oldDelay);
45 } 35 }
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 }
94} 36}