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