summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/cuchaz/enigma/CommandMain.java20
-rw-r--r--src/main/java/cuchaz/enigma/Deobfuscator.java63
-rw-r--r--src/main/java/cuchaz/enigma/analysis/EntryReference.java2
-rw-r--r--src/main/java/cuchaz/enigma/analysis/IndexClassVisitor.java5
-rw-r--r--src/main/java/cuchaz/enigma/analysis/IndexInnerClassVisitor.java6
-rw-r--r--src/main/java/cuchaz/enigma/analysis/JarIndex.java14
-rw-r--r--src/main/java/cuchaz/enigma/analysis/ParsedJar.java58
-rw-r--r--src/main/java/cuchaz/enigma/analysis/SourceIndex.java36
-rw-r--r--src/main/java/cuchaz/enigma/analysis/Token.java21
-rw-r--r--src/main/java/cuchaz/enigma/api/EnigmaPlugin.java18
-rw-r--r--src/main/java/cuchaz/enigma/bytecode/ClassProtectifier.java49
-rw-r--r--src/main/java/cuchaz/enigma/bytecode/ClassPublifier.java55
-rw-r--r--src/main/java/cuchaz/enigma/config/Config.java85
-rw-r--r--src/main/java/cuchaz/enigma/config/Themes.java22
-rw-r--r--src/main/java/cuchaz/enigma/gui/CodeReader.java1
-rw-r--r--src/main/java/cuchaz/enigma/gui/EnigmaSyntaxKit.java (renamed from src/main/java/cuchaz/enigma/gui/MinecraftSyntaxKit.java)2
-rw-r--r--src/main/java/cuchaz/enigma/gui/Gui.java41
-rw-r--r--src/main/java/cuchaz/enigma/gui/GuiController.java81
-rw-r--r--src/main/java/cuchaz/enigma/gui/highlight/BoxHighlightPainter.java13
-rw-r--r--src/main/java/cuchaz/enigma/gui/highlight/DeobfuscatedHighlightPainter.java21
-rw-r--r--src/main/java/cuchaz/enigma/gui/highlight/ObfuscatedHighlightPainter.java21
-rw-r--r--src/main/java/cuchaz/enigma/gui/highlight/OtherHighlightPainter.java21
-rw-r--r--src/main/java/cuchaz/enigma/mapping/DirectionalTranslator.java1
-rw-r--r--src/main/java/cuchaz/enigma/mapping/Mappings.java1
24 files changed, 310 insertions, 347 deletions
diff --git a/src/main/java/cuchaz/enigma/CommandMain.java b/src/main/java/cuchaz/enigma/CommandMain.java
index 59eb1b66..6c8caa43 100644
--- a/src/main/java/cuchaz/enigma/CommandMain.java
+++ b/src/main/java/cuchaz/enigma/CommandMain.java
@@ -28,10 +28,6 @@ public class CommandMain {
28 deobfuscate(args); 28 deobfuscate(args);
29 } else if (command.equalsIgnoreCase("decompile")) { 29 } else if (command.equalsIgnoreCase("decompile")) {
30 decompile(args); 30 decompile(args);
31 } else if (command.equalsIgnoreCase("protectify")) {
32 protectify(args);
33 } else if (command.equalsIgnoreCase("publify")) {
34 publify(args);
35 } else if (command.equalsIgnoreCase("convertmappings")) { 31 } else if (command.equalsIgnoreCase("convertmappings")) {
36 convertMappings(args); 32 convertMappings(args);
37 } else { 33 } else {
@@ -50,8 +46,6 @@ public class CommandMain {
50 System.out.println("\twhere <command> is one of:"); 46 System.out.println("\twhere <command> is one of:");
51 System.out.println("\t\tdeobfuscate <in jar> <out jar> [<mappings file>]"); 47 System.out.println("\t\tdeobfuscate <in jar> <out jar> [<mappings file>]");
52 System.out.println("\t\tdecompile <in jar> <out folder> [<mappings file>]"); 48 System.out.println("\t\tdecompile <in jar> <out folder> [<mappings file>]");
53 System.out.println("\t\tprotectify <in jar> <out jar>");
54 System.out.println("\t\tpublify <in jar> <out jar>");
55 System.out.println("\t\tconvertmappings <enigma mappings> <converted mappings> <ENIGMA_FILE|ENIGMA_DIRECTORY|SRG_FILE>"); 49 System.out.println("\t\tconvertmappings <enigma mappings> <converted mappings> <ENIGMA_FILE|ENIGMA_DIRECTORY|SRG_FILE>");
56 } 50 }
57 51
@@ -71,20 +65,6 @@ public class CommandMain {
71 deobfuscator.writeJar(fileJarOut, new ConsoleProgressListener()); 65 deobfuscator.writeJar(fileJarOut, new ConsoleProgressListener());
72 } 66 }
73 67
74 private static void protectify(String[] args) throws Exception {
75 File fileJarIn = getReadableFile(getArg(args, 1, "in jar", true));
76 File fileJarOut = getWritableFile(getArg(args, 2, "out jar", true));
77 Deobfuscator deobfuscator = getDeobfuscator(null, new JarFile(fileJarIn));
78 deobfuscator.protectifyJar(fileJarOut, new ConsoleProgressListener());
79 }
80
81 private static void publify(String[] args) throws Exception {
82 File fileJarIn = getReadableFile(getArg(args, 1, "in jar", true));
83 File fileJarOut = getWritableFile(getArg(args, 2, "out jar", true));
84 Deobfuscator deobfuscator = getDeobfuscator(null, new JarFile(fileJarIn));
85 deobfuscator.publifyJar(fileJarOut, new ConsoleProgressListener());
86 }
87
88 private static Deobfuscator getDeobfuscator(File fileMappings, JarFile jar) throws Exception { 68 private static Deobfuscator getDeobfuscator(File fileMappings, JarFile jar) throws Exception {
89 System.out.println("Reading jar..."); 69 System.out.println("Reading jar...");
90 Deobfuscator deobfuscator = new Deobfuscator(jar); 70 Deobfuscator deobfuscator = new Deobfuscator(jar);
diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java
index 465c1ec3..c1992259 100644
--- a/src/main/java/cuchaz/enigma/Deobfuscator.java
+++ b/src/main/java/cuchaz/enigma/Deobfuscator.java
@@ -28,8 +28,7 @@ import com.strobel.decompiler.languages.java.ast.CompilationUnit;
28import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor; 28import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor;
29import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform; 29import com.strobel.decompiler.languages.java.ast.transforms.IAstTransform;
30import cuchaz.enigma.analysis.*; 30import cuchaz.enigma.analysis.*;
31import cuchaz.enigma.bytecode.ClassProtectifier; 31import cuchaz.enigma.api.EnigmaPlugin;
32import cuchaz.enigma.bytecode.ClassPublifier;
33import cuchaz.enigma.mapping.*; 32import cuchaz.enigma.mapping.*;
34import cuchaz.enigma.mapping.entry.*; 33import cuchaz.enigma.mapping.entry.*;
35import cuchaz.enigma.throwables.IllegalNameException; 34import cuchaz.enigma.throwables.IllegalNameException;
@@ -40,19 +39,20 @@ import oml.ast.transformers.ObfuscatedEnumSwitchRewriterTransform;
40import oml.ast.transformers.RemoveObjectCasts; 39import oml.ast.transformers.RemoveObjectCasts;
41import oml.ast.transformers.VarargsFixer; 40import oml.ast.transformers.VarargsFixer;
42import org.objectweb.asm.ClassWriter; 41import org.objectweb.asm.ClassWriter;
43import org.objectweb.asm.Opcodes;
44import org.objectweb.asm.tree.ClassNode; 42import org.objectweb.asm.tree.ClassNode;
45 43
46import java.io.*; 44import java.io.*;
47import java.util.*; 45import java.util.*;
48import java.util.concurrent.ConcurrentHashMap; 46import java.util.concurrent.ConcurrentHashMap;
49import java.util.concurrent.atomic.AtomicInteger; 47import java.util.concurrent.atomic.AtomicInteger;
48import java.util.function.Consumer;
50import java.util.jar.JarEntry; 49import java.util.jar.JarEntry;
51import java.util.jar.JarFile; 50import java.util.jar.JarFile;
52import java.util.jar.JarOutputStream; 51import java.util.jar.JarOutputStream;
53 52
54public class Deobfuscator { 53public class Deobfuscator {
55 54
55 private final ServiceLoader<EnigmaPlugin> plugins = ServiceLoader.load(EnigmaPlugin.class);
56 private final ReferencedEntryPool entryPool = new ReferencedEntryPool(); 56 private final ReferencedEntryPool entryPool = new ReferencedEntryPool();
57 private final ParsedJar parsedJar; 57 private final ParsedJar parsedJar;
58 private final DecompilerSettings settings; 58 private final DecompilerSettings settings;
@@ -61,13 +61,20 @@ public class Deobfuscator {
61 private final Map<TranslationDirection, Translator> translatorCache; 61 private final Map<TranslationDirection, Translator> translatorCache;
62 private Mappings mappings; 62 private Mappings mappings;
63 63
64 public Deobfuscator(ParsedJar jar) { 64 public Deobfuscator(ParsedJar jar, Consumer<String> listener) {
65 this.parsedJar = jar; 65 this.parsedJar = jar;
66 66
67 // build the jar index 67 // build the jar index
68 listener.accept("Indexing JAR...");
68 this.jarIndex = new JarIndex(entryPool); 69 this.jarIndex = new JarIndex(entryPool);
69 this.jarIndex.indexJar(this.parsedJar, true); 70 this.jarIndex.indexJar(this.parsedJar, true);
70 71
72 listener.accept("Initializing plugins...");
73 for (EnigmaPlugin plugin : getPlugins()) {
74 plugin.onClassesLoaded(parsedJar.getClassDataMap(), parsedJar::getClassNode);
75 }
76
77 listener.accept("Preparing...");
71 // config the decompiler 78 // config the decompiler
72 this.settings = DecompilerSettings.javaDefaults(); 79 this.settings = DecompilerSettings.javaDefaults();
73 this.settings.setMergeVariables(Utils.getSystemPropertyAsBoolean("enigma.mergeVariables", true)); 80 this.settings.setMergeVariables(Utils.getSystemPropertyAsBoolean("enigma.mergeVariables", true));
@@ -85,8 +92,20 @@ public class Deobfuscator {
85 setMappings(new Mappings()); 92 setMappings(new Mappings());
86 } 93 }
87 94
88 public Deobfuscator(JarFile jar) throws IOException { 95 public Deobfuscator(JarFile jar, Consumer<String> listener) throws IOException {
89 this(new ParsedJar(jar)); 96 this(new ParsedJar(jar), listener);
97 }
98
99 public Deobfuscator(ParsedJar jar) throws IOException {
100 this(jar, (msg) -> {});
101 }
102
103 public Deobfuscator(JarFile jar) throws IOException {
104 this(jar, (msg) -> {});
105 }
106
107 public ServiceLoader<EnigmaPlugin> getPlugins() {
108 return plugins;
90 } 109 }
91 110
92 public ParsedJar getJar() { 111 public ParsedJar getJar() {
@@ -442,20 +461,6 @@ public class Deobfuscator {
442 transformJar(out, progress, createTypeLoader()::transformInto); 461 transformJar(out, progress, createTypeLoader()::transformInto);
443 } 462 }
444 463
445 public void protectifyJar(File out, ProgressListener progress) {
446 transformJar(out, progress, (node, writer) -> {
447 node.accept(new ClassProtectifier(Opcodes.ASM5, writer));
448 return node.name;
449 });
450 }
451
452 public void publifyJar(File out, ProgressListener progress) {
453 transformJar(out, progress, (node, writer) -> {
454 node.accept(new ClassPublifier(Opcodes.ASM5, writer));
455 return node.name;
456 });
457 }
458
459 public void transformJar(File out, ProgressListener progress, ClassTransformer transformer) { 464 public void transformJar(File out, ProgressListener progress, ClassTransformer transformer) {
460 try (JarOutputStream outJar = new JarOutputStream(new FileOutputStream(out))) { 465 try (JarOutputStream outJar = new JarOutputStream(new FileOutputStream(out))) {
461 if (progress != null) { 466 if (progress != null) {
@@ -463,7 +468,7 @@ public class Deobfuscator {
463 } 468 }
464 469
465 AtomicInteger i = new AtomicInteger(); 470 AtomicInteger i = new AtomicInteger();
466 parsedJar.visit(node -> { 471 parsedJar.visitNode(node -> {
467 if (progress != null) { 472 if (progress != null) {
468 progress.onProgress(i.getAndIncrement(), node.name); 473 progress.onProgress(i.getAndIncrement(), node.name);
469 } 474 }
@@ -524,13 +529,7 @@ public class Deobfuscator {
524 } 529 }
525 530
526 public boolean isObfuscatedIdentifier(Entry obfEntry) { 531 public boolean isObfuscatedIdentifier(Entry obfEntry) {
527 return isObfuscatedIdentifier(obfEntry, false);
528 }
529
530 public boolean isObfuscatedIdentifier(Entry obfEntry, boolean hack) {
531
532 if (obfEntry instanceof MethodEntry) { 532 if (obfEntry instanceof MethodEntry) {
533
534 // HACKHACK: Object methods are not obfuscated identifiers 533 // HACKHACK: Object methods are not obfuscated identifiers
535 MethodEntry obfMethodEntry = (MethodEntry) obfEntry; 534 MethodEntry obfMethodEntry = (MethodEntry) obfEntry;
536 String name = obfMethodEntry.getName(); 535 String name = obfMethodEntry.getName();
@@ -558,21 +557,13 @@ public class Deobfuscator {
558 } else if (name.equals("wait") && sig.equals("(JI)V")) { 557 } else if (name.equals("wait") && sig.equals("(JI)V")) {
559 return false; 558 return false;
560 } 559 }
561
562 // FIXME: HACK EVEN MORE HACK!
563 if (hack && this.jarIndex.containsObfEntry(obfEntry.getOwnerClassEntry()))
564 return true;
565 } 560 }
566 561
567 return this.jarIndex.containsObfEntry(obfEntry); 562 return this.jarIndex.containsObfEntry(obfEntry);
568 } 563 }
569 564
570 public boolean isRenameable(EntryReference<Entry, Entry> obfReference, boolean activeHack) {
571 return obfReference.isNamed() && isObfuscatedIdentifier(obfReference.getNameableEntry(), activeHack);
572 }
573
574 public boolean isRenameable(EntryReference<Entry, Entry> obfReference) { 565 public boolean isRenameable(EntryReference<Entry, Entry> obfReference) {
575 return isRenameable(obfReference, false); 566 return obfReference.isNamed() && isObfuscatedIdentifier(obfReference.getNameableEntry());
576 } 567 }
577 568
578 public boolean hasDeobfuscatedName(Entry obfEntry) { 569 public boolean hasDeobfuscatedName(Entry obfEntry) {
diff --git a/src/main/java/cuchaz/enigma/analysis/EntryReference.java b/src/main/java/cuchaz/enigma/analysis/EntryReference.java
index 101729d8..df36c236 100644
--- a/src/main/java/cuchaz/enigma/analysis/EntryReference.java
+++ b/src/main/java/cuchaz/enigma/analysis/EntryReference.java
@@ -70,7 +70,7 @@ public class EntryReference<E extends Entry, C extends Entry> {
70 return entry; 70 return entry;
71 } 71 }
72 72
73 public String getNamableName() { 73 public String getNameableName() {
74 if (getNameableEntry() instanceof ClassEntry) { 74 if (getNameableEntry() instanceof ClassEntry) {
75 ClassEntry classEntry = (ClassEntry) getNameableEntry(); 75 ClassEntry classEntry = (ClassEntry) getNameableEntry();
76 if (classEntry.isInnerClass()) { 76 if (classEntry.isInnerClass()) {
diff --git a/src/main/java/cuchaz/enigma/analysis/IndexClassVisitor.java b/src/main/java/cuchaz/enigma/analysis/IndexClassVisitor.java
index 69fe54fc..4d5e8037 100644
--- a/src/main/java/cuchaz/enigma/analysis/IndexClassVisitor.java
+++ b/src/main/java/cuchaz/enigma/analysis/IndexClassVisitor.java
@@ -14,6 +14,11 @@ public class IndexClassVisitor extends ClassVisitor {
14 this.index = index; 14 this.index = index;
15 } 15 }
16 16
17 public IndexClassVisitor(JarIndex index, int api, ClassVisitor cv) {
18 super(api, cv);
19 this.index = index;
20 }
21
17 @Override 22 @Override
18 public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 23 public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
19 this.classEntry = this.index.indexClass(access, name, signature, superName, interfaces); 24 this.classEntry = this.index.indexClass(access, name, signature, superName, interfaces);
diff --git a/src/main/java/cuchaz/enigma/analysis/IndexInnerClassVisitor.java b/src/main/java/cuchaz/enigma/analysis/IndexInnerClassVisitor.java
index 04742278..b6ab2d5b 100644
--- a/src/main/java/cuchaz/enigma/analysis/IndexInnerClassVisitor.java
+++ b/src/main/java/cuchaz/enigma/analysis/IndexInnerClassVisitor.java
@@ -11,6 +11,11 @@ public class IndexInnerClassVisitor extends ClassVisitor {
11 this.index = index; 11 this.index = index;
12 } 12 }
13 13
14 public IndexInnerClassVisitor(JarIndex index, int api, ClassVisitor cv) {
15 super(api, cv);
16 this.index = index;
17 }
18
14 @Override 19 @Override
15 public void visitInnerClass(String name, String outerName, String innerName, int access) { 20 public void visitInnerClass(String name, String outerName, String innerName, int access) {
16 ClassEntry entry = new ClassEntry(name); 21 ClassEntry entry = new ClassEntry(name);
@@ -19,5 +24,6 @@ public class IndexInnerClassVisitor extends ClassVisitor {
19 ClassEntry outerEntry = new ClassEntry(outerName); 24 ClassEntry outerEntry = new ClassEntry(outerName);
20 index.indexInnerClass(entry, outerEntry); 25 index.indexInnerClass(entry, outerEntry);
21 } 26 }
27 super.visitInnerClass(name, outerName, innerName, access);
22 } 28 }
23} 29}
diff --git a/src/main/java/cuchaz/enigma/analysis/JarIndex.java b/src/main/java/cuchaz/enigma/analysis/JarIndex.java
index 158df4b5..e8bda8ef 100644
--- a/src/main/java/cuchaz/enigma/analysis/JarIndex.java
+++ b/src/main/java/cuchaz/enigma/analysis/JarIndex.java
@@ -15,6 +15,8 @@ import com.google.common.collect.*;
15import cuchaz.enigma.bytecode.AccessFlags; 15import cuchaz.enigma.bytecode.AccessFlags;
16import cuchaz.enigma.mapping.*; 16import cuchaz.enigma.mapping.*;
17import cuchaz.enigma.mapping.entry.*; 17import cuchaz.enigma.mapping.entry.*;
18import org.objectweb.asm.ClassReader;
19import org.objectweb.asm.ClassVisitor;
18import org.objectweb.asm.Opcodes; 20import org.objectweb.asm.Opcodes;
19 21
20import java.util.*; 22import java.util.*;
@@ -62,10 +64,15 @@ public class JarIndex {
62 obfClassEntries.addAll(jar.getClassEntries()); 64 obfClassEntries.addAll(jar.getClassEntries());
63 65
64 // step 2: index classes, fields, methods, interfaces 66 // step 2: index classes, fields, methods, interfaces
65 jar.visit(node -> node.accept(new IndexClassVisitor(this, Opcodes.ASM5))); 67 if (buildInnerClasses) {
68 // + step 5: index inner classes
69 jar.visitReader(name -> new IndexClassVisitor(this, Opcodes.ASM5, new IndexInnerClassVisitor(this, Opcodes.ASM5)), ClassReader.SKIP_CODE);
70 } else {
71 jar.visitReader(name -> new IndexClassVisitor(this, Opcodes.ASM5), ClassReader.SKIP_CODE);
72 }
66 73
67 // step 3: index field, method, constructor references 74 // step 3: index field, method, constructor references
68 jar.visit(node -> node.accept(new IndexReferenceVisitor(this, Opcodes.ASM5))); 75 jar.visitReader(name -> new IndexReferenceVisitor(this, Opcodes.ASM5), ClassReader.SKIP_FRAMES);
69 76
70 // step 4: index access and bridged methods 77 // step 4: index access and bridged methods
71 for (MethodDefEntry methodEntry : methods.values()) { 78 for (MethodDefEntry methodEntry : methods.values()) {
@@ -79,9 +86,6 @@ public class JarIndex {
79 } 86 }
80 87
81 if (buildInnerClasses) { 88 if (buildInnerClasses) {
82 // step 5: index inner classes and anonymous classes
83 jar.visit(node -> node.accept(new IndexInnerClassVisitor(this, Opcodes.ASM5)));
84
85 // step 6: update other indices with inner class info 89 // step 6: update other indices with inner class info
86 Map<String, String> renames = Maps.newHashMap(); 90 Map<String, String> renames = Maps.newHashMap();
87 for (ClassEntry innerClassEntry : this.innerClassesByOuter.values()) { 91 for (ClassEntry innerClassEntry : this.innerClassesByOuter.values()) {
diff --git a/src/main/java/cuchaz/enigma/analysis/ParsedJar.java b/src/main/java/cuchaz/enigma/analysis/ParsedJar.java
index 55f2141b..86655d09 100644
--- a/src/main/java/cuchaz/enigma/analysis/ParsedJar.java
+++ b/src/main/java/cuchaz/enigma/analysis/ParsedJar.java
@@ -11,8 +11,10 @@
11 11
12package cuchaz.enigma.analysis; 12package cuchaz.enigma.analysis;
13 13
14import com.google.common.io.ByteStreams;
14import cuchaz.enigma.mapping.entry.ClassEntry; 15import cuchaz.enigma.mapping.entry.ClassEntry;
15import org.objectweb.asm.ClassReader; 16import org.objectweb.asm.ClassReader;
17import org.objectweb.asm.ClassVisitor;
16import org.objectweb.asm.tree.ClassNode; 18import org.objectweb.asm.tree.ClassNode;
17 19
18import java.io.BufferedInputStream; 20import java.io.BufferedInputStream;
@@ -20,14 +22,17 @@ import java.io.IOException;
20import java.io.InputStream; 22import java.io.InputStream;
21import java.util.*; 23import java.util.*;
22import java.util.function.Consumer; 24import java.util.function.Consumer;
25import java.util.function.Function;
23import java.util.jar.JarEntry; 26import java.util.jar.JarEntry;
24import java.util.jar.JarFile; 27import java.util.jar.JarFile;
25import java.util.jar.JarInputStream; 28import java.util.jar.JarInputStream;
26 29
27public class ParsedJar { 30public class ParsedJar {
28 private final Map<String, ClassNode> nodes = new LinkedHashMap<>(); 31 private final Map<String, byte[]> classBytes;
32 private final Map<String, ClassNode> nodeCache = new HashMap<>();
29 33
30 public ParsedJar(JarFile jar) throws IOException { 34 public ParsedJar(JarFile jar) throws IOException {
35 Map<String, byte[]> uClassBytes = new LinkedHashMap<>();;
31 try { 36 try {
32 // get the jar entries that correspond to classes 37 // get the jar entries that correspond to classes
33 Enumeration<JarEntry> entries = jar.entries(); 38 Enumeration<JarEntry> entries = jar.entries();
@@ -36,60 +41,75 @@ public class ParsedJar {
36 // is this a class file? 41 // is this a class file?
37 if (entry.getName().endsWith(".class")) { 42 if (entry.getName().endsWith(".class")) {
38 try (InputStream input = new BufferedInputStream(jar.getInputStream(entry))) { 43 try (InputStream input = new BufferedInputStream(jar.getInputStream(entry))) {
39 // read the ClassNode from the jar
40 ClassReader reader = new ClassReader(input);
41 ClassNode node = new ClassNode();
42 reader.accept(node, 0);
43 String path = entry.getName().substring(0, entry.getName().length() - ".class".length()); 44 String path = entry.getName().substring(0, entry.getName().length() - ".class".length());
44 nodes.put(path, node); 45 uClassBytes.put(path, ByteStreams.toByteArray(input));
45 } 46 }
46 } 47 }
47 } 48 }
48 } finally { 49 } finally {
49 jar.close(); 50 jar.close();
51 classBytes = Collections.unmodifiableMap(uClassBytes);
50 } 52 }
51 } 53 }
52 54
53 public ParsedJar(JarInputStream jar) throws IOException { 55 public ParsedJar(JarInputStream jar) throws IOException {
56 Map<String, byte[]> uClassBytes = new LinkedHashMap<>();
54 try { 57 try {
55 // get the jar entries that correspond to classes 58 // get the jar entries that correspond to classes
56 JarEntry entry; 59 JarEntry entry;
57 while ((entry = jar.getNextJarEntry()) != null) { 60 while ((entry = jar.getNextJarEntry()) != null) {
58 // is this a class file? 61 // is this a class file?
59 if (entry.getName().endsWith(".class")) { 62 if (entry.getName().endsWith(".class")) {
60 // read the ClassNode from the jar
61 ClassReader reader = new ClassReader(jar);
62 ClassNode node = new ClassNode();
63 reader.accept(node, 0);
64 String path = entry.getName().substring(0, entry.getName().length() - ".class".length()); 63 String path = entry.getName().substring(0, entry.getName().length() - ".class".length());
65 nodes.put(path, node); 64 uClassBytes.put(path, ByteStreams.toByteArray(jar));
66 jar.closeEntry(); 65 jar.closeEntry();
67 } 66 }
68 } 67 }
69 } finally { 68 } finally {
70 jar.close(); 69 jar.close();
70 classBytes = Collections.unmodifiableMap(uClassBytes);
71 } 71 }
72 } 72 }
73 73
74 public void visit(Consumer<ClassNode> visitor) { 74 public void visitReader(Function<String, ClassVisitor> visitorFunction, int options) {
75 for (ClassNode node : nodes.values()) { 75 for (String s : classBytes.keySet()) {
76 visitor.accept(node); 76 ClassNode nodeCached = nodeCache.get(s);
77 if (nodeCached != null) {
78 nodeCached.accept(visitorFunction.apply(s));
79 } else {
80 new ClassReader(classBytes.get(s)).accept(visitorFunction.apply(s), options);
81 }
82 }
83 }
84
85 public void visitNode(Consumer<ClassNode> consumer) {
86 for (String s : classBytes.keySet()) {
87 consumer.accept(getClassNode(s));
77 } 88 }
78 } 89 }
79 90
80 public int getClassCount() { 91 public int getClassCount() {
81 return nodes.size(); 92 return classBytes.size();
82 } 93 }
83 94
84 public List<ClassEntry> getClassEntries() { 95 public List<ClassEntry> getClassEntries() {
85 List<ClassEntry> entries = new ArrayList<>(nodes.size()); 96 List<ClassEntry> entries = new ArrayList<>(classBytes.size());
86 for (ClassNode node : nodes.values()) { 97 for (String s : classBytes.keySet()) {
87 entries.add(new ClassEntry(node.name)); 98 entries.add(new ClassEntry(s));
88 } 99 }
89 return entries; 100 return entries;
90 } 101 }
91 102
92 public ClassNode getClassNode(String name) { 103 public ClassNode getClassNode(String name) {
93 return nodes.get(name); 104 return nodeCache.computeIfAbsent(name, (n) -> {
105 ClassReader reader = new ClassReader(classBytes.get(name));
106 ClassNode node = new ClassNode();
107 reader.accept(node, 0);
108 return node;
109 });
94 } 110 }
111
112 public Map<String, byte[]> getClassDataMap() {
113 return classBytes;
114 }
95} 115}
diff --git a/src/main/java/cuchaz/enigma/analysis/SourceIndex.java b/src/main/java/cuchaz/enigma/analysis/SourceIndex.java
index 78195cb7..4c84e69d 100644
--- a/src/main/java/cuchaz/enigma/analysis/SourceIndex.java
+++ b/src/main/java/cuchaz/enigma/analysis/SourceIndex.java
@@ -22,10 +22,7 @@ import com.strobel.decompiler.languages.java.ast.Identifier;
22import com.strobel.decompiler.languages.java.ast.TypeDeclaration; 22import com.strobel.decompiler.languages.java.ast.TypeDeclaration;
23import cuchaz.enigma.mapping.entry.Entry; 23import cuchaz.enigma.mapping.entry.Entry;
24 24
25import java.util.Collection; 25import java.util.*;
26import java.util.List;
27import java.util.Map;
28import java.util.TreeMap;
29import java.util.regex.Pattern; 26import java.util.regex.Pattern;
30 27
31public class SourceIndex { 28public class SourceIndex {
@@ -48,9 +45,12 @@ public class SourceIndex {
48 this.tokenToReference = Maps.newTreeMap(); 45 this.tokenToReference = Maps.newTreeMap();
49 this.referenceToTokens = HashMultimap.create(); 46 this.referenceToTokens = HashMultimap.create();
50 this.declarationToToken = Maps.newHashMap(); 47 this.declarationToToken = Maps.newHashMap();
51 this.lineOffsets = Lists.newArrayList(); 48 calculateLineOffsets();
49 }
52 50
51 private void calculateLineOffsets() {
53 // count the lines 52 // count the lines
53 this.lineOffsets = Lists.newArrayList();
54 this.lineOffsets.add(0); 54 this.lineOffsets.add(0);
55 for (int i = 0; i < source.length(); i++) { 55 for (int i = 0; i < source.length(); i++) {
56 if (source.charAt(i) == '\n') { 56 if (source.charAt(i) == '\n') {
@@ -59,6 +59,32 @@ public class SourceIndex {
59 } 59 }
60 } 60 }
61 61
62 public void remap(String source, Map<Token, Token> tokenMap) {
63 this.source = source;
64 calculateLineOffsets();
65
66 for (Entry entry : Lists.newArrayList(declarationToToken.keySet())) {
67 Token token = declarationToToken.get(entry);
68 declarationToToken.put(entry, tokenMap.getOrDefault(token, token));
69 }
70
71 for (Token token : Lists.newArrayList(tokenToReference.keySet())) {
72 EntryReference<Entry, Entry> e = tokenToReference.remove(token);
73 tokenToReference.put(tokenMap.getOrDefault(token, token), e);
74 }
75
76 for (EntryReference<Entry, Entry> ref : Lists.newArrayList(referenceToTokens.keySet())) {
77 List<Token> newTokens = new ArrayList<>();
78
79 for (Token token : referenceToTokens.get(ref)) {
80 newTokens.add(tokenMap.getOrDefault(token, token));
81 }
82
83 referenceToTokens.removeAll(ref);
84 referenceToTokens.putAll(ref, newTokens);
85 }
86 }
87
62 public String getSource() { 88 public String getSource() {
63 return this.source; 89 return this.source;
64 } 90 }
diff --git a/src/main/java/cuchaz/enigma/analysis/Token.java b/src/main/java/cuchaz/enigma/analysis/Token.java
index 266d2027..14fa7ca4 100644
--- a/src/main/java/cuchaz/enigma/analysis/Token.java
+++ b/src/main/java/cuchaz/enigma/analysis/Token.java
@@ -25,6 +25,25 @@ public class Token implements Comparable<Token> {
25 } 25 }
26 } 26 }
27 27
28 public int getRenameOffset(String to) {
29 int length = this.end - this.start;
30 return to.length() - length;
31 }
32
33 public String rename(String source, String to) {
34 int oldEnd = this.end;
35 this.text = to;
36 this.end = this.start + to.length();
37
38 return source.substring(0, this.start) + to + source.substring(oldEnd);
39 }
40
41 public Token move(int offset) {
42 Token token = new Token(this.start + offset, this.end + offset, null);
43 token.text = text;
44 return token;
45 }
46
28 public boolean contains(int pos) { 47 public boolean contains(int pos) {
29 return pos >= start && pos <= end; 48 return pos >= start && pos <= end;
30 } 49 }
@@ -41,7 +60,7 @@ public class Token implements Comparable<Token> {
41 60
42 @Override 61 @Override
43 public int hashCode() { 62 public int hashCode() {
44 return Integer.hashCode(start) + Integer.hashCode(end) + (text != null ? text.hashCode() : 0); 63 return start * 37 + end;
45 } 64 }
46 65
47 public boolean equals(Token other) { 66 public boolean equals(Token other) {
diff --git a/src/main/java/cuchaz/enigma/api/EnigmaPlugin.java b/src/main/java/cuchaz/enigma/api/EnigmaPlugin.java
new file mode 100644
index 00000000..3efe0dc5
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/api/EnigmaPlugin.java
@@ -0,0 +1,18 @@
1package cuchaz.enigma.api;
2
3import org.objectweb.asm.tree.ClassNode;
4
5import javax.annotation.Nullable;
6import java.util.Map;
7import java.util.function.Function;
8
9public abstract class EnigmaPlugin {
10 public void onClassesLoaded(Map<String, byte[]> classData, Function<String, ClassNode> classNodeGetter) {
11
12 }
13
14 @Nullable
15 public String proposeFieldName(String owner, String name, String desc) {
16 return null;
17 }
18}
diff --git a/src/main/java/cuchaz/enigma/bytecode/ClassProtectifier.java b/src/main/java/cuchaz/enigma/bytecode/ClassProtectifier.java
deleted file mode 100644
index 9ed6db9f..00000000
--- a/src/main/java/cuchaz/enigma/bytecode/ClassProtectifier.java
+++ /dev/null
@@ -1,49 +0,0 @@
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 ******************************************************************************/
11
12package cuchaz.enigma.bytecode;
13
14import org.objectweb.asm.ClassVisitor;
15import org.objectweb.asm.FieldVisitor;
16import org.objectweb.asm.MethodVisitor;
17
18public class ClassProtectifier extends ClassVisitor {
19
20 public ClassProtectifier(int api, ClassVisitor cv) {
21 super(api, cv);
22 }
23
24 @Override
25 public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
26 access = protectify(access);
27 return super.visitMethod(access, name, desc, signature, exceptions);
28 }
29
30 @Override
31 public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
32 access = protectify(access);
33 return super.visitField(access, name, desc, signature, value);
34 }
35
36 @Override
37 public void visitInnerClass(String name, String outerName, String innerName, int access) {
38 access = protectify(access);
39 super.visitInnerClass(name, outerName, innerName, access);
40 }
41
42 private static int protectify(int access) {
43 AccessFlags accessFlags = new AccessFlags(access);
44 if (accessFlags.isPrivate()) {
45 accessFlags.setProtected();
46 }
47 return accessFlags.getFlags();
48 }
49}
diff --git a/src/main/java/cuchaz/enigma/bytecode/ClassPublifier.java b/src/main/java/cuchaz/enigma/bytecode/ClassPublifier.java
deleted file mode 100644
index 64de788f..00000000
--- a/src/main/java/cuchaz/enigma/bytecode/ClassPublifier.java
+++ /dev/null
@@ -1,55 +0,0 @@
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 ******************************************************************************/
11
12package cuchaz.enigma.bytecode;
13
14import org.objectweb.asm.ClassVisitor;
15import org.objectweb.asm.FieldVisitor;
16import org.objectweb.asm.MethodVisitor;
17
18public class ClassPublifier extends ClassVisitor {
19
20 public ClassPublifier(int api, ClassVisitor cv) {
21 super(api, cv);
22 }
23
24 @Override
25 public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
26 access = publify(access);
27 super.visit(version, access, name, signature, superName, interfaces);
28 }
29
30 @Override
31 public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
32 access = publify(access);
33 return super.visitField(access, name, desc, signature, value);
34 }
35
36 @Override
37 public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
38 access = publify(access);
39 return super.visitMethod(access, name, desc, signature, exceptions);
40 }
41
42 @Override
43 public void visitInnerClass(String name, String outerName, String innerName, int access) {
44 access = publify(access);
45 super.visitInnerClass(name, outerName, innerName, access);
46 }
47
48 private static int publify(int access) {
49 AccessFlags accessFlags = new AccessFlags(access);
50 if (!accessFlags.isPublic()) {
51 accessFlags.setPublic();
52 }
53 return accessFlags.getFlags();
54 }
55}
diff --git a/src/main/java/cuchaz/enigma/config/Config.java b/src/main/java/cuchaz/enigma/config/Config.java
index 8c16c47b..47bd0a7f 100644
--- a/src/main/java/cuchaz/enigma/config/Config.java
+++ b/src/main/java/cuchaz/enigma/config/Config.java
@@ -6,12 +6,32 @@ import com.google.gson.*;
6 6
7import javax.swing.*; 7import javax.swing.*;
8import javax.swing.plaf.metal.MetalLookAndFeel; 8import javax.swing.plaf.metal.MetalLookAndFeel;
9import java.awt.*;
9import java.io.File; 10import java.io.File;
10import java.io.IOException; 11import java.io.IOException;
11import java.lang.reflect.Type; 12import java.lang.reflect.Type;
12import java.nio.charset.Charset; 13import java.nio.charset.Charset;
13 14
14public class Config { 15public class Config {
16 public static class AlphaColorEntry {
17 public Integer rgb;
18 public float alpha = 1.0f;
19
20 public AlphaColorEntry(Integer rgb, float alpha) {
21 this.rgb = rgb;
22 this.alpha = alpha;
23 }
24
25 public Color get() {
26 if (rgb == null) {
27 return new Color(0, 0, 0, 0);
28 }
29
30 Color baseColor = new Color(rgb);
31 return new Color(baseColor.getRed(), baseColor.getGreen(), baseColor.getBlue(), (int)(255 * alpha));
32 }
33 }
34
15 public enum LookAndFeel { 35 public enum LookAndFeel {
16 DEFAULT("Default"), 36 DEFAULT("Default"),
17 DARCULA("Dank"); 37 DARCULA("Dank");
@@ -47,16 +67,13 @@ public class Config {
47 config.lineNumbersForeground = 0x333300; 67 config.lineNumbersForeground = 0x333300;
48 config.lineNumbersBackground = 0xEEEEFF; 68 config.lineNumbersBackground = 0xEEEEFF;
49 config.lineNumbersSelected = 0xCCCCEE; 69 config.lineNumbersSelected = 0xCCCCEE;
50 config.obfuscatedColor = 0xFFDCDC; 70 config.obfuscatedColor = new AlphaColorEntry(0xFFDCDC, 1.0f);
51 config.obfuscatedHiglightAlpha = 1.0F; 71 config.obfuscatedColorOutline = new AlphaColorEntry(0xA05050, 1.0f);
52 config.obfuscatedColorOutline = 0xA05050; 72 config.proposedColor = new AlphaColorEntry(0x000000, 0.075f);
53 config.obfuscatedOutlineAlpha = 1.0F; 73 config.proposedColorOutline = new AlphaColorEntry(0x000000, 0.15f);
54 config.deobfuscatedColor = 0xDCFFDC; 74 config.deobfuscatedColor = new AlphaColorEntry(0xDCFFDC, 1.0f);
55 config.deobfuscatedHiglightAlpha = 1.0F; 75 config.deobfuscatedColorOutline = new AlphaColorEntry(0x50A050, 1.0f);
56 config.deobfuscatedColorOutline = 0x50A050; 76 config.otherColorOutline = new AlphaColorEntry(0xB4B4B4, 1.0f);
57 config.deobfuscatedOutlineAlpha = 1.0F;
58 config.otherColorOutline = 0xB4B4B4;
59 config.otherOutlineAlpha = 1.0F;
60 config.editorBackground = 0xFFFFFF; 77 config.editorBackground = 0xFFFFFF;
61 config.highlightColor = 0x3333EE; 78 config.highlightColor = 0x3333EE;
62 config.stringColor = 0xCC6600; 79 config.stringColor = 0xCC6600;
@@ -72,16 +89,13 @@ public class Config {
72 config.lineNumbersForeground = 0xA4A4A3; 89 config.lineNumbersForeground = 0xA4A4A3;
73 config.lineNumbersBackground = 0x313335; 90 config.lineNumbersBackground = 0x313335;
74 config.lineNumbersSelected = 0x606366; 91 config.lineNumbersSelected = 0x606366;
75 config.obfuscatedColor = 0xFF5555; 92 config.obfuscatedColor = new AlphaColorEntry(0xFF5555, 0.3f);
76 config.obfuscatedHiglightAlpha = 0.3F; 93 config.obfuscatedColorOutline = new AlphaColorEntry(0xFF5555, 0.5f);
77 config.obfuscatedColorOutline = 0xFF5555; 94 config.deobfuscatedColor = new AlphaColorEntry(0x50FA7B, 0.3f);
78 config.obfuscatedOutlineAlpha = 0.5F; 95 config.deobfuscatedColorOutline = new AlphaColorEntry(0x50FA7B, 0.5f);
79 config.deobfuscatedColor = 0x50FA7B; 96 config.proposedColor = new AlphaColorEntry(0x606366, 0.3f);
80 config.deobfuscatedHiglightAlpha = 0.3F; 97 config.proposedColorOutline = new AlphaColorEntry(0x606366, 0.5f);
81 config.deobfuscatedColorOutline = 0x50FA7B; 98 config.otherColorOutline = new AlphaColorEntry(0xB4B4B4, 0.0f);
82 config.deobfuscatedOutlineAlpha = 0.5F;
83 config.otherColorOutline = 0xB4B4B4;
84 config.otherOutlineAlpha = 0.0F;
85 config.editorBackground = 0x282A36; 99 config.editorBackground = 0x282A36;
86 config.highlightColor = 0xFF79C6; 100 config.highlightColor = 0xFF79C6;
87 config.stringColor = 0xF1FA8C; 101 config.stringColor = 0xF1FA8C;
@@ -103,16 +117,13 @@ public class Config {
103 117
104 private final transient Gson gson; // transient to exclude it from being exposed 118 private final transient Gson gson; // transient to exclude it from being exposed
105 119
106 public Integer obfuscatedColor; 120 public AlphaColorEntry obfuscatedColor;
107 public float obfuscatedHiglightAlpha; 121 public AlphaColorEntry obfuscatedColorOutline;
108 public Integer obfuscatedColorOutline; 122 public AlphaColorEntry proposedColor;
109 public float obfuscatedOutlineAlpha; 123 public AlphaColorEntry proposedColorOutline;
110 public Integer deobfuscatedColor; 124 public AlphaColorEntry deobfuscatedColor;
111 public float deobfuscatedHiglightAlpha; 125 public AlphaColorEntry deobfuscatedColorOutline;
112 public Integer deobfuscatedColorOutline; 126 public AlphaColorEntry otherColorOutline;
113 public float deobfuscatedOutlineAlpha;
114 public Integer otherColorOutline;
115 public float otherOutlineAlpha;
116 127
117 //Defaults found here: https://github.com/Sciss/SyntaxPane/blob/122da367ff7a5d31627a70c62a48a9f0f4f85a0a/src/main/resources/de/sciss/syntaxpane/defaultsyntaxkit/config.properties#L139 128 //Defaults found here: https://github.com/Sciss/SyntaxPane/blob/122da367ff7a5d31627a70c62a48a9f0f4f85a0a/src/main/resources/de/sciss/syntaxpane/defaultsyntaxkit/config.properties#L139
118 public Integer editorBackground; 129 public Integer editorBackground;
@@ -152,8 +163,18 @@ public class Config {
152 public void loadConfig() throws IOException { 163 public void loadConfig() throws IOException {
153 if (!ENIGMA_DIR.exists()) ENIGMA_DIR.mkdirs(); 164 if (!ENIGMA_DIR.exists()) ENIGMA_DIR.mkdirs();
154 File configFile = new File(ENIGMA_DIR, "config.json"); 165 File configFile = new File(ENIGMA_DIR, "config.json");
155 if (configFile.exists()) gson.fromJson(Files.asCharSource(configFile, Charset.defaultCharset()).read(), Config.class); 166 boolean loaded = false;
156 else { 167
168 if (configFile.exists()) {
169 try {
170 gson.fromJson(Files.asCharSource(configFile, Charset.defaultCharset()).read(), Config.class);
171 loaded = true;
172 } catch (Exception e) {
173 e.printStackTrace();
174 }
175 }
176
177 if (!loaded) {
157 this.reset(); 178 this.reset();
158 Files.touch(configFile); 179 Files.touch(configFile);
159 } 180 }
diff --git a/src/main/java/cuchaz/enigma/config/Themes.java b/src/main/java/cuchaz/enigma/config/Themes.java
index 8a4c3417..00324f47 100644
--- a/src/main/java/cuchaz/enigma/config/Themes.java
+++ b/src/main/java/cuchaz/enigma/config/Themes.java
@@ -1,15 +1,12 @@
1package cuchaz.enigma.config; 1package cuchaz.enigma.config;
2 2
3import com.bulenkov.darcula.DarculaLaf; 3import com.google.common.collect.ImmutableMap;
4import cuchaz.enigma.gui.Gui; 4import cuchaz.enigma.gui.Gui;
5import cuchaz.enigma.gui.MinecraftSyntaxKit; 5import cuchaz.enigma.gui.EnigmaSyntaxKit;
6import cuchaz.enigma.gui.highlight.DeobfuscatedHighlightPainter; 6import cuchaz.enigma.gui.highlight.BoxHighlightPainter;
7import cuchaz.enigma.gui.highlight.ObfuscatedHighlightPainter;
8import cuchaz.enigma.gui.highlight.OtherHighlightPainter;
9import de.sciss.syntaxpane.DefaultSyntaxKit; 7import de.sciss.syntaxpane.DefaultSyntaxKit;
10 8
11import javax.swing.*; 9import javax.swing.*;
12import java.awt.*;
13import java.io.IOException; 10import java.io.IOException;
14 11
15public class Themes { 12public class Themes {
@@ -27,12 +24,15 @@ public class Themes {
27 } catch (IOException e) { 24 } catch (IOException e) {
28 e.printStackTrace(); 25 e.printStackTrace();
29 } 26 }
30 MinecraftSyntaxKit.invalidate(); 27 EnigmaSyntaxKit.invalidate();
31 DefaultSyntaxKit.initKit(); 28 DefaultSyntaxKit.initKit();
32 DefaultSyntaxKit.registerContentType("text/minecraft", MinecraftSyntaxKit.class.getName()); 29 DefaultSyntaxKit.registerContentType("text/enigma-sources", EnigmaSyntaxKit.class.getName());
33 gui.obfuscatedHighlightPainter = new ObfuscatedHighlightPainter(); 30 gui.boxHighlightPainters = ImmutableMap.of(
34 gui.deobfuscatedHighlightPainter = new DeobfuscatedHighlightPainter(); 31 "obfuscated", BoxHighlightPainter.create(Config.getInstance().obfuscatedColor, Config.getInstance().obfuscatedColorOutline),
35 gui.otherHighlightPainter = new OtherHighlightPainter(); 32 "proposed", BoxHighlightPainter.create(Config.getInstance().proposedColor, Config.getInstance().proposedColorOutline),
33 "deobfuscated", BoxHighlightPainter.create(Config.getInstance().deobfuscatedColor, Config.getInstance().deobfuscatedColorOutline),
34 "other", BoxHighlightPainter.create(null, Config.getInstance().otherColorOutline)
35 );
36 gui.setEditorTheme(Config.getInstance().lookAndFeel); 36 gui.setEditorTheme(Config.getInstance().lookAndFeel);
37 SwingUtilities.updateComponentTreeUI(gui.getFrame()); 37 SwingUtilities.updateComponentTreeUI(gui.getFrame());
38 } 38 }
diff --git a/src/main/java/cuchaz/enigma/gui/CodeReader.java b/src/main/java/cuchaz/enigma/gui/CodeReader.java
index ac45b4a7..137c7303 100644
--- a/src/main/java/cuchaz/enigma/gui/CodeReader.java
+++ b/src/main/java/cuchaz/enigma/gui/CodeReader.java
@@ -143,6 +143,7 @@ public class CodeReader extends JEditorPane {
143 { 143 {
144 144
145 // decompile it 145 // decompile it
146
146 CompilationUnit sourceTree = deobfuscator.getSourceTree(classEntry.getOutermostClassName()); 147 CompilationUnit sourceTree = deobfuscator.getSourceTree(classEntry.getOutermostClassName());
147 String source = deobfuscator.getSource(sourceTree); 148 String source = deobfuscator.getSource(sourceTree);
148 setCode(source); 149 setCode(source);
diff --git a/src/main/java/cuchaz/enigma/gui/MinecraftSyntaxKit.java b/src/main/java/cuchaz/enigma/gui/EnigmaSyntaxKit.java
index d9fcee53..5ea0bc20 100644
--- a/src/main/java/cuchaz/enigma/gui/MinecraftSyntaxKit.java
+++ b/src/main/java/cuchaz/enigma/gui/EnigmaSyntaxKit.java
@@ -5,7 +5,7 @@ import de.sciss.syntaxpane.components.LineNumbersRuler;
5import de.sciss.syntaxpane.syntaxkits.JavaSyntaxKit; 5import de.sciss.syntaxpane.syntaxkits.JavaSyntaxKit;
6import de.sciss.syntaxpane.util.Configuration; 6import de.sciss.syntaxpane.util.Configuration;
7 7
8public class MinecraftSyntaxKit extends JavaSyntaxKit { 8public class EnigmaSyntaxKit extends JavaSyntaxKit {
9 private static Configuration configuration = null; 9 private static Configuration configuration = null;
10 10
11 @Override 11 @Override
diff --git a/src/main/java/cuchaz/enigma/gui/Gui.java b/src/main/java/cuchaz/enigma/gui/Gui.java
index 06e78420..8ec58f9e 100644
--- a/src/main/java/cuchaz/enigma/gui/Gui.java
+++ b/src/main/java/cuchaz/enigma/gui/Gui.java
@@ -22,9 +22,7 @@ import cuchaz.enigma.gui.elements.MenuBar;
22import cuchaz.enigma.gui.elements.PopupMenuBar; 22import cuchaz.enigma.gui.elements.PopupMenuBar;
23import cuchaz.enigma.gui.filechooser.FileChooserAny; 23import cuchaz.enigma.gui.filechooser.FileChooserAny;
24import cuchaz.enigma.gui.filechooser.FileChooserFolder; 24import cuchaz.enigma.gui.filechooser.FileChooserFolder;
25import cuchaz.enigma.gui.highlight.DeobfuscatedHighlightPainter; 25import cuchaz.enigma.gui.highlight.BoxHighlightPainter;
26import cuchaz.enigma.gui.highlight.ObfuscatedHighlightPainter;
27import cuchaz.enigma.gui.highlight.OtherHighlightPainter;
28import cuchaz.enigma.gui.highlight.SelectionHighlightPainter; 26import cuchaz.enigma.gui.highlight.SelectionHighlightPainter;
29import cuchaz.enigma.gui.node.ClassSelectorPackageNode; 27import cuchaz.enigma.gui.node.ClassSelectorPackageNode;
30import cuchaz.enigma.gui.panels.PanelDeobf; 28import cuchaz.enigma.gui.panels.PanelDeobf;
@@ -48,10 +46,8 @@ import java.awt.*;
48import java.awt.event.*; 46import java.awt.event.*;
49import java.io.File; 47import java.io.File;
50import java.io.IOException; 48import java.io.IOException;
51import java.util.Collection; 49import java.util.*;
52import java.util.Collections;
53import java.util.List; 50import java.util.List;
54import java.util.Vector;
55import java.util.function.Function; 51import java.util.function.Function;
56 52
57public class Gui { 53public class Gui {
@@ -75,9 +71,7 @@ public class Gui {
75 private JPanel classesPanel; 71 private JPanel classesPanel;
76 private JSplitPane splitClasses; 72 private JSplitPane splitClasses;
77 private PanelIdentifier infoPanel; 73 private PanelIdentifier infoPanel;
78 public ObfuscatedHighlightPainter obfuscatedHighlightPainter; 74 public Map<String, BoxHighlightPainter> boxHighlightPainters;
79 public DeobfuscatedHighlightPainter deobfuscatedHighlightPainter;
80 public OtherHighlightPainter otherHighlightPainter;
81 private SelectionHighlightPainter selectionHighlightPainter; 75 private SelectionHighlightPainter selectionHighlightPainter;
82 private JTree inheritanceTree; 76 private JTree inheritanceTree;
83 private JTree implementationsTree; 77 private JTree implementationsTree;
@@ -145,7 +139,7 @@ public class Gui {
145 selectionHighlightPainter = new SelectionHighlightPainter(); 139 selectionHighlightPainter = new SelectionHighlightPainter();
146 this.editor = new PanelEditor(this); 140 this.editor = new PanelEditor(this);
147 JScrollPane sourceScroller = new JScrollPane(this.editor); 141 JScrollPane sourceScroller = new JScrollPane(this.editor);
148 this.editor.setContentType("text/minecraft"); 142 this.editor.setContentType("text/enigma-sources");
149 this.editor.setBackground(new Color(Config.getInstance().editorBackground)); 143 this.editor.setBackground(new Color(Config.getInstance().editorBackground));
150 DefaultSyntaxKit kit = (DefaultSyntaxKit) this.editor.getEditorKit(); 144 DefaultSyntaxKit kit = (DefaultSyntaxKit) this.editor.getEditorKit();
151 kit.toggleComponent(this.editor, "de.sciss.syntaxpane.components.TokenMarker"); 145 kit.toggleComponent(this.editor, "de.sciss.syntaxpane.components.TokenMarker");
@@ -311,11 +305,11 @@ public class Gui {
311 return this.controller; 305 return this.controller;
312 } 306 }
313 307
314 public void onStartOpenJar() { 308 public void onStartOpenJar(String message) {
315 this.classesPanel.removeAll(); 309 this.classesPanel.removeAll();
316 JPanel panel = new JPanel(); 310 JPanel panel = new JPanel();
317 panel.setLayout(new FlowLayout()); 311 panel.setLayout(new FlowLayout());
318 panel.add(new JLabel("Loading...")); 312 panel.add(new JLabel(message));
319 this.classesPanel.add(panel); 313 this.classesPanel.add(panel);
320 314
321 redraw(); 315 redraw();
@@ -407,20 +401,17 @@ public class Gui {
407 showToken(sortedTokens.get(0)); 401 showToken(sortedTokens.get(0));
408 } 402 }
409 403
410 public void setHighlightedTokens(Iterable<Token> obfuscatedTokens, Iterable<Token> deobfuscatedTokens, Iterable<Token> otherTokens) { 404 public void setHighlightedTokens(Map<String, Iterable<Token>> tokens) {
411
412 // remove any old highlighters 405 // remove any old highlighters
413 this.editor.getHighlighter().removeAllHighlights(); 406 this.editor.getHighlighter().removeAllHighlights();
414 407
415 // color things based on the index 408 if (boxHighlightPainters != null) {
416 if (obfuscatedTokens != null) { 409 for (String s : tokens.keySet()) {
417 setHighlightedTokens(obfuscatedTokens, obfuscatedHighlightPainter); 410 BoxHighlightPainter painter = boxHighlightPainters.get(s);
418 } 411 if (painter != null) {
419 if (deobfuscatedTokens != null) { 412 setHighlightedTokens(tokens.get(s), painter);
420 setHighlightedTokens(deobfuscatedTokens, deobfuscatedHighlightPainter); 413 }
421 } 414 }
422 if (otherTokens != null) {
423 setHighlightedTokens(otherTokens, otherHighlightPainter);
424 } 415 }
425 416
426 redraw(); 417 redraw();
@@ -582,7 +573,7 @@ public class Gui {
582 573
583 // init the text box 574 // init the text box
584 final JTextField text = new JTextField(); 575 final JTextField text = new JTextField();
585 text.setText(reference.getNamableName()); 576 text.setText(reference.getNameableName());
586 text.setPreferredSize(new Dimension(360, text.getPreferredSize().height)); 577 text.setPreferredSize(new Dimension(360, text.getPreferredSize().height));
587 text.addKeyListener(new KeyAdapter() { 578 text.addKeyListener(new KeyAdapter() {
588 @Override 579 @Override
@@ -633,7 +624,7 @@ public class Gui {
633 // abort the rename 624 // abort the rename
634 JPanel panel = (JPanel) infoPanel.getComponent(0); 625 JPanel panel = (JPanel) infoPanel.getComponent(0);
635 panel.remove(panel.getComponentCount() - 1); 626 panel.remove(panel.getComponentCount() - 1);
636 panel.add(Utils.unboldLabel(new JLabel(reference.getNamableName(), JLabel.LEFT))); 627 panel.add(Utils.unboldLabel(new JLabel(reference.getNameableName(), JLabel.LEFT)));
637 628
638 this.editor.grabFocus(); 629 this.editor.grabFocus();
639 630
diff --git a/src/main/java/cuchaz/enigma/gui/GuiController.java b/src/main/java/cuchaz/enigma/gui/GuiController.java
index 6e15bb02..e2f332d0 100644
--- a/src/main/java/cuchaz/enigma/gui/GuiController.java
+++ b/src/main/java/cuchaz/enigma/gui/GuiController.java
@@ -11,13 +11,14 @@
11 11
12package cuchaz.enigma.gui; 12package cuchaz.enigma.gui;
13 13
14import com.google.common.collect.ImmutableMap;
14import com.google.common.collect.Lists; 15import com.google.common.collect.Lists;
15import com.google.common.collect.Queues; 16import com.google.common.collect.Queues;
16import com.strobel.decompiler.languages.java.ast.CompilationUnit; 17import com.strobel.decompiler.languages.java.ast.CompilationUnit;
17import cuchaz.enigma.Deobfuscator; 18import cuchaz.enigma.Deobfuscator;
18import cuchaz.enigma.analysis.*; 19import cuchaz.enigma.analysis.*;
20import cuchaz.enigma.api.EnigmaPlugin;
19import cuchaz.enigma.config.Config; 21import cuchaz.enigma.config.Config;
20import cuchaz.enigma.config.Themes;
21import cuchaz.enigma.gui.dialog.ProgressDialog; 22import cuchaz.enigma.gui.dialog.ProgressDialog;
22import cuchaz.enigma.mapping.*; 23import cuchaz.enigma.mapping.*;
23import cuchaz.enigma.mapping.entry.ClassEntry; 24import cuchaz.enigma.mapping.entry.ClassEntry;
@@ -30,9 +31,7 @@ import cuchaz.enigma.utils.ReadableToken;
30import java.awt.event.ItemEvent; 31import java.awt.event.ItemEvent;
31import java.io.File; 32import java.io.File;
32import java.io.IOException; 33import java.io.IOException;
33import java.util.Collection; 34import java.util.*;
34import java.util.Deque;
35import java.util.List;
36import java.util.jar.JarFile; 35import java.util.jar.JarFile;
37 36
38public class GuiController { 37public class GuiController {
@@ -58,8 +57,10 @@ public class GuiController {
58 } 57 }
59 58
60 public void openJar(final JarFile jar) throws IOException { 59 public void openJar(final JarFile jar) throws IOException {
61 this.gui.onStartOpenJar(); 60 this.gui.onStartOpenJar("Loading JAR...");
62 this.deobfuscator = new Deobfuscator(jar); 61 this.deobfuscator = new Deobfuscator(jar, (msg) -> {
62 this.gui.onStartOpenJar(msg);
63 });
63 this.gui.onFinishOpenJar(jar.getName()); 64 this.gui.onFinishOpenJar(jar.getName());
64 refreshClasses(); 65 refreshClasses();
65 } 66 }
@@ -162,7 +163,7 @@ public class GuiController {
162 } 163 }
163 164
164 public boolean referenceIsRenameable(EntryReference<Entry, Entry> deobfReference) { 165 public boolean referenceIsRenameable(EntryReference<Entry, Entry> deobfReference) {
165 return this.deobfuscator.isRenameable(this.deobfuscator.obfuscateReference(deobfReference), true); 166 return this.deobfuscator.isRenameable(this.deobfuscator.obfuscateReference(deobfReference));
166 } 167 }
167 168
168 public ClassInheritanceTreeNode getClassInheritance(ClassEntry deobfClassEntry) { 169 public ClassInheritanceTreeNode getClassInheritance(ClassEntry deobfClassEntry) {
@@ -334,29 +335,73 @@ public class GuiController {
334 } 335 }
335 String source = deobfuscator.getSource(sourceTree); 336 String source = deobfuscator.getSource(sourceTree);
336 index = deobfuscator.getSourceIndex(sourceTree, source); 337 index = deobfuscator.getSourceIndex(sourceTree, source);
337 gui.setSource(index.getSource()); 338
338 if (obfReference != null) { 339 String sourceString = index.getSource();
339 showReference(obfReference);
340 }
341 340
342 // set the highlighted tokens 341 // set the highlighted tokens
343 List<Token> obfuscatedTokens = Lists.newArrayList(); 342 List<Token> obfuscatedTokens = Lists.newArrayList();
343 List<Token> proposedTokens = Lists.newArrayList();
344 List<Token> deobfuscatedTokens = Lists.newArrayList(); 344 List<Token> deobfuscatedTokens = Lists.newArrayList();
345 List<Token> otherTokens = Lists.newArrayList(); 345 List<Token> otherTokens = Lists.newArrayList();
346 for (Token token : index.referenceTokens()) { 346
347 EntryReference<Entry, Entry> reference = index.getDeobfReference(token); 347 int offset = 0;
348 Map<Token, Token> tokenRemap = new IdentityHashMap<>();
349 boolean remapped = false;
350
351 for (Token inToken : index.referenceTokens()) {
352 EntryReference<Entry, Entry> reference = index.getDeobfReference(inToken);
353 Token token = inToken.move(offset);
354
348 if (referenceIsRenameable(reference)) { 355 if (referenceIsRenameable(reference)) {
349 if (entryHasDeobfuscatedName(reference.getNameableEntry())) { 356 boolean renamed = false;
350 deobfuscatedTokens.add(token); 357
351 } else { 358 if (!entryHasDeobfuscatedName(reference.getNameableEntry())) {
352 obfuscatedTokens.add(token); 359 Entry obfEntry = deobfuscator.obfuscateEntry(reference.getNameableEntry());
360 if (obfEntry instanceof FieldEntry) {
361 for (EnigmaPlugin plugin : deobfuscator.getPlugins()) {
362 String proposal = plugin.proposeFieldName(obfEntry.getClassName(), obfEntry.getName(), ((FieldEntry) obfEntry).getDesc().toString());
363 if (proposal != null) {
364 proposedTokens.add(token);
365 offset += token.getRenameOffset(proposal);
366 sourceString = token.rename(sourceString, proposal);
367 renamed = true;
368 remapped = true;
369 break;
370 }
371 }
372 }
373 }
374
375 if (!renamed) {
376 if (entryHasDeobfuscatedName(reference.getNameableEntry())) {
377 deobfuscatedTokens.add(token);
378 } else {
379 obfuscatedTokens.add(token);
380 }
353 } 381 }
354 } else { 382 } else {
355 otherTokens.add(token); 383 otherTokens.add(token);
356 } 384 }
385
386 tokenRemap.put(inToken, token);
387 }
388
389 if (remapped) {
390 index.remap(sourceString, tokenRemap);
391 }
392
393 gui.setSource(sourceString);
394 if (obfReference != null) {
395 showReference(obfReference);
357 } 396 }
397
358 gui.setEditorTheme(Config.getInstance().lookAndFeel); 398 gui.setEditorTheme(Config.getInstance().lookAndFeel);
359 gui.setHighlightedTokens(obfuscatedTokens, deobfuscatedTokens, otherTokens); 399 gui.setHighlightedTokens(ImmutableMap.of(
400 "obfuscated", obfuscatedTokens,
401 "proposed", proposedTokens,
402 "deobfuscated", deobfuscatedTokens,
403 "other", otherTokens
404 ));
360 }).start(); 405 }).start();
361 } 406 }
362 407
diff --git a/src/main/java/cuchaz/enigma/gui/highlight/BoxHighlightPainter.java b/src/main/java/cuchaz/enigma/gui/highlight/BoxHighlightPainter.java
index 976c215e..10366ced 100644
--- a/src/main/java/cuchaz/enigma/gui/highlight/BoxHighlightPainter.java
+++ b/src/main/java/cuchaz/enigma/gui/highlight/BoxHighlightPainter.java
@@ -11,13 +11,14 @@
11 11
12package cuchaz.enigma.gui.highlight; 12package cuchaz.enigma.gui.highlight;
13 13
14import cuchaz.enigma.config.Config;
15
14import javax.swing.text.BadLocationException; 16import javax.swing.text.BadLocationException;
15import javax.swing.text.Highlighter; 17import javax.swing.text.Highlighter;
16import javax.swing.text.JTextComponent; 18import javax.swing.text.JTextComponent;
17import java.awt.*; 19import java.awt.*;
18 20
19public abstract class BoxHighlightPainter implements Highlighter.HighlightPainter { 21public class BoxHighlightPainter implements Highlighter.HighlightPainter {
20
21 private Color fillColor; 22 private Color fillColor;
22 private Color borderColor; 23 private Color borderColor;
23 24
@@ -26,6 +27,10 @@ public abstract class BoxHighlightPainter implements Highlighter.HighlightPainte
26 this.borderColor = borderColor; 27 this.borderColor = borderColor;
27 } 28 }
28 29
30 public static BoxHighlightPainter create(Config.AlphaColorEntry entry, Config.AlphaColorEntry entryOutline) {
31 return new BoxHighlightPainter(entry != null ? entry.get() : null, entryOutline != null ? entryOutline.get() : null);
32 }
33
29 public static Rectangle getBounds(JTextComponent text, int start, int end) { 34 public static Rectangle getBounds(JTextComponent text, int start, int end) {
30 try { 35 try {
31 // determine the bounds of the text 36 // determine the bounds of the text
@@ -59,8 +64,4 @@ public abstract class BoxHighlightPainter implements Highlighter.HighlightPainte
59 g.drawRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4); 64 g.drawRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 4, 4);
60 } 65 }
61 66
62 protected static Color getColor(int rgb, float alpha){
63 Color baseColor = new Color(rgb);
64 return new Color(baseColor.getRed(), baseColor.getGreen(), baseColor.getBlue(), (int)(255 * alpha));
65 }
66} 67}
diff --git a/src/main/java/cuchaz/enigma/gui/highlight/DeobfuscatedHighlightPainter.java b/src/main/java/cuchaz/enigma/gui/highlight/DeobfuscatedHighlightPainter.java
deleted file mode 100644
index 41aa97f8..00000000
--- a/src/main/java/cuchaz/enigma/gui/highlight/DeobfuscatedHighlightPainter.java
+++ /dev/null
@@ -1,21 +0,0 @@
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 ******************************************************************************/
11
12package cuchaz.enigma.gui.highlight;
13
14import cuchaz.enigma.config.Config;
15
16public class DeobfuscatedHighlightPainter extends BoxHighlightPainter {
17
18 public DeobfuscatedHighlightPainter() {
19 super(getColor(Config.getInstance().deobfuscatedColor, Config.getInstance().deobfuscatedHiglightAlpha), getColor(Config.getInstance().deobfuscatedColorOutline, Config.getInstance().deobfuscatedOutlineAlpha));
20 }
21}
diff --git a/src/main/java/cuchaz/enigma/gui/highlight/ObfuscatedHighlightPainter.java b/src/main/java/cuchaz/enigma/gui/highlight/ObfuscatedHighlightPainter.java
deleted file mode 100644
index d7358743..00000000
--- a/src/main/java/cuchaz/enigma/gui/highlight/ObfuscatedHighlightPainter.java
+++ /dev/null
@@ -1,21 +0,0 @@
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 ******************************************************************************/
11
12package cuchaz.enigma.gui.highlight;
13
14import cuchaz.enigma.config.Config;
15
16public class ObfuscatedHighlightPainter extends BoxHighlightPainter {
17
18 public ObfuscatedHighlightPainter() {
19 super(getColor(Config.getInstance().obfuscatedColor, Config.getInstance().obfuscatedHiglightAlpha), getColor(Config.getInstance().obfuscatedColorOutline, Config.getInstance().obfuscatedOutlineAlpha));
20 }
21}
diff --git a/src/main/java/cuchaz/enigma/gui/highlight/OtherHighlightPainter.java b/src/main/java/cuchaz/enigma/gui/highlight/OtherHighlightPainter.java
deleted file mode 100644
index f4ae235a..00000000
--- a/src/main/java/cuchaz/enigma/gui/highlight/OtherHighlightPainter.java
+++ /dev/null
@@ -1,21 +0,0 @@
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 ******************************************************************************/
11
12package cuchaz.enigma.gui.highlight;
13
14import cuchaz.enigma.config.Config;
15
16public class OtherHighlightPainter extends BoxHighlightPainter {
17
18 public OtherHighlightPainter() {
19 super(null, getColor(Config.getInstance().otherColorOutline, Config.getInstance().otherOutlineAlpha));
20 }
21}
diff --git a/src/main/java/cuchaz/enigma/mapping/DirectionalTranslator.java b/src/main/java/cuchaz/enigma/mapping/DirectionalTranslator.java
index 99a63154..10fb9215 100644
--- a/src/main/java/cuchaz/enigma/mapping/DirectionalTranslator.java
+++ b/src/main/java/cuchaz/enigma/mapping/DirectionalTranslator.java
@@ -20,6 +20,7 @@ import cuchaz.enigma.mapping.entry.*;
20import java.util.ArrayList; 20import java.util.ArrayList;
21import java.util.List; 21import java.util.List;
22import java.util.Map; 22import java.util.Map;
23import java.util.ServiceLoader;
23 24
24public class DirectionalTranslator implements Translator { 25public class DirectionalTranslator implements Translator {
25 private final TranslationDirection direction; 26 private final TranslationDirection direction;
diff --git a/src/main/java/cuchaz/enigma/mapping/Mappings.java b/src/main/java/cuchaz/enigma/mapping/Mappings.java
index 3ef1be52..c8650795 100644
--- a/src/main/java/cuchaz/enigma/mapping/Mappings.java
+++ b/src/main/java/cuchaz/enigma/mapping/Mappings.java
@@ -15,6 +15,7 @@ import com.google.common.collect.Lists;
15import com.google.common.collect.Maps; 15import com.google.common.collect.Maps;
16import com.google.common.collect.Sets; 16import com.google.common.collect.Sets;
17import cuchaz.enigma.analysis.TranslationIndex; 17import cuchaz.enigma.analysis.TranslationIndex;
18import cuchaz.enigma.api.EnigmaPlugin;
18import cuchaz.enigma.bytecode.AccessFlags; 19import cuchaz.enigma.bytecode.AccessFlags;
19import cuchaz.enigma.mapping.entry.ClassEntry; 20import cuchaz.enigma.mapping.entry.ClassEntry;
20import cuchaz.enigma.mapping.entry.MethodEntry; 21import cuchaz.enigma.mapping.entry.MethodEntry;