summaryrefslogtreecommitdiff
path: root/src/main/java/cuchaz/enigma/gui/GuiController.java
diff options
context:
space:
mode:
authorGravatar Gegy2019-01-30 21:05:32 +0200
committerGravatar GitHub2019-01-30 21:05:32 +0200
commitba7a354efae7d49833c887cf147ac940c975a1fa (patch)
tree02e14fda81dd5984e24f2df392c57c6e829fc875 /src/main/java/cuchaz/enigma/gui/GuiController.java
parentRewrite the Jenkinsfile to use the new declarative pipeline syntax, lets hope... (diff)
downloadenigma-fork-ba7a354efae7d49833c887cf147ac940c975a1fa.tar.gz
enigma-fork-ba7a354efae7d49833c887cf147ac940c975a1fa.tar.xz
enigma-fork-ba7a354efae7d49833c887cf147ac940c975a1fa.zip
Remap sources (#106)
* Source remapping beginnings * Fix navigation to remapped classes * Translate identifier info reference * Remap local variables with default names in source * Caching translator * Fix lack of highlighting for first opened class * Fix unicode variable names * Unicode checker shouldn't be checking just alphanumeric * Fix package tree being built from obf names * Don't index `this` as method call for method::reference * Apply proposed names * Fix source export issues * Replace unicode var names at bytecode level uniquely * Drop imports from editor source * Class selector fixes * Delta keep track of base mappings to enable lookup of old names * Optimize source remapping by remapping source with a StringBuffer instead of copying * Bump version
Diffstat (limited to 'src/main/java/cuchaz/enigma/gui/GuiController.java')
-rw-r--r--src/main/java/cuchaz/enigma/gui/GuiController.java305
1 files changed, 127 insertions, 178 deletions
diff --git a/src/main/java/cuchaz/enigma/gui/GuiController.java b/src/main/java/cuchaz/enigma/gui/GuiController.java
index fd9e7f0..03e1768 100644
--- a/src/main/java/cuchaz/enigma/gui/GuiController.java
+++ b/src/main/java/cuchaz/enigma/gui/GuiController.java
@@ -11,13 +11,13 @@
11 11
12package cuchaz.enigma.gui; 12package cuchaz.enigma.gui;
13 13
14import com.google.common.collect.ImmutableMap;
15import com.google.common.collect.Lists; 14import com.google.common.collect.Lists;
16import com.google.common.collect.Queues; 15import com.google.common.collect.Queues;
16import com.google.common.util.concurrent.ThreadFactoryBuilder;
17import com.strobel.decompiler.languages.java.ast.CompilationUnit; 17import com.strobel.decompiler.languages.java.ast.CompilationUnit;
18import cuchaz.enigma.Deobfuscator; 18import cuchaz.enigma.Deobfuscator;
19import cuchaz.enigma.SourceProvider;
19import cuchaz.enigma.analysis.*; 20import cuchaz.enigma.analysis.*;
20import cuchaz.enigma.api.EnigmaPlugin;
21import cuchaz.enigma.config.Config; 21import cuchaz.enigma.config.Config;
22import cuchaz.enigma.gui.dialog.ProgressDialog; 22import cuchaz.enigma.gui.dialog.ProgressDialog;
23import cuchaz.enigma.throwables.MappingParseException; 23import cuchaz.enigma.throwables.MappingParseException;
@@ -36,16 +36,20 @@ import java.awt.event.ItemEvent;
36import java.io.File; 36import java.io.File;
37import java.io.IOException; 37import java.io.IOException;
38import java.nio.file.Path; 38import java.nio.file.Path;
39import java.util.*; 39import java.util.Collection;
40import java.util.Deque;
41import java.util.List;
42import java.util.concurrent.ExecutorService;
43import java.util.concurrent.Executors;
40import java.util.jar.JarFile; 44import java.util.jar.JarFile;
41import java.util.stream.Collectors; 45import java.util.stream.Collectors;
42 46
43public class GuiController { 47public class GuiController {
48 private static final ExecutorService DECOMPILER_SERVICE = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setDaemon(true).setNameFormat("decompiler-thread").build());
44 49
45 private Deobfuscator deobfuscator; 50 private Deobfuscator deobfuscator;
46 private Gui gui; 51 private Gui gui;
47 private SourceIndex index; 52 private DecompiledClassSource currentSource;
48 private ClassEntry currentObfClass;
49 private Deque<EntryReference<Entry<?>, Entry<?>>> referenceStack; 53 private Deque<EntryReference<Entry<?>, Entry<?>>> referenceStack;
50 54
51 private Path loadedMappingPath; 55 private Path loadedMappingPath;
@@ -54,8 +58,7 @@ public class GuiController {
54 public GuiController(Gui gui) { 58 public GuiController(Gui gui) {
55 this.gui = gui; 59 this.gui = gui;
56 this.deobfuscator = null; 60 this.deobfuscator = null;
57 this.index = null; 61 this.currentSource = null;
58 this.currentObfClass = null;
59 this.referenceStack = Queues.newArrayDeque(); 62 this.referenceStack = Queues.newArrayDeque();
60 } 63 }
61 64
@@ -93,7 +96,7 @@ public class GuiController {
93 public void saveMappings(MappingFormat format, Path path) { 96 public void saveMappings(MappingFormat format, Path path) {
94 EntryRemapper mapper = deobfuscator.getMapper(); 97 EntryRemapper mapper = deobfuscator.getMapper();
95 98
96 MappingDelta delta = mapper.takeMappingDelta(); 99 MappingDelta<EntryMapping> delta = mapper.takeMappingDelta();
97 boolean saveAll = !path.equals(loadedMappingPath); 100 boolean saveAll = !path.equals(loadedMappingPath);
98 101
99 ProgressDialog.runInThread(this.gui.getFrame(), progress -> { 102 ProgressDialog.runInThread(this.gui.getFrame(), progress -> {
@@ -116,189 +119,167 @@ public class GuiController {
116 } 119 }
117 120
118 public void exportSource(final File dirOut) { 121 public void exportSource(final File dirOut) {
119 ProgressDialog.runInThread(this.gui.getFrame(), progress -> this.deobfuscator.writeSources(dirOut, progress)); 122 ProgressDialog.runInThread(this.gui.getFrame(), progress -> this.deobfuscator.writeSources(dirOut.toPath(), progress));
120 } 123 }
121 124
122 public void exportJar(final File fileOut) { 125 public void exportJar(final File fileOut) {
123 ProgressDialog.runInThread(this.gui.getFrame(), progress -> this.deobfuscator.writeJar(fileOut, progress)); 126 ProgressDialog.runInThread(this.gui.getFrame(), progress -> this.deobfuscator.writeTransformedJar(fileOut, progress));
124 } 127 }
125 128
126 public Token getToken(int pos) { 129 public Token getToken(int pos) {
127 if (this.index == null) { 130 if (this.currentSource == null) {
128 return null; 131 return null;
129 } 132 }
130 return this.index.getReferenceToken(pos); 133 return this.currentSource.getIndex().getReferenceToken(pos);
131 } 134 }
132 135
133 @Nullable 136 @Nullable
134 public EntryReference<Entry<?>, Entry<?>> getDeobfReference(Token token) { 137 public EntryReference<Entry<?>, Entry<?>> getReference(Token token) {
135 if (this.index == null) { 138 if (this.currentSource == null) {
136 return null; 139 return null;
137 } 140 }
138 return this.index.getDeobfReference(token); 141 return this.currentSource.getIndex().getReference(token);
139 } 142 }
140 143
141 public ReadableToken getReadableToken(Token token) { 144 public ReadableToken getReadableToken(Token token) {
142 if (this.index == null) { 145 if (this.currentSource == null) {
143 return null; 146 return null;
144 } 147 }
148 SourceIndex index = this.currentSource.getIndex();
145 return new ReadableToken( 149 return new ReadableToken(
146 this.index.getLineNumber(token.start), 150 index.getLineNumber(token.start),
147 this.index.getColumnNumber(token.start), 151 index.getColumnNumber(token.start),
148 this.index.getColumnNumber(token.end) 152 index.getColumnNumber(token.end)
149 ); 153 );
150 } 154 }
151 155
152 public boolean entryHasDeobfuscatedName(Entry<?> deobfEntry) { 156 public boolean entryIsInJar(Entry<?> entry) {
153 EntryResolver resolver = this.deobfuscator.getMapper().getDeobfResolver(); 157 if (entry == null) return false;
154 Entry<?> resolvedEntry = resolver.resolveFirstEntry(deobfEntry, ResolutionStrategy.RESOLVE_ROOT); 158 return this.deobfuscator.isRenamable(entry);
155 return this.deobfuscator.hasDeobfuscatedName(this.deobfuscator.getMapper().obfuscate(resolvedEntry));
156 } 159 }
157 160
158 public boolean entryIsInJar(Entry<?> deobfEntry) { 161 public ClassInheritanceTreeNode getClassInheritance(ClassEntry entry) {
159 if (deobfEntry == null) return false;
160 return this.deobfuscator.isObfuscatedIdentifier(this.deobfuscator.getMapper().obfuscate(deobfEntry));
161 }
162
163 public boolean referenceIsRenameable(EntryReference<Entry<?>, Entry<?>> deobfReference) {
164 if (deobfReference == null) return false;
165 return this.deobfuscator.isRenameable(this.deobfuscator.getMapper().obfuscate(deobfReference));
166 }
167
168 public ClassInheritanceTreeNode getClassInheritance(ClassEntry deobfClassEntry) {
169 ClassEntry obfClassEntry = this.deobfuscator.getMapper().obfuscate(deobfClassEntry);
170 Translator translator = this.deobfuscator.getMapper().getDeobfuscator(); 162 Translator translator = this.deobfuscator.getMapper().getDeobfuscator();
171 ClassInheritanceTreeNode rootNode = this.deobfuscator.getIndexTreeBuilder().buildClassInheritance(translator, obfClassEntry); 163 ClassInheritanceTreeNode rootNode = this.deobfuscator.getIndexTreeBuilder().buildClassInheritance(translator, entry);
172 return ClassInheritanceTreeNode.findNode(rootNode, obfClassEntry); 164 return ClassInheritanceTreeNode.findNode(rootNode, entry);
173 } 165 }
174 166
175 public ClassImplementationsTreeNode getClassImplementations(ClassEntry deobfClassEntry) { 167 public ClassImplementationsTreeNode getClassImplementations(ClassEntry entry) {
176 ClassEntry obfClassEntry = this.deobfuscator.getMapper().obfuscate(deobfClassEntry);
177 Translator translator = this.deobfuscator.getMapper().getDeobfuscator(); 168 Translator translator = this.deobfuscator.getMapper().getDeobfuscator();
178 return this.deobfuscator.getIndexTreeBuilder().buildClassImplementations(translator, obfClassEntry); 169 return this.deobfuscator.getIndexTreeBuilder().buildClassImplementations(translator, entry);
179 } 170 }
180 171
181 public MethodInheritanceTreeNode getMethodInheritance(MethodEntry deobfMethodEntry) { 172 public MethodInheritanceTreeNode getMethodInheritance(MethodEntry entry) {
182 MethodEntry obfMethodEntry = this.deobfuscator.getMapper().obfuscate(deobfMethodEntry);
183 Translator translator = this.deobfuscator.getMapper().getDeobfuscator(); 173 Translator translator = this.deobfuscator.getMapper().getDeobfuscator();
184 MethodInheritanceTreeNode rootNode = this.deobfuscator.getIndexTreeBuilder().buildMethodInheritance(translator, obfMethodEntry); 174 MethodInheritanceTreeNode rootNode = this.deobfuscator.getIndexTreeBuilder().buildMethodInheritance(translator, entry);
185 return MethodInheritanceTreeNode.findNode(rootNode, obfMethodEntry); 175 return MethodInheritanceTreeNode.findNode(rootNode, entry);
186 } 176 }
187 177
188 public MethodImplementationsTreeNode getMethodImplementations(MethodEntry deobfMethodEntry) { 178 public MethodImplementationsTreeNode getMethodImplementations(MethodEntry entry) {
189 MethodEntry obfMethodEntry = this.deobfuscator.getMapper().obfuscate(deobfMethodEntry);
190 Translator translator = this.deobfuscator.getMapper().getDeobfuscator(); 179 Translator translator = this.deobfuscator.getMapper().getDeobfuscator();
191 List<MethodImplementationsTreeNode> rootNodes = this.deobfuscator.getIndexTreeBuilder().buildMethodImplementations(translator, obfMethodEntry); 180 List<MethodImplementationsTreeNode> rootNodes = this.deobfuscator.getIndexTreeBuilder().buildMethodImplementations(translator, entry);
192 if (rootNodes.isEmpty()) { 181 if (rootNodes.isEmpty()) {
193 return null; 182 return null;
194 } 183 }
195 if (rootNodes.size() > 1) { 184 if (rootNodes.size() > 1) {
196 System.err.println("WARNING: Method " + deobfMethodEntry + " implements multiple interfaces. Only showing first one."); 185 System.err.println("WARNING: Method " + entry + " implements multiple interfaces. Only showing first one.");
197 } 186 }
198 return MethodImplementationsTreeNode.findNode(rootNodes.get(0), obfMethodEntry); 187 return MethodImplementationsTreeNode.findNode(rootNodes.get(0), entry);
199 } 188 }
200 189
201 public ClassReferenceTreeNode getClassReferences(ClassEntry deobfClassEntry) { 190 public ClassReferenceTreeNode getClassReferences(ClassEntry entry) {
202 ClassEntry obfClassEntry = this.deobfuscator.getMapper().obfuscate(deobfClassEntry);
203 Translator deobfuscator = this.deobfuscator.getMapper().getDeobfuscator(); 191 Translator deobfuscator = this.deobfuscator.getMapper().getDeobfuscator();
204 ClassReferenceTreeNode rootNode = new ClassReferenceTreeNode(deobfuscator, obfClassEntry); 192 ClassReferenceTreeNode rootNode = new ClassReferenceTreeNode(deobfuscator, entry);
205 rootNode.load(this.deobfuscator.getJarIndex(), true); 193 rootNode.load(this.deobfuscator.getJarIndex(), true);
206 return rootNode; 194 return rootNode;
207 } 195 }
208 196
209 public FieldReferenceTreeNode getFieldReferences(FieldEntry deobfFieldEntry) { 197 public FieldReferenceTreeNode getFieldReferences(FieldEntry entry) {
210 FieldEntry obfFieldEntry = this.deobfuscator.getMapper().obfuscate(deobfFieldEntry);
211 Translator translator = this.deobfuscator.getMapper().getDeobfuscator(); 198 Translator translator = this.deobfuscator.getMapper().getDeobfuscator();
212 FieldReferenceTreeNode rootNode = new FieldReferenceTreeNode(translator, obfFieldEntry); 199 FieldReferenceTreeNode rootNode = new FieldReferenceTreeNode(translator, entry);
213 rootNode.load(this.deobfuscator.getJarIndex(), true); 200 rootNode.load(this.deobfuscator.getJarIndex(), true);
214 return rootNode; 201 return rootNode;
215 } 202 }
216 203
217 public MethodReferenceTreeNode getMethodReferences(MethodEntry deobfMethodEntry, boolean recursive) { 204 public MethodReferenceTreeNode getMethodReferences(MethodEntry entry, boolean recursive) {
218 MethodEntry obfMethodEntry = this.deobfuscator.getMapper().obfuscate(deobfMethodEntry);
219 Translator translator = this.deobfuscator.getMapper().getDeobfuscator(); 205 Translator translator = this.deobfuscator.getMapper().getDeobfuscator();
220 MethodReferenceTreeNode rootNode = new MethodReferenceTreeNode(translator, obfMethodEntry); 206 MethodReferenceTreeNode rootNode = new MethodReferenceTreeNode(translator, entry);
221 rootNode.load(this.deobfuscator.getJarIndex(), true, recursive); 207 rootNode.load(this.deobfuscator.getJarIndex(), true, recursive);
222 return rootNode; 208 return rootNode;
223 } 209 }
224 210
225 public void rename(EntryReference<Entry<?>, Entry<?>> deobfReference, String newName, boolean refreshClassTree) { 211 public void rename(EntryReference<Entry<?>, Entry<?>> reference, String newName, boolean refreshClassTree) {
226 EntryReference<Entry<?>, Entry<?>> obfReference = this.deobfuscator.getMapper().obfuscate(deobfReference); 212 this.deobfuscator.rename(reference.getNameableEntry(), newName);
227 this.deobfuscator.rename(obfReference.getNameableEntry(), newName);
228
229 if (refreshClassTree && deobfReference.entry instanceof ClassEntry && !((ClassEntry) deobfReference.entry).isInnerClass())
230 this.gui.moveClassTree(deobfReference, newName);
231 refreshCurrentClass(obfReference);
232 213
214 if (refreshClassTree && reference.entry instanceof ClassEntry && !((ClassEntry) reference.entry).isInnerClass())
215 this.gui.moveClassTree(reference, newName);
216 refreshCurrentClass(reference);
233 } 217 }
234 218
235 public void removeMapping(EntryReference<Entry<?>, Entry<?>> deobfReference) { 219 public void removeMapping(EntryReference<Entry<?>, Entry<?>> reference) {
236 EntryReference<Entry<?>, Entry<?>> obfReference = this.deobfuscator.getMapper().obfuscate(deobfReference); 220 this.deobfuscator.removeMapping(reference.getNameableEntry());
237 this.deobfuscator.removeMapping(obfReference.getNameableEntry()); 221 if (reference.entry instanceof ClassEntry)
238 if (deobfReference.entry instanceof ClassEntry) 222 this.gui.moveClassTree(reference, false, true);
239 this.gui.moveClassTree(deobfReference, obfReference.entry.getName(), false, true); 223 refreshCurrentClass(reference);
240 refreshCurrentClass(obfReference);
241 } 224 }
242 225
243 public void markAsDeobfuscated(EntryReference<Entry<?>, Entry<?>> deobfReference) { 226 public void markAsDeobfuscated(EntryReference<Entry<?>, Entry<?>> reference) {
244 EntryReference<Entry<?>, Entry<?>> obfReference = this.deobfuscator.getMapper().obfuscate(deobfReference); 227 this.deobfuscator.markAsDeobfuscated(reference.getNameableEntry());
245 this.deobfuscator.markAsDeobfuscated(obfReference.getNameableEntry()); 228 if (reference.entry instanceof ClassEntry && !((ClassEntry) reference.entry).isInnerClass())
246 if (deobfReference.entry instanceof ClassEntry && !((ClassEntry) deobfReference.entry).isInnerClass()) 229 this.gui.moveClassTree(reference, true, false);
247 this.gui.moveClassTree(deobfReference, obfReference.entry.getName(), true, false); 230 refreshCurrentClass(reference);
248 refreshCurrentClass(obfReference);
249 } 231 }
250 232
251 public void openDeclaration(Entry<?> deobfEntry) { 233 public void openDeclaration(Entry<?> entry) {
252 if (deobfEntry == null) { 234 if (entry == null) {
253 throw new IllegalArgumentException("Entry cannot be null!"); 235 throw new IllegalArgumentException("Entry cannot be null!");
254 } 236 }
255 openReference(new EntryReference<>(deobfEntry, deobfEntry.getName())); 237 openReference(new EntryReference<>(entry, entry.getName()));
256 } 238 }
257 239
258 public void openReference(EntryReference<Entry<?>, Entry<?>> deobfReference) { 240 public void openReference(EntryReference<Entry<?>, Entry<?>> reference) {
259 if (deobfReference == null) { 241 if (reference == null) {
260 throw new IllegalArgumentException("Reference cannot be null!"); 242 throw new IllegalArgumentException("Reference cannot be null!");
261 } 243 }
262 244
263 // get the reference target class 245 // get the reference target class
264 EntryReference<Entry<?>, Entry<?>> obfReference = this.deobfuscator.getMapper().obfuscate(deobfReference); 246 ClassEntry classEntry = reference.getLocationClassEntry();
265 ClassEntry obfClassEntry = obfReference.getLocationClassEntry(); 247 if (!this.deobfuscator.isRenamable(classEntry)) {
266 if (!this.deobfuscator.isObfuscatedIdentifier(obfClassEntry)) { 248 throw new IllegalArgumentException("Obfuscated class " + classEntry + " was not found in the jar!");
267 throw new IllegalArgumentException("Obfuscated class " + obfClassEntry + " was not found in the jar!");
268 } 249 }
269 if (this.currentObfClass == null || !this.currentObfClass.equals(obfClassEntry)) { 250
251 if (this.currentSource == null || !this.currentSource.getEntry().equals(classEntry)) {
270 // deobfuscate the class, then navigate to the reference 252 // deobfuscate the class, then navigate to the reference
271 this.currentObfClass = obfClassEntry; 253 loadClass(classEntry, () -> showReference(reference));
272 deobfuscate(this.currentObfClass, obfReference);
273 } else { 254 } else {
274 showReference(obfReference); 255 showReference(reference);
275 } 256 }
276 } 257 }
277 258
278 private void showReference(EntryReference<Entry<?>, Entry<?>> obfReference) { 259 private void showReference(EntryReference<Entry<?>, Entry<?>> reference) {
279 EntryRemapper mapper = this.deobfuscator.getMapper(); 260 EntryRemapper mapper = this.deobfuscator.getMapper();
280 261
281 Collection<Token> tokens = mapper.getObfResolver().resolveReference(obfReference, ResolutionStrategy.RESOLVE_ROOT) 262 SourceIndex index = this.currentSource.getIndex();
263 Collection<Token> tokens = mapper.getObfResolver().resolveReference(reference, ResolutionStrategy.RESOLVE_ROOT)
282 .stream() 264 .stream()
283 .map(mapper::deobfuscate) 265 .flatMap(r -> index.getReferenceTokens(r).stream())
284 .flatMap(reference -> index.getReferenceTokens(reference).stream())
285 .collect(Collectors.toList()); 266 .collect(Collectors.toList());
286 267
287 if (tokens.isEmpty()) { 268 if (tokens.isEmpty()) {
288 // DEBUG 269 // DEBUG
289 System.err.println(String.format("WARNING: no tokens found for %s in %s", tokens, this.currentObfClass)); 270 System.err.println(String.format("WARNING: no tokens found for %s in %s", tokens, this.currentSource.getEntry()));
290 } else { 271 } else {
291 this.gui.showTokens(tokens); 272 this.gui.showTokens(tokens);
292 } 273 }
293 } 274 }
294 275
295 public void savePreviousReference(EntryReference<Entry<?>, Entry<?>> deobfReference) { 276 public void savePreviousReference(EntryReference<Entry<?>, Entry<?>> reference) {
296 this.referenceStack.push(this.deobfuscator.getMapper().obfuscate(deobfReference)); 277 this.referenceStack.push(reference);
297 } 278 }
298 279
299 public void openPreviousReference() { 280 public void openPreviousReference() {
300 if (hasPreviousLocation()) { 281 if (hasPreviousLocation()) {
301 openReference(this.deobfuscator.getMapper().deobfuscate(this.referenceStack.pop())); 282 openReference(this.referenceStack.pop());
302 } 283 }
303 } 284 }
304 285
@@ -318,97 +299,65 @@ public class GuiController {
318 refreshCurrentClass(null); 299 refreshCurrentClass(null);
319 } 300 }
320 301
321 private void refreshCurrentClass(EntryReference<Entry<?>, Entry<?>> obfReference) { 302 private void refreshCurrentClass(EntryReference<Entry<?>, Entry<?>> reference) {
322 if (this.currentObfClass != null) { 303 if (currentSource != null) {
323 deobfuscate(this.currentObfClass, obfReference); 304 loadClass(currentSource.getEntry(), () -> {
305 if (reference != null) {
306 showReference(reference);
307 }
308 });
324 } 309 }
325 } 310 }
326 311
327 private void deobfuscate(final ClassEntry classEntry, final EntryReference<Entry<?>, Entry<?>> obfReference) { 312 private void loadClass(ClassEntry classEntry, Runnable callback) {
313 ClassEntry targetClass = classEntry.getOutermostClass();
328 314
329 this.gui.setSource("(deobfuscating...)"); 315 boolean requiresDecompile = currentSource == null || !currentSource.getEntry().equals(targetClass);
316 if (requiresDecompile) {
317 gui.setEditorText("(decompiling...)");
318 }
330 319
331 // run the deobfuscator in a separate thread so we don't block the GUI event queue 320 DECOMPILER_SERVICE.submit(() -> {
332 new Thread(() -> 321 try {
333 { 322 if (requiresDecompile) {
334 // decompile,deobfuscate the bytecode 323 decompileSource(targetClass, deobfuscator.getObfSourceProvider());
335 CompilationUnit sourceTree = deobfuscator.getSourceTree(classEntry.getOutermostClass().getFullName());
336 if (sourceTree == null) {
337 // decompilation of this class is not supported
338 gui.setSource("Unable to find class: " + classEntry);
339 return;
340 }
341 String source = deobfuscator.getSource(sourceTree);
342 index = deobfuscator.getSourceIndex(sourceTree, source);
343
344 String sourceString = index.getSource();
345
346 // set the highlighted tokens
347 List<Token> obfuscatedTokens = Lists.newArrayList();
348 List<Token> proposedTokens = Lists.newArrayList();
349 List<Token> deobfuscatedTokens = Lists.newArrayList();
350 List<Token> otherTokens = Lists.newArrayList();
351
352 int offset = 0;
353 Map<Token, Token> tokenRemap = new HashMap<>();
354 boolean remapped = false;
355
356 for (Token inToken : index.referenceTokens()) {
357 Token token = inToken.move(offset);
358
359 EntryReference<Entry<?>, Entry<?>> reference = index.getDeobfReference(inToken);
360 if (referenceIsRenameable(reference)) {
361 boolean added = false;
362
363 if (!entryHasDeobfuscatedName(reference.getNameableEntry())) {
364 Entry<?> obfEntry = deobfuscator.getMapper().obfuscate(reference.getNameableEntry());
365 if (obfEntry instanceof FieldEntry) {
366 for (EnigmaPlugin plugin : deobfuscator.getPlugins()) {
367 String owner = obfEntry.getContainingClass().getFullName();
368 String proposal = plugin.proposeFieldName(owner, obfEntry.getName(), ((FieldEntry) obfEntry).getDesc().toString());
369 if (proposal != null) {
370 proposedTokens.add(token);
371 offset += token.getRenameOffset(proposal);
372 sourceString = token.rename(sourceString, proposal);
373 added = true;
374 remapped = true;
375 break;
376 }
377 }
378 }
379 }
380
381 if (!added) {
382 if (entryHasDeobfuscatedName(reference.getNameableEntry())) {
383 deobfuscatedTokens.add(token);
384 } else {
385 obfuscatedTokens.add(token);
386 }
387 }
388 } else {
389 otherTokens.add(token);
390 } 324 }
391 325
392 tokenRemap.put(inToken, token); 326 remapSource(deobfuscator.getMapper().getDeobfuscator());
327 callback.run();
328 } catch (Throwable t) {
329 System.err.println("An exception was thrown while decompiling class " + classEntry.getFullName());
330 t.printStackTrace(System.err);
393 } 331 }
332 });
333 }
394 334
395 if (remapped) { 335 private void decompileSource(ClassEntry targetClass, SourceProvider sourceProvider) {
396 index.remap(sourceString, tokenRemap); 336 CompilationUnit sourceTree = sourceProvider.getSources(targetClass.getFullName());
397 } 337 if (sourceTree == null) {
338 gui.setEditorText("Unable to find class: " + targetClass);
339 return;
340 }
398 341
399 gui.setSource(sourceString); 342 DropImportAstTransform.INSTANCE.run(sourceTree);
400 if (obfReference != null) { 343
401 showReference(obfReference); 344 String sourceString = sourceProvider.writeSourceToString(sourceTree);
402 } 345
346 SourceIndex index = SourceIndex.buildIndex(sourceString, sourceTree, true);
347 index.resolveReferences(deobfuscator.getMapper().getObfResolver());
348
349 currentSource = new DecompiledClassSource(targetClass, deobfuscator, index);
350 }
351
352 private void remapSource(Translator translator) {
353 if (currentSource == null) {
354 return;
355 }
356
357 currentSource.remapSource(translator);
403 358
404 gui.setEditorTheme(Config.getInstance().lookAndFeel); 359 gui.setEditorTheme(Config.getInstance().lookAndFeel);
405 gui.setHighlightedTokens(ImmutableMap.of( 360 gui.setSource(currentSource);
406 "obfuscated", obfuscatedTokens,
407 "proposed", proposedTokens,
408 "deobfuscated", deobfuscatedTokens,
409 "other", otherTokens
410 ));
411 }).start();
412 } 361 }
413 362
414 public Deobfuscator getDeobfuscator() { 363 public Deobfuscator getDeobfuscator() {