summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/gui/GuiController.java
diff options
context:
space:
mode:
authorGravatar jeff2015-02-08 21:29:25 -0500
committerGravatar jeff2015-02-08 21:29:25 -0500
commited9b5cdfc648e86fd463bfa8d86b94c41671e14c (patch)
tree2619bbc7e04dfa3b82f8dfd3b1d31f529766cd4b /src/cuchaz/enigma/gui/GuiController.java
downloadenigma-fork-ed9b5cdfc648e86fd463bfa8d86b94c41671e14c.tar.gz
enigma-fork-ed9b5cdfc648e86fd463bfa8d86b94c41671e14c.tar.xz
enigma-fork-ed9b5cdfc648e86fd463bfa8d86b94c41671e14c.zip
switch all classes to new signature/type system
Diffstat (limited to 'src/cuchaz/enigma/gui/GuiController.java')
-rw-r--r--src/cuchaz/enigma/gui/GuiController.java355
1 files changed, 355 insertions, 0 deletions
diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java
new file mode 100644
index 0000000..61fea9c
--- /dev/null
+++ b/src/cuchaz/enigma/gui/GuiController.java
@@ -0,0 +1,355 @@
1/*******************************************************************************
2 * Copyright (c) 2014 Jeff Martin.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the GNU Public License v3.0
5 * which accompanies this distribution, and is available at
6 * http://www.gnu.org/licenses/gpl.html
7 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.gui;
12
13import java.io.File;
14import java.io.FileReader;
15import java.io.FileWriter;
16import java.io.IOException;
17import java.util.Collection;
18import java.util.Deque;
19import java.util.List;
20import java.util.jar.JarFile;
21
22import com.google.common.collect.Lists;
23import com.google.common.collect.Queues;
24import com.strobel.decompiler.languages.java.ast.CompilationUnit;
25
26import cuchaz.enigma.Deobfuscator;
27import cuchaz.enigma.Deobfuscator.ProgressListener;
28import cuchaz.enigma.analysis.BehaviorReferenceTreeNode;
29import cuchaz.enigma.analysis.ClassImplementationsTreeNode;
30import cuchaz.enigma.analysis.ClassInheritanceTreeNode;
31import cuchaz.enigma.analysis.EntryReference;
32import cuchaz.enigma.analysis.FieldReferenceTreeNode;
33import cuchaz.enigma.analysis.MethodImplementationsTreeNode;
34import cuchaz.enigma.analysis.MethodInheritanceTreeNode;
35import cuchaz.enigma.analysis.SourceIndex;
36import cuchaz.enigma.analysis.Token;
37import cuchaz.enigma.gui.ProgressDialog.ProgressRunnable;
38import cuchaz.enigma.mapping.BehaviorEntry;
39import cuchaz.enigma.mapping.ClassEntry;
40import cuchaz.enigma.mapping.Entry;
41import cuchaz.enigma.mapping.FieldEntry;
42import cuchaz.enigma.mapping.MappingParseException;
43import cuchaz.enigma.mapping.MappingsReader;
44import cuchaz.enigma.mapping.MappingsWriter;
45import cuchaz.enigma.mapping.MethodEntry;
46import cuchaz.enigma.mapping.TranslationDirection;
47
48public class GuiController {
49
50 private Deobfuscator m_deobfuscator;
51 private Gui m_gui;
52 private SourceIndex m_index;
53 private ClassEntry m_currentObfClass;
54 private boolean m_isDirty;
55 private Deque<EntryReference<Entry,Entry>> m_referenceStack;
56
57 public GuiController(Gui gui) {
58 m_gui = gui;
59 m_deobfuscator = null;
60 m_index = null;
61 m_currentObfClass = null;
62 m_isDirty = false;
63 m_referenceStack = Queues.newArrayDeque();
64 }
65
66 public boolean isDirty() {
67 return m_isDirty;
68 }
69
70 public void openJar(final JarFile jar) throws IOException {
71 m_gui.onStartOpenJar();
72 m_deobfuscator = new Deobfuscator(jar);
73 m_gui.onFinishOpenJar(m_deobfuscator.getJarName());
74 refreshClasses();
75 }
76
77 public void closeJar() {
78 m_deobfuscator = null;
79 m_gui.onCloseJar();
80 }
81
82 public void openMappings(File file) throws IOException, MappingParseException {
83 FileReader in = new FileReader(file);
84 m_deobfuscator.setMappings(new MappingsReader().read(in));
85 in.close();
86 m_isDirty = false;
87 m_gui.setMappingsFile(file);
88 refreshClasses();
89 refreshCurrentClass();
90 }
91
92 public void saveMappings(File file) throws IOException {
93 FileWriter out = new FileWriter(file);
94 new MappingsWriter().write(out, m_deobfuscator.getMappings());
95 out.close();
96 m_isDirty = false;
97 }
98
99 public void closeMappings() {
100 m_deobfuscator.setMappings(null);
101 m_gui.setMappingsFile(null);
102 refreshClasses();
103 refreshCurrentClass();
104 }
105
106 public void exportSource(final File dirOut) {
107 ProgressDialog.runInThread(m_gui.getFrame(), new ProgressRunnable() {
108 @Override
109 public void run(ProgressListener progress) throws Exception {
110 m_deobfuscator.writeSources(dirOut, progress);
111 }
112 });
113 }
114
115 public void exportJar(final File fileOut) {
116 ProgressDialog.runInThread(m_gui.getFrame(), new ProgressRunnable() {
117 @Override
118 public void run(ProgressListener progress) {
119 m_deobfuscator.writeJar(fileOut, progress);
120 }
121 });
122 }
123
124 public Token getToken(int pos) {
125 if (m_index == null) {
126 return null;
127 }
128 return m_index.getReferenceToken(pos);
129 }
130
131 public EntryReference<Entry,Entry> getDeobfReference(Token token) {
132 if (m_index == null) {
133 return null;
134 }
135 return m_index.getDeobfReference(token);
136 }
137
138 public ReadableToken getReadableToken(Token token) {
139 if (m_index == null) {
140 return null;
141 }
142 return new ReadableToken(
143 m_index.getLineNumber(token.start),
144 m_index.getColumnNumber(token.start),
145 m_index.getColumnNumber(token.end)
146 );
147 }
148
149 public boolean entryHasDeobfuscatedName(Entry deobfEntry) {
150 return m_deobfuscator.hasDeobfuscatedName(m_deobfuscator.obfuscateEntry(deobfEntry));
151 }
152
153 public boolean entryIsInJar(Entry deobfEntry) {
154 return m_deobfuscator.isObfuscatedIdentifier(m_deobfuscator.obfuscateEntry(deobfEntry));
155 }
156
157 public boolean referenceIsRenameable(EntryReference<Entry,Entry> deobfReference) {
158 return m_deobfuscator.isRenameable(m_deobfuscator.obfuscateReference(deobfReference));
159 }
160
161 public ClassInheritanceTreeNode getClassInheritance(ClassEntry deobfClassEntry) {
162 ClassEntry obfClassEntry = m_deobfuscator.obfuscateEntry(deobfClassEntry);
163 ClassInheritanceTreeNode rootNode = m_deobfuscator.getJarIndex().getClassInheritance(
164 m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating),
165 obfClassEntry
166 );
167 return ClassInheritanceTreeNode.findNode(rootNode, obfClassEntry);
168 }
169
170 public ClassImplementationsTreeNode getClassImplementations(ClassEntry deobfClassEntry) {
171 ClassEntry obfClassEntry = m_deobfuscator.obfuscateEntry(deobfClassEntry);
172 return m_deobfuscator.getJarIndex().getClassImplementations(
173 m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating),
174 obfClassEntry
175 );
176 }
177
178 public MethodInheritanceTreeNode getMethodInheritance(MethodEntry deobfMethodEntry) {
179 MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry(deobfMethodEntry);
180 MethodInheritanceTreeNode rootNode = m_deobfuscator.getJarIndex().getMethodInheritance(
181 m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating),
182 obfMethodEntry
183 );
184 return MethodInheritanceTreeNode.findNode(rootNode, obfMethodEntry);
185 }
186
187 public MethodImplementationsTreeNode getMethodImplementations(MethodEntry deobfMethodEntry) {
188 MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry(deobfMethodEntry);
189 MethodImplementationsTreeNode rootNode = m_deobfuscator.getJarIndex().getMethodImplementations(
190 m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating),
191 obfMethodEntry
192 );
193 if (rootNode == null) {
194 return null;
195 }
196 return MethodImplementationsTreeNode.findNode(rootNode, obfMethodEntry);
197 }
198
199 public FieldReferenceTreeNode getFieldReferences(FieldEntry deobfFieldEntry) {
200 FieldEntry obfFieldEntry = m_deobfuscator.obfuscateEntry(deobfFieldEntry);
201 FieldReferenceTreeNode rootNode = new FieldReferenceTreeNode(
202 m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating),
203 obfFieldEntry
204 );
205 rootNode.load(m_deobfuscator.getJarIndex(), true);
206 return rootNode;
207 }
208
209 public BehaviorReferenceTreeNode getMethodReferences(BehaviorEntry deobfBehaviorEntry) {
210 BehaviorEntry obfBehaviorEntry = m_deobfuscator.obfuscateEntry(deobfBehaviorEntry);
211 BehaviorReferenceTreeNode rootNode = new BehaviorReferenceTreeNode(
212 m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating),
213 obfBehaviorEntry
214 );
215 rootNode.load(m_deobfuscator.getJarIndex(), true);
216 return rootNode;
217 }
218
219 public void rename(EntryReference<Entry,Entry> deobfReference, String newName) {
220 EntryReference<Entry,Entry> obfReference = m_deobfuscator.obfuscateReference(deobfReference);
221 m_deobfuscator.rename(obfReference.getNameableEntry(), newName);
222 m_isDirty = true;
223 refreshClasses();
224 refreshCurrentClass(obfReference);
225 }
226
227 public void removeMapping(EntryReference<Entry,Entry> deobfReference) {
228 EntryReference<Entry,Entry> obfReference = m_deobfuscator.obfuscateReference(deobfReference);
229 m_deobfuscator.removeMapping(obfReference.getNameableEntry());
230 m_isDirty = true;
231 refreshClasses();
232 refreshCurrentClass(obfReference);
233 }
234
235 public void markAsDeobfuscated(EntryReference<Entry,Entry> deobfReference) {
236 EntryReference<Entry,Entry> obfReference = m_deobfuscator.obfuscateReference(deobfReference);
237 m_deobfuscator.markAsDeobfuscated(obfReference.getNameableEntry());
238 m_isDirty = true;
239 refreshClasses();
240 refreshCurrentClass(obfReference);
241 }
242
243 public void openDeclaration(Entry deobfEntry) {
244 if (deobfEntry == null) {
245 throw new IllegalArgumentException("Entry cannot be null!");
246 }
247 openReference(new EntryReference<Entry,Entry>(deobfEntry, deobfEntry.getName()));
248 }
249
250 public void openReference(EntryReference<Entry,Entry> deobfReference) {
251 if (deobfReference == null) {
252 throw new IllegalArgumentException("Reference cannot be null!");
253 }
254
255 // get the reference target class
256 EntryReference<Entry,Entry> obfReference = m_deobfuscator.obfuscateReference(deobfReference);
257 ClassEntry obfClassEntry = obfReference.getLocationClassEntry().getOuterClassEntry();
258 if (!m_deobfuscator.isObfuscatedIdentifier(obfClassEntry)) {
259 throw new IllegalArgumentException("Obfuscated class " + obfClassEntry + " was not found in the jar!");
260 }
261 if (m_currentObfClass == null || !m_currentObfClass.equals(obfClassEntry)) {
262 // deobfuscate the class, then navigate to the reference
263 m_currentObfClass = obfClassEntry;
264 deobfuscate(m_currentObfClass, obfReference);
265 } else {
266 showReference(obfReference);
267 }
268 }
269
270 private void showReference(EntryReference<Entry,Entry> obfReference) {
271 EntryReference<Entry,Entry> deobfReference = m_deobfuscator.deobfuscateReference(obfReference);
272 Collection<Token> tokens = m_index.getReferenceTokens(deobfReference);
273 if (tokens.isEmpty()) {
274 // DEBUG
275 System.err.println(String.format("WARNING: no tokens found for %s in %s", deobfReference, m_currentObfClass));
276 } else {
277 m_gui.showTokens(tokens);
278 }
279 }
280
281 public void savePreviousReference(EntryReference<Entry,Entry> deobfReference) {
282 m_referenceStack.push(m_deobfuscator.obfuscateReference(deobfReference));
283 }
284
285 public void openPreviousReference() {
286 if (hasPreviousLocation()) {
287 openReference(m_deobfuscator.deobfuscateReference(m_referenceStack.pop()));
288 }
289 }
290
291 public boolean hasPreviousLocation() {
292 return !m_referenceStack.isEmpty();
293 }
294
295 private void refreshClasses() {
296 List<ClassEntry> obfClasses = Lists.newArrayList();
297 List<ClassEntry> deobfClasses = Lists.newArrayList();
298 m_deobfuscator.getSeparatedClasses(obfClasses, deobfClasses);
299 m_gui.setObfClasses(obfClasses);
300 m_gui.setDeobfClasses(deobfClasses);
301 }
302
303 private void refreshCurrentClass() {
304 refreshCurrentClass(null);
305 }
306
307 private void refreshCurrentClass(EntryReference<Entry,Entry> obfReference) {
308 if (m_currentObfClass != null) {
309 deobfuscate(m_currentObfClass, obfReference);
310 }
311 }
312
313 private void deobfuscate(final ClassEntry classEntry, final EntryReference<Entry,Entry> obfReference) {
314
315 m_gui.setSource("(deobfuscating...)");
316
317 // run the deobfuscator in a separate thread so we don't block the GUI event queue
318 new Thread() {
319 @Override
320 public void run() {
321 // decompile,deobfuscate the bytecode
322 CompilationUnit sourceTree = m_deobfuscator.getSourceTree(classEntry.getClassName());
323 if (sourceTree == null) {
324 // decompilation of this class is not supported
325 m_gui.setSource("Unable to find class: " + classEntry);
326 return;
327 }
328 String source = m_deobfuscator.getSource(sourceTree);
329 m_index = m_deobfuscator.getSourceIndex(sourceTree, source);
330 m_gui.setSource(m_index.getSource());
331 if (obfReference != null) {
332 showReference(obfReference);
333 }
334
335 // set the highlighted tokens
336 List<Token> obfuscatedTokens = Lists.newArrayList();
337 List<Token> deobfuscatedTokens = Lists.newArrayList();
338 List<Token> otherTokens = Lists.newArrayList();
339 for (Token token : m_index.referenceTokens()) {
340 EntryReference<Entry,Entry> reference = m_index.getDeobfReference(token);
341 if (referenceIsRenameable(reference)) {
342 if (entryHasDeobfuscatedName(reference.getNameableEntry())) {
343 deobfuscatedTokens.add(token);
344 } else {
345 obfuscatedTokens.add(token);
346 }
347 } else {
348 otherTokens.add(token);
349 }
350 }
351 m_gui.setHighlightedTokens(obfuscatedTokens, deobfuscatedTokens, otherTokens);
352 }
353 }.start();
354 }
355}