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