summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/gui/MatchingGui.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/cuchaz/enigma/gui/MatchingGui.java')
-rw-r--r--src/cuchaz/enigma/gui/MatchingGui.java208
1 files changed, 146 insertions, 62 deletions
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}