summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar jeff2015-03-09 12:53:11 -0400
committerGravatar jeff2015-03-09 12:53:11 -0400
commitd6b2a223a7973941e5e4fb45c8ceec4885891496 (patch)
tree5728ab513d0b4ed85a720da7eb48c6591dd3f8b0 /src
parentadd tracking for mismatched fields/methods (diff)
downloadenigma-d6b2a223a7973941e5e4fb45c8ceec4885891496.tar.gz
enigma-d6b2a223a7973941e5e4fb45c8ceec4885891496.tar.xz
enigma-d6b2a223a7973941e5e4fb45c8ceec4885891496.zip
starting on field matching gui
Diffstat (limited to 'src')
-rw-r--r--src/cuchaz/enigma/ConvertMain.java136
-rw-r--r--src/cuchaz/enigma/convert/ClassMatches.java (renamed from src/cuchaz/enigma/convert/Matches.java)6
-rw-r--r--src/cuchaz/enigma/convert/FieldMatches.java35
-rw-r--r--src/cuchaz/enigma/convert/MappingsConverter.java8
-rw-r--r--src/cuchaz/enigma/convert/MatchesReader.java8
-rw-r--r--src/cuchaz/enigma/convert/MatchesWriter.java6
-rw-r--r--src/cuchaz/enigma/gui/ClassMatchingGui.java145
-rw-r--r--src/cuchaz/enigma/gui/CodeReader.java164
-rw-r--r--src/cuchaz/enigma/gui/FieldMatchingGui.java131
-rw-r--r--src/cuchaz/enigma/gui/Gui.java2
-rw-r--r--src/cuchaz/enigma/gui/GuiTricks.java58
11 files changed, 495 insertions, 204 deletions
diff --git a/src/cuchaz/enigma/ConvertMain.java b/src/cuchaz/enigma/ConvertMain.java
index 2afd9ca9..624eb40a 100644
--- a/src/cuchaz/enigma/ConvertMain.java
+++ b/src/cuchaz/enigma/ConvertMain.java
@@ -6,14 +6,16 @@ import java.io.FileWriter;
6import java.io.IOException; 6import java.io.IOException;
7import java.util.jar.JarFile; 7import java.util.jar.JarFile;
8 8
9import cuchaz.enigma.convert.ClassMatches;
10import cuchaz.enigma.convert.FieldMatches;
9import cuchaz.enigma.convert.MappingsConverter; 11import cuchaz.enigma.convert.MappingsConverter;
10import cuchaz.enigma.convert.Matches;
11import cuchaz.enigma.convert.MatchesReader; 12import cuchaz.enigma.convert.MatchesReader;
12import cuchaz.enigma.convert.MatchesWriter; 13import cuchaz.enigma.convert.MatchesWriter;
13import cuchaz.enigma.gui.ClassMatchingGui; 14import cuchaz.enigma.gui.ClassMatchingGui;
14import cuchaz.enigma.gui.ClassMatchingGui.SaveListener; 15import cuchaz.enigma.gui.FieldMatchingGui;
15import cuchaz.enigma.mapping.MappingParseException; 16import cuchaz.enigma.mapping.MappingParseException;
16import cuchaz.enigma.mapping.Mappings; 17import cuchaz.enigma.mapping.Mappings;
18import cuchaz.enigma.mapping.MappingsChecker;
17import cuchaz.enigma.mapping.MappingsReader; 19import cuchaz.enigma.mapping.MappingsReader;
18import cuchaz.enigma.mapping.MappingsWriter; 20import cuchaz.enigma.mapping.MappingsWriter;
19 21
@@ -30,11 +32,13 @@ public class ConvertMain {
30 File inMappingsFile = new File("../Enigma Mappings/1.8.mappings"); 32 File inMappingsFile = new File("../Enigma Mappings/1.8.mappings");
31 File outMappingsFile = new File("../Enigma Mappings/1.8.3.mappings"); 33 File outMappingsFile = new File("../Enigma Mappings/1.8.3.mappings");
32 Mappings mappings = new MappingsReader().read(new FileReader(inMappingsFile)); 34 Mappings mappings = new MappingsReader().read(new FileReader(inMappingsFile));
33 File matchingFile = new File(inMappingsFile.getName() + ".matching"); 35 File classMatchingFile = new File(inMappingsFile.getName() + ".class.matching");
36 File fieldMatchingFile = new File(inMappingsFile.getName() + ".field.matching");
34 37
35 //computeMatches(matchingFile, sourceJar, destJar, mappings); 38 //computeMatches(classMatchingFile, sourceJar, destJar, mappings);
36 editMatches(matchingFile, sourceJar, destJar, mappings); 39 //editClasssMatches(classMatchingFile, sourceJar, destJar, mappings);
37 //convertMappings(outMappingsFile, sourceJar, destJar, mappings, matchingFile); 40 //convertMappings(outMappingsFile, sourceJar, destJar, mappings, classMatchingFile);
41 editFieldMatches(sourceJar, destJar, outMappingsFile, mappings, classMatchingFile, fieldMatchingFile);
38 42
39 /* TODO 43 /* TODO
40 // write out the converted mappings 44 // write out the converted mappings
@@ -45,28 +49,25 @@ public class ConvertMain {
45 */ 49 */
46 } 50 }
47 51
48 private static void computeMatches(File matchingFile, JarFile sourceJar, JarFile destJar, Mappings mappings) 52 private static void computeMatches(File classMatchingFile, JarFile sourceJar, JarFile destJar, Mappings mappings)
49 throws IOException { 53 throws IOException {
50 Matches matches = MappingsConverter.computeMatches(sourceJar, destJar, mappings); 54 ClassMatches classMatches = MappingsConverter.computeMatches(sourceJar, destJar, mappings);
51 MatchesWriter.write(matches, matchingFile); 55 MatchesWriter.writeClasses(classMatches, classMatchingFile);
52 System.out.println("Wrote:\n\t" + matchingFile.getAbsolutePath()); 56 System.out.println("Wrote:\n\t" + classMatchingFile.getAbsolutePath());
53 } 57 }
54 58
55 private static void editMatches(final File matchingFile, JarFile sourceJar, JarFile destJar, Mappings mappings) 59 private static void editClasssMatches(final File classMatchingFile, JarFile sourceJar, JarFile destJar, Mappings mappings)
56 throws IOException { 60 throws IOException {
57 System.out.println("Reading matches..."); 61 System.out.println("Reading matches...");
58 Matches matches = MatchesReader.read(matchingFile); 62 ClassMatches classMatches = MatchesReader.readClasses(classMatchingFile);
59 System.out.println("Indexing source jar..."); 63 Deobfuscators deobfuscators = new Deobfuscators(sourceJar, destJar);
60 Deobfuscator sourceDeobfuscator = new Deobfuscator(sourceJar); 64 deobfuscators.source.setMappings(mappings);
61 sourceDeobfuscator.setMappings(mappings);
62 System.out.println("Indexing dest jar...");
63 Deobfuscator destDeobfuscator = new Deobfuscator(destJar);
64 System.out.println("Starting GUI..."); 65 System.out.println("Starting GUI...");
65 new ClassMatchingGui(matches, sourceDeobfuscator, destDeobfuscator).setSaveListener(new SaveListener() { 66 new ClassMatchingGui(classMatches, deobfuscators.source, deobfuscators.dest).setSaveListener(new ClassMatchingGui.SaveListener() {
66 @Override 67 @Override
67 public void save(Matches matches) { 68 public void save(ClassMatches matches) {
68 try { 69 try {
69 MatchesWriter.write(matches, matchingFile); 70 MatchesWriter.writeClasses(matches, classMatchingFile);
70 } catch (IOException ex) { 71 } catch (IOException ex) {
71 throw new Error(ex); 72 throw new Error(ex);
72 } 73 }
@@ -74,21 +75,100 @@ public class ConvertMain {
74 }); 75 });
75 } 76 }
76 77
77 private static void convertMappings(File outMappingsFile, JarFile sourceJar, JarFile destJar, Mappings mappings, File matchingFile) 78 private static void convertMappings(File outMappingsFile, JarFile sourceJar, JarFile destJar, Mappings mappings, File classMatchingFile)
78 throws IOException { 79 throws IOException {
79 System.out.println("Reading matches..."); 80 System.out.println("Reading matches...");
80 Matches matches = MatchesReader.read(matchingFile); 81 ClassMatches classMatches = MatchesReader.readClasses(classMatchingFile);
81 System.out.println("Indexing source jar..."); 82 Deobfuscators deobfuscators = new Deobfuscators(sourceJar, destJar);
82 Deobfuscator sourceDeobfuscator = new Deobfuscator(sourceJar); 83 deobfuscators.source.setMappings(mappings);
83 sourceDeobfuscator.setMappings(mappings);
84 System.out.println("Indexing dest jar...");
85 Deobfuscator destDeobfuscator = new Deobfuscator(destJar);
86 84
87 Mappings newMappings = MappingsConverter.newMappings(matches, mappings, sourceDeobfuscator, destDeobfuscator); 85 Mappings newMappings = MappingsConverter.newMappings(classMatches, mappings, deobfuscators.source, deobfuscators.source);
88 86
89 try (FileWriter out = new FileWriter(outMappingsFile)) { 87 try (FileWriter out = new FileWriter(outMappingsFile)) {
90 new MappingsWriter().write(out, newMappings); 88 new MappingsWriter().write(out, newMappings);
91 } 89 }
92 System.out.println("Write converted mappings to: " + outMappingsFile.getAbsolutePath()); 90 System.out.println("Write converted mappings to: " + outMappingsFile.getAbsolutePath());
93 } 91 }
92
93 private static void editFieldMatches(JarFile sourceJar, JarFile destJar, File destMappingsFile, Mappings sourceMappings, File classMatchingFile, final File fieldMatchingFile)
94 throws IOException, MappingParseException {
95
96 System.out.println("Reading matches...");
97 ClassMatches classMatches = MatchesReader.readClasses(classMatchingFile);
98 FieldMatches fieldMatches;
99 if (fieldMatchingFile.exists() /* TEMP */ && false) {
100 // TODO
101 //fieldMatches = MatchesReader.readFields(fieldMatchingFile);
102 } else {
103 fieldMatches = new FieldMatches();
104 }
105
106 // prep deobfuscators
107 Deobfuscators deobfuscators = new Deobfuscators(sourceJar, destJar);
108 deobfuscators.source.setMappings(sourceMappings);
109 Mappings destMappings = new MappingsReader().read(new FileReader(destMappingsFile));
110 MappingsChecker checker = new MappingsChecker(deobfuscators.dest.getJarIndex());
111 checker.dropBrokenMappings(destMappings);
112 deobfuscators.dest.setMappings(destMappings);
113
114 new FieldMatchingGui(classMatches, fieldMatches, checker.getDroppedFieldMappings(), deobfuscators.source, deobfuscators.dest).setSaveListener(new FieldMatchingGui.SaveListener() {
115 @Override
116 public void save(FieldMatches matches) {
117 /* TODO
118 try {
119 MatchesWriter.writeFields(matches, fieldMatchingFile);
120 } catch (IOException ex) {
121 throw new Error(ex);
122 }
123 */
124 }
125 });
126 }
127
128 private static class Deobfuscators {
129
130 public Deobfuscator source;
131 public Deobfuscator dest;
132
133 public Deobfuscators(JarFile sourceJar, JarFile destJar) {
134 System.out.println("Indexing source jar...");
135 IndexerThread sourceIndexer = new IndexerThread(sourceJar);
136 sourceIndexer.start();
137 System.out.println("Indexing dest jar...");
138 IndexerThread destIndexer = new IndexerThread(destJar);
139 destIndexer.start();
140 sourceIndexer.joinOrBail();
141 destIndexer.joinOrBail();
142 source = sourceIndexer.deobfuscator;
143 dest = destIndexer.deobfuscator;
144 }
145 }
146
147 private static class IndexerThread extends Thread {
148
149 private JarFile m_jarFile;
150 public Deobfuscator deobfuscator;
151
152 public IndexerThread(JarFile jarFile) {
153 m_jarFile = jarFile;
154 deobfuscator = null;
155 }
156
157 public void joinOrBail() {
158 try {
159 join();
160 } catch (InterruptedException ex) {
161 throw new Error(ex);
162 }
163 }
164
165 @Override
166 public void run() {
167 try {
168 deobfuscator = new Deobfuscator(m_jarFile);
169 } catch (IOException ex) {
170 throw new Error(ex);
171 }
172 }
173 }
94} 174}
diff --git a/src/cuchaz/enigma/convert/Matches.java b/src/cuchaz/enigma/convert/ClassMatches.java
index 19bb155f..f8b2afdc 100644
--- a/src/cuchaz/enigma/convert/Matches.java
+++ b/src/cuchaz/enigma/convert/ClassMatches.java
@@ -14,7 +14,7 @@ import com.google.common.collect.Sets;
14import cuchaz.enigma.mapping.ClassEntry; 14import cuchaz.enigma.mapping.ClassEntry;
15 15
16 16
17public class Matches implements Iterable<ClassMatch> { 17public class ClassMatches implements Iterable<ClassMatch> {
18 18
19 Collection<ClassMatch> m_matches; 19 Collection<ClassMatch> m_matches;
20 Map<ClassEntry,ClassMatch> m_matchesBySource; 20 Map<ClassEntry,ClassMatch> m_matchesBySource;
@@ -25,11 +25,11 @@ public class Matches implements Iterable<ClassMatch> {
25 Set<ClassEntry> m_unmatchedSourceClasses; 25 Set<ClassEntry> m_unmatchedSourceClasses;
26 Set<ClassEntry> m_unmatchedDestClasses; 26 Set<ClassEntry> m_unmatchedDestClasses;
27 27
28 public Matches() { 28 public ClassMatches() {
29 this(new ArrayList<ClassMatch>()); 29 this(new ArrayList<ClassMatch>());
30 } 30 }
31 31
32 public Matches(Collection<ClassMatch> matches) { 32 public ClassMatches(Collection<ClassMatch> matches) {
33 m_matches = matches; 33 m_matches = matches;
34 m_matchesBySource = Maps.newHashMap(); 34 m_matchesBySource = Maps.newHashMap();
35 m_matchesByDest = Maps.newHashMap(); 35 m_matchesByDest = Maps.newHashMap();
diff --git a/src/cuchaz/enigma/convert/FieldMatches.java b/src/cuchaz/enigma/convert/FieldMatches.java
new file mode 100644
index 00000000..f78a8f55
--- /dev/null
+++ b/src/cuchaz/enigma/convert/FieldMatches.java
@@ -0,0 +1,35 @@
1package cuchaz.enigma.convert;
2
3import java.util.Collection;
4import java.util.Set;
5
6import com.google.common.collect.BiMap;
7import com.google.common.collect.HashBiMap;
8import com.google.common.collect.Sets;
9
10import cuchaz.enigma.mapping.ClassEntry;
11import cuchaz.enigma.mapping.FieldEntry;
12
13
14public class FieldMatches {
15
16 private BiMap<FieldEntry,FieldEntry> m_matches;
17 private Set<FieldEntry> m_unmatchedSourceFields;
18
19 public FieldMatches() {
20 m_matches = HashBiMap.create();
21 m_unmatchedSourceFields = Sets.newHashSet();
22 }
23
24 public void addUnmatchedSourceFields(Set<FieldEntry> fieldEntries) {
25 m_unmatchedSourceFields.addAll(fieldEntries);
26 }
27
28 public Collection<ClassEntry> getSourceClassesWithUnmatchedFields() {
29 Set<ClassEntry> classEntries = Sets.newHashSet();
30 for (FieldEntry fieldEntry : m_unmatchedSourceFields) {
31 classEntries.add(fieldEntry.getClassEntry());
32 }
33 return classEntries;
34 }
35}
diff --git a/src/cuchaz/enigma/convert/MappingsConverter.java b/src/cuchaz/enigma/convert/MappingsConverter.java
index 5883878c..667ee9de 100644
--- a/src/cuchaz/enigma/convert/MappingsConverter.java
+++ b/src/cuchaz/enigma/convert/MappingsConverter.java
@@ -37,7 +37,7 @@ import cuchaz.enigma.mapping.MethodMapping;
37 37
38public class MappingsConverter { 38public class MappingsConverter {
39 39
40 public static Matches computeMatches(JarFile sourceJar, JarFile destJar, Mappings mappings) { 40 public static ClassMatches computeMatches(JarFile sourceJar, JarFile destJar, Mappings mappings) {
41 41
42 // index jars 42 // index jars
43 System.out.println("Indexing source jar..."); 43 System.out.println("Indexing source jar...");
@@ -49,7 +49,7 @@ public class MappingsConverter {
49 49
50 // compute the matching 50 // compute the matching
51 ClassMatching matching = computeMatching(sourceJar, sourceIndex, destJar, destIndex, null); 51 ClassMatching matching = computeMatching(sourceJar, sourceIndex, destJar, destIndex, null);
52 return new Matches(matching.matches()); 52 return new ClassMatches(matching.matches());
53 } 53 }
54 54
55 public static ClassMatching computeMatching(JarFile sourceJar, JarIndex sourceIndex, JarFile destJar, JarIndex destIndex, BiMap<ClassEntry,ClassEntry> knownMatches) { 55 public static ClassMatching computeMatching(JarFile sourceJar, JarIndex sourceIndex, JarFile destJar, JarIndex destIndex, BiMap<ClassEntry,ClassEntry> knownMatches) {
@@ -115,7 +115,7 @@ public class MappingsConverter {
115 return lastMatching; 115 return lastMatching;
116 } 116 }
117 117
118 public static Mappings newMappings(Matches matches, Mappings oldMappings, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) { 118 public static Mappings newMappings(ClassMatches matches, Mappings oldMappings, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) {
119 119
120 // sort the unique matches by size of inner class chain 120 // sort the unique matches by size of inner class chain
121 Multimap<Integer,Entry<ClassEntry,ClassEntry>> matchesByDestChainSize = HashMultimap.create(); 121 Multimap<Integer,Entry<ClassEntry,ClassEntry>> matchesByDestChainSize = HashMultimap.create();
@@ -172,7 +172,7 @@ public class MappingsConverter {
172 return newMappings; 172 return newMappings;
173 } 173 }
174 174
175 private static ClassMapping migrateClassMapping(ClassEntry newObfClass, ClassMapping mapping, final Matches matches, boolean useSimpleName) { 175 private static ClassMapping migrateClassMapping(ClassEntry newObfClass, ClassMapping mapping, final ClassMatches matches, boolean useSimpleName) {
176 176
177 ClassNameReplacer replacer = new ClassNameReplacer() { 177 ClassNameReplacer replacer = new ClassNameReplacer() {
178 @Override 178 @Override
diff --git a/src/cuchaz/enigma/convert/MatchesReader.java b/src/cuchaz/enigma/convert/MatchesReader.java
index 808f8d0a..b43535cb 100644
--- a/src/cuchaz/enigma/convert/MatchesReader.java
+++ b/src/cuchaz/enigma/convert/MatchesReader.java
@@ -14,19 +14,19 @@ import cuchaz.enigma.mapping.ClassEntry;
14 14
15public class MatchesReader { 15public class MatchesReader {
16 16
17 public static Matches read(File file) 17 public static ClassMatches readClasses(File file)
18 throws IOException { 18 throws IOException {
19 try (BufferedReader in = new BufferedReader(new FileReader(file))) { 19 try (BufferedReader in = new BufferedReader(new FileReader(file))) {
20 Matches matches = new Matches(); 20 ClassMatches matches = new ClassMatches();
21 String line = null; 21 String line = null;
22 while ((line = in.readLine()) != null) { 22 while ((line = in.readLine()) != null) {
23 matches.add(readMatch(line)); 23 matches.add(readClassMatch(line));
24 } 24 }
25 return matches; 25 return matches;
26 } 26 }
27 } 27 }
28 28
29 private static ClassMatch readMatch(String line) 29 private static ClassMatch readClassMatch(String line)
30 throws IOException { 30 throws IOException {
31 String[] sides = line.split(":", 2); 31 String[] sides = line.split(":", 2);
32 return new ClassMatch(readClasses(sides[0]), readClasses(sides[1])); 32 return new ClassMatch(readClasses(sides[0]), readClasses(sides[1]));
diff --git a/src/cuchaz/enigma/convert/MatchesWriter.java b/src/cuchaz/enigma/convert/MatchesWriter.java
index 49ffb6d7..6658e2a3 100644
--- a/src/cuchaz/enigma/convert/MatchesWriter.java
+++ b/src/cuchaz/enigma/convert/MatchesWriter.java
@@ -9,16 +9,16 @@ import cuchaz.enigma.mapping.ClassEntry;
9 9
10public class MatchesWriter { 10public class MatchesWriter {
11 11
12 public static void write(Matches matches, File file) 12 public static void writeClasses(ClassMatches matches, File file)
13 throws IOException { 13 throws IOException {
14 try (FileWriter out = new FileWriter(file)) { 14 try (FileWriter out = new FileWriter(file)) {
15 for (ClassMatch match : matches) { 15 for (ClassMatch match : matches) {
16 writeMatch(out, match); 16 writeClassMatch(out, match);
17 } 17 }
18 } 18 }
19 } 19 }
20 20
21 private static void writeMatch(FileWriter out, ClassMatch match) 21 private static void writeClassMatch(FileWriter out, ClassMatch match)
22 throws IOException { 22 throws IOException {
23 writeClasses(out, match.sourceClasses); 23 writeClasses(out, match.sourceClasses);
24 out.write(":"); 24 out.write(":");
diff --git a/src/cuchaz/enigma/gui/ClassMatchingGui.java b/src/cuchaz/enigma/gui/ClassMatchingGui.java
index ff7cda99..b6744515 100644
--- a/src/cuchaz/enigma/gui/ClassMatchingGui.java
+++ b/src/cuchaz/enigma/gui/ClassMatchingGui.java
@@ -15,7 +15,6 @@ import javax.swing.BoxLayout;
15import javax.swing.ButtonGroup; 15import javax.swing.ButtonGroup;
16import javax.swing.JButton; 16import javax.swing.JButton;
17import javax.swing.JCheckBox; 17import javax.swing.JCheckBox;
18import javax.swing.JEditorPane;
19import javax.swing.JFrame; 18import javax.swing.JFrame;
20import javax.swing.JLabel; 19import javax.swing.JLabel;
21import javax.swing.JPanel; 20import javax.swing.JPanel;
@@ -28,22 +27,18 @@ import javax.swing.WindowConstants;
28import com.beust.jcommander.internal.Lists; 27import com.beust.jcommander.internal.Lists;
29import com.beust.jcommander.internal.Maps; 28import com.beust.jcommander.internal.Maps;
30import com.google.common.collect.BiMap; 29import com.google.common.collect.BiMap;
31import com.strobel.decompiler.languages.java.ast.CompilationUnit;
32 30
33import cuchaz.enigma.Constants; 31import cuchaz.enigma.Constants;
34import cuchaz.enigma.Deobfuscator; 32import cuchaz.enigma.Deobfuscator;
35import cuchaz.enigma.analysis.SourceIndex;
36import cuchaz.enigma.analysis.Token;
37import cuchaz.enigma.convert.ClassIdentifier; 33import cuchaz.enigma.convert.ClassIdentifier;
38import cuchaz.enigma.convert.ClassIdentity; 34import cuchaz.enigma.convert.ClassIdentity;
39import cuchaz.enigma.convert.ClassMatch; 35import cuchaz.enigma.convert.ClassMatch;
36import cuchaz.enigma.convert.ClassMatches;
40import cuchaz.enigma.convert.ClassMatching; 37import cuchaz.enigma.convert.ClassMatching;
41import cuchaz.enigma.convert.ClassNamer; 38import cuchaz.enigma.convert.ClassNamer;
42import cuchaz.enigma.convert.MappingsConverter; 39import cuchaz.enigma.convert.MappingsConverter;
43import cuchaz.enigma.convert.Matches;
44import cuchaz.enigma.gui.ClassSelector.ClassSelectionListener; 40import cuchaz.enigma.gui.ClassSelector.ClassSelectionListener;
45import cuchaz.enigma.mapping.ClassEntry; 41import cuchaz.enigma.mapping.ClassEntry;
46import cuchaz.enigma.mapping.Entry;
47import cuchaz.enigma.mapping.Mappings; 42import cuchaz.enigma.mapping.Mappings;
48import cuchaz.enigma.mapping.MappingsChecker; 43import cuchaz.enigma.mapping.MappingsChecker;
49import de.sciss.syntaxpane.DefaultSyntaxKit; 44import de.sciss.syntaxpane.DefaultSyntaxKit;
@@ -55,21 +50,21 @@ public class ClassMatchingGui {
55 Matched { 50 Matched {
56 51
57 @Override 52 @Override
58 public Collection<ClassEntry> getSourceClasses(Matches matches) { 53 public Collection<ClassEntry> getSourceClasses(ClassMatches matches) {
59 return matches.getUniqueMatches().keySet(); 54 return matches.getUniqueMatches().keySet();
60 } 55 }
61 }, 56 },
62 Unmatched { 57 Unmatched {
63 58
64 @Override 59 @Override
65 public Collection<ClassEntry> getSourceClasses(Matches matches) { 60 public Collection<ClassEntry> getSourceClasses(ClassMatches matches) {
66 return matches.getUnmatchedSourceClasses(); 61 return matches.getUnmatchedSourceClasses();
67 } 62 }
68 }, 63 },
69 Ambiguous { 64 Ambiguous {
70 65
71 @Override 66 @Override
72 public Collection<ClassEntry> getSourceClasses(Matches matches) { 67 public Collection<ClassEntry> getSourceClasses(ClassMatches matches) {
73 return matches.getAmbiguouslyMatchedSourceClasses(); 68 return matches.getAmbiguouslyMatchedSourceClasses();
74 } 69 }
75 }; 70 };
@@ -82,7 +77,7 @@ public class ClassMatchingGui {
82 return button; 77 return button;
83 } 78 }
84 79
85 public abstract Collection<ClassEntry> getSourceClasses(Matches matches); 80 public abstract Collection<ClassEntry> getSourceClasses(ClassMatches matches);
86 81
87 public static SourceType getDefault() { 82 public static SourceType getDefault() {
88 return values()[0]; 83 return values()[0];
@@ -90,23 +85,22 @@ public class ClassMatchingGui {
90 } 85 }
91 86
92 public static interface SaveListener { 87 public static interface SaveListener {
93 public void save(Matches matches); 88 public void save(ClassMatches matches);
94 } 89 }
95 90
96 // controls 91 // controls
97 private JFrame m_frame; 92 private JFrame m_frame;
98 private ClassSelector m_sourceClasses; 93 private ClassSelector m_sourceClasses;
99 private ClassSelector m_destClasses; 94 private ClassSelector m_destClasses;
100 private JEditorPane m_sourceReader; 95 private CodeReader m_sourceReader;
101 private JEditorPane m_destReader; 96 private CodeReader m_destReader;
102 private JLabel m_sourceClassLabel; 97 private JLabel m_sourceClassLabel;
103 private JLabel m_destClassLabel; 98 private JLabel m_destClassLabel;
104 private JButton m_matchButton; 99 private JButton m_matchButton;
105 private Map<SourceType,JRadioButton> m_sourceTypeButtons; 100 private Map<SourceType,JRadioButton> m_sourceTypeButtons;
106 private JCheckBox m_advanceCheck; 101 private JCheckBox m_advanceCheck;
107 private SelectionHighlightPainter m_selectionHighlightPainter;
108 102
109 private Matches m_matches; 103 private ClassMatches m_classMatches;
110 private Deobfuscator m_sourceDeobfuscator; 104 private Deobfuscator m_sourceDeobfuscator;
111 private Deobfuscator m_destDeobfuscator; 105 private Deobfuscator m_destDeobfuscator;
112 private ClassEntry m_sourceClass; 106 private ClassEntry m_sourceClass;
@@ -114,14 +108,14 @@ public class ClassMatchingGui {
114 private SourceType m_sourceType; 108 private SourceType m_sourceType;
115 private SaveListener m_saveListener; 109 private SaveListener m_saveListener;
116 110
117 public ClassMatchingGui(Matches matches, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) { 111 public ClassMatchingGui(ClassMatches matches, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) {
118 112
119 m_matches = matches; 113 m_classMatches = matches;
120 m_sourceDeobfuscator = sourceDeobfuscator; 114 m_sourceDeobfuscator = sourceDeobfuscator;
121 m_destDeobfuscator = destDeobfuscator; 115 m_destDeobfuscator = destDeobfuscator;
122 116
123 // init frame 117 // init frame
124 m_frame = new JFrame(Constants.Name); 118 m_frame = new JFrame(Constants.Name + " - Class Matcher");
125 final Container pane = m_frame.getContentPane(); 119 final Container pane = m_frame.getContentPane();
126 pane.setLayout(new BorderLayout()); 120 pane.setLayout(new BorderLayout());
127 121
@@ -188,8 +182,8 @@ public class ClassMatchingGui {
188 182
189 // init source panels 183 // init source panels
190 DefaultSyntaxKit.initKit(); 184 DefaultSyntaxKit.initKit();
191 m_sourceReader = makeReader(); 185 m_sourceReader = new CodeReader();
192 m_destReader = makeReader(); 186 m_destReader = new CodeReader();
193 187
194 // init all the splits 188 // init all the splits
195 JSplitPane splitLeft = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, sourcePanel, new JScrollPane(m_sourceReader)); 189 JSplitPane splitLeft = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, sourcePanel, new JScrollPane(m_sourceReader));
@@ -238,8 +232,6 @@ public class ClassMatchingGui {
238 m_frame.setVisible(true); 232 m_frame.setVisible(true);
239 m_frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 233 m_frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
240 234
241 m_selectionHighlightPainter = new SelectionHighlightPainter();
242
243 // init state 235 // init state
244 updateDestMappings(); 236 updateDestMappings();
245 setSourceType(SourceType.getDefault()); 237 setSourceType(SourceType.getDefault());
@@ -247,19 +239,6 @@ public class ClassMatchingGui {
247 m_saveListener = null; 239 m_saveListener = null;
248 } 240 }
249 241
250 private JEditorPane makeReader() {
251
252 JEditorPane reader = new JEditorPane();
253 reader.setEditable(false);
254 reader.setContentType("text/java");
255
256 // turn off token highlighting (it's wrong most of the time anyway...)
257 DefaultSyntaxKit kit = (DefaultSyntaxKit)reader.getEditorKit();
258 kit.toggleComponent(reader, "de.sciss.syntaxpane.components.TokenMarker");
259
260 return reader;
261 }
262
263 public void setSaveListener(SaveListener val) { 242 public void setSaveListener(SaveListener val) {
264 m_saveListener = val; 243 m_saveListener = val;
265 } 244 }
@@ -267,7 +246,7 @@ public class ClassMatchingGui {
267 private void updateDestMappings() { 246 private void updateDestMappings() {
268 247
269 Mappings newMappings = MappingsConverter.newMappings( 248 Mappings newMappings = MappingsConverter.newMappings(
270 m_matches, 249 m_classMatches,
271 m_sourceDeobfuscator.getMappings(), 250 m_sourceDeobfuscator.getMappings(),
272 m_sourceDeobfuscator, 251 m_sourceDeobfuscator,
273 m_destDeobfuscator 252 m_destDeobfuscator
@@ -294,13 +273,13 @@ public class ClassMatchingGui {
294 273
295 // show the source classes 274 // show the source classes
296 m_sourceType = val; 275 m_sourceType = val;
297 m_sourceClasses.setClasses(deobfuscateClasses(m_sourceType.getSourceClasses(m_matches), m_sourceDeobfuscator)); 276 m_sourceClasses.setClasses(deobfuscateClasses(m_sourceType.getSourceClasses(m_classMatches), m_sourceDeobfuscator));
298 277
299 // update counts 278 // update counts
300 for (SourceType sourceType : SourceType.values()) { 279 for (SourceType sourceType : SourceType.values()) {
301 m_sourceTypeButtons.get(sourceType).setText(String.format("%s (%d)", 280 m_sourceTypeButtons.get(sourceType).setText(String.format("%s (%d)",
302 sourceType.name(), 281 sourceType.name(),
303 sourceType.getSourceClasses(m_matches).size() 282 sourceType.getSourceClasses(m_classMatches).size()
304 )); 283 ));
305 } 284 }
306 } 285 }
@@ -345,7 +324,7 @@ public class ClassMatchingGui {
345 if (m_sourceClass != null) { 324 if (m_sourceClass != null) {
346 325
347 // show the dest class(es) 326 // show the dest class(es)
348 ClassMatch match = m_matches.getMatchBySource(m_sourceDeobfuscator.obfuscateEntry(m_sourceClass)); 327 ClassMatch match = m_classMatches.getMatchBySource(m_sourceDeobfuscator.obfuscateEntry(m_sourceClass));
349 assert(match != null); 328 assert(match != null);
350 if (match.destClasses.isEmpty()) { 329 if (match.destClasses.isEmpty()) {
351 330
@@ -376,7 +355,12 @@ public class ClassMatchingGui {
376 } 355 }
377 356
378 setDestClass(null); 357 setDestClass(null);
379 decompileClass(m_sourceClass, m_sourceDeobfuscator, m_sourceReader); 358 m_sourceReader.decompileClass(m_sourceClass, m_sourceDeobfuscator, new Runnable() {
359 @Override
360 public void run() {
361 m_sourceReader.navigateToClassDeclaration(m_sourceClass);
362 }
363 });
380 364
381 updateMatchButton(); 365 updateMatchButton();
382 } 366 }
@@ -386,7 +370,7 @@ public class ClassMatchingGui {
386 ClassEntry obfSourceClass = m_sourceDeobfuscator.obfuscateEntry(sourceClass); 370 ClassEntry obfSourceClass = m_sourceDeobfuscator.obfuscateEntry(sourceClass);
387 371
388 // set up identifiers 372 // set up identifiers
389 ClassNamer namer = new ClassNamer(m_matches.getUniqueMatches()); 373 ClassNamer namer = new ClassNamer(m_classMatches.getUniqueMatches());
390 ClassIdentifier sourceIdentifier = new ClassIdentifier( 374 ClassIdentifier sourceIdentifier = new ClassIdentifier(
391 m_sourceDeobfuscator.getJar(), m_sourceDeobfuscator.getJarIndex(), 375 m_sourceDeobfuscator.getJar(), m_sourceDeobfuscator.getJarIndex(),
392 namer.getSourceNamer(), true 376 namer.getSourceNamer(), true
@@ -401,7 +385,7 @@ public class ClassMatchingGui {
401 // rank all the unmatched dest classes against the source class 385 // rank all the unmatched dest classes against the source class
402 ClassIdentity sourceIdentity = sourceIdentifier.identify(obfSourceClass); 386 ClassIdentity sourceIdentity = sourceIdentifier.identify(obfSourceClass);
403 List<ClassEntry> scoredDestClasses = Lists.newArrayList(); 387 List<ClassEntry> scoredDestClasses = Lists.newArrayList();
404 for (ClassEntry unmatchedDestClass : m_matches.getUnmatchedDestClasses()) { 388 for (ClassEntry unmatchedDestClass : m_classMatches.getUnmatchedDestClasses()) {
405 ClassIdentity destIdentity = destIdentifier.identify(unmatchedDestClass); 389 ClassIdentity destIdentity = destIdentifier.identify(unmatchedDestClass);
406 float score = 100.0f*(sourceIdentity.getMatchScore(destIdentity) + destIdentity.getMatchScore(sourceIdentity)) 390 float score = 100.0f*(sourceIdentity.getMatchScore(destIdentity) + destIdentity.getMatchScore(sourceIdentity))
407 /(sourceIdentity.getMaxMatchScore() + destIdentity.getMaxMatchScore()); 391 /(sourceIdentity.getMaxMatchScore() + destIdentity.getMaxMatchScore());
@@ -420,59 +404,14 @@ public class ClassMatchingGui {
420 m_destClass = classEntry; 404 m_destClass = classEntry;
421 m_destClassLabel.setText(m_destClass != null ? m_destClass.getName() : ""); 405 m_destClassLabel.setText(m_destClass != null ? m_destClass.getName() : "");
422 406
423 decompileClass(m_destClass, m_destDeobfuscator, m_destReader); 407 m_destReader.decompileClass(m_destClass, m_destDeobfuscator, new Runnable() {
424
425 updateMatchButton();
426 }
427
428 protected void decompileClass(final ClassEntry classEntry, final Deobfuscator deobfuscator, final JEditorPane reader) {
429
430 if (classEntry == null) {
431 reader.setText(null);
432 return;
433 }
434
435 reader.setText("(decompiling...)");
436
437 // run in a separate thread to keep ui responsive
438 new Thread() {
439 @Override 408 @Override
440 public void run() { 409 public void run() {
441 410 m_destReader.navigateToClassDeclaration(m_destClass);
442 // get the outermost class
443 ClassEntry outermostClassEntry = classEntry;
444 while (outermostClassEntry.isInnerClass()) {
445 outermostClassEntry = outermostClassEntry.getOuterClassEntry();
446 }
447
448 // decompile it
449 CompilationUnit sourceTree = deobfuscator.getSourceTree(outermostClassEntry.getName());
450 String source = deobfuscator.getSource(sourceTree);
451 reader.setText(source);
452 SourceIndex sourceIndex = deobfuscator.getSourceIndex(sourceTree, source);
453
454 // navigate to the class declaration
455 Token token = sourceIndex.getDeclarationToken(classEntry);
456 if (token == null) {
457 // couldn't find the class declaration token, might be an anonymous class
458 // look for any declaration in that class instead
459 for (Entry entry : sourceIndex.declarations()) {
460 if (entry.getClassEntry().equals(classEntry)) {
461 token = sourceIndex.getDeclarationToken(entry);
462 break;
463 }
464 }
465 }
466
467 if (token != null) {
468 GuiTricks.navigateToToken(reader, token, m_selectionHighlightPainter);
469 } else {
470 // couldn't find anything =(
471 System.out.println("Unable to find declaration in source for " + classEntry);
472 }
473
474 } 411 }
475 }.start(); 412 });
413
414 updateMatchButton();
476 } 415 }
477 416
478 private void updateMatchButton() { 417 private void updateMatchButton() {
@@ -480,7 +419,7 @@ public class ClassMatchingGui {
480 ClassEntry obfSource = m_sourceDeobfuscator.obfuscateEntry(m_sourceClass); 419 ClassEntry obfSource = m_sourceDeobfuscator.obfuscateEntry(m_sourceClass);
481 ClassEntry obfDest = m_destDeobfuscator.obfuscateEntry(m_destClass); 420 ClassEntry obfDest = m_destDeobfuscator.obfuscateEntry(m_destClass);
482 421
483 BiMap<ClassEntry,ClassEntry> uniqueMatches = m_matches.getUniqueMatches(); 422 BiMap<ClassEntry,ClassEntry> uniqueMatches = m_classMatches.getUniqueMatches();
484 boolean twoSelected = m_sourceClass != null && m_destClass != null; 423 boolean twoSelected = m_sourceClass != null && m_destClass != null;
485 boolean isMatched = uniqueMatches.containsKey(obfSource) && uniqueMatches.containsValue(obfDest); 424 boolean isMatched = uniqueMatches.containsKey(obfSource) && uniqueMatches.containsValue(obfDest);
486 boolean canMatch = !uniqueMatches.containsKey(obfSource) && ! uniqueMatches.containsValue(obfDest); 425 boolean canMatch = !uniqueMatches.containsKey(obfSource) && ! uniqueMatches.containsValue(obfDest);
@@ -529,11 +468,11 @@ public class ClassMatchingGui {
529 ClassEntry obfDest = m_destDeobfuscator.obfuscateEntry(m_destClass); 468 ClassEntry obfDest = m_destDeobfuscator.obfuscateEntry(m_destClass);
530 469
531 // remove the classes from their match 470 // remove the classes from their match
532 m_matches.removeSource(obfSource); 471 m_classMatches.removeSource(obfSource);
533 m_matches.removeDest(obfDest); 472 m_classMatches.removeDest(obfDest);
534 473
535 // add them as matched classes 474 // add them as matched classes
536 m_matches.add(new ClassMatch(obfSource, obfDest)); 475 m_classMatches.add(new ClassMatch(obfSource, obfDest));
537 476
538 ClassEntry nextClass = null; 477 ClassEntry nextClass = null;
539 if (m_advanceCheck.isSelected()) { 478 if (m_advanceCheck.isSelected()) {
@@ -554,8 +493,8 @@ public class ClassMatchingGui {
554 ClassEntry obfSource = m_sourceDeobfuscator.obfuscateEntry(m_sourceClass); 493 ClassEntry obfSource = m_sourceDeobfuscator.obfuscateEntry(m_sourceClass);
555 494
556 // remove the source to break the match, then add the source back as unmatched 495 // remove the source to break the match, then add the source back as unmatched
557 m_matches.removeSource(obfSource); 496 m_classMatches.removeSource(obfSource);
558 m_matches.add(new ClassMatch(obfSource, null)); 497 m_classMatches.add(new ClassMatch(obfSource, null));
559 498
560 save(); 499 save();
561 updateMatches(); 500 updateMatches();
@@ -577,7 +516,7 @@ public class ClassMatchingGui {
577 516
578 private void save() { 517 private void save() {
579 if (m_saveListener != null) { 518 if (m_saveListener != null) {
580 m_saveListener.save(m_matches); 519 m_saveListener.save(m_classMatches);
581 } 520 }
582 } 521 }
583 522
@@ -589,15 +528,15 @@ public class ClassMatchingGui {
589 ClassMatching matching = MappingsConverter.computeMatching( 528 ClassMatching matching = MappingsConverter.computeMatching(
590 m_sourceDeobfuscator.getJar(), m_sourceDeobfuscator.getJarIndex(), 529 m_sourceDeobfuscator.getJar(), m_sourceDeobfuscator.getJarIndex(),
591 m_destDeobfuscator.getJar(), m_destDeobfuscator.getJarIndex(), 530 m_destDeobfuscator.getJar(), m_destDeobfuscator.getJarIndex(),
592 m_matches.getUniqueMatches() 531 m_classMatches.getUniqueMatches()
593 ); 532 );
594 Matches newMatches = new Matches(matching.matches()); 533 ClassMatches newMatches = new ClassMatches(matching.matches());
595 System.out.println(String.format("Automatch found %d new matches", 534 System.out.println(String.format("Automatch found %d new matches",
596 newMatches.getUniqueMatches().size() - m_matches.getUniqueMatches().size() 535 newMatches.getUniqueMatches().size() - m_classMatches.getUniqueMatches().size()
597 )); 536 ));
598 537
599 // update the current matches 538 // update the current matches
600 m_matches = newMatches; 539 m_classMatches = newMatches;
601 save(); 540 save();
602 updateMatches(); 541 updateMatches();
603 } 542 }
diff --git a/src/cuchaz/enigma/gui/CodeReader.java b/src/cuchaz/enigma/gui/CodeReader.java
new file mode 100644
index 00000000..05feb59e
--- /dev/null
+++ b/src/cuchaz/enigma/gui/CodeReader.java
@@ -0,0 +1,164 @@
1package cuchaz.enigma.gui;
2
3import java.awt.Rectangle;
4import java.awt.event.ActionEvent;
5import java.awt.event.ActionListener;
6
7import javax.swing.JEditorPane;
8import javax.swing.SwingUtilities;
9import javax.swing.Timer;
10import javax.swing.text.BadLocationException;
11import javax.swing.text.Highlighter.HighlightPainter;
12
13import com.strobel.decompiler.languages.java.ast.CompilationUnit;
14
15import cuchaz.enigma.Deobfuscator;
16import cuchaz.enigma.analysis.SourceIndex;
17import cuchaz.enigma.analysis.Token;
18import cuchaz.enigma.mapping.ClassEntry;
19import cuchaz.enigma.mapping.Entry;
20import de.sciss.syntaxpane.DefaultSyntaxKit;
21
22
23public class CodeReader extends JEditorPane {
24
25 private static final long serialVersionUID = 3673180950485748810L;
26
27 private static final Object m_lock = new Object();
28
29 private SelectionHighlightPainter m_highlightPainter;
30 private SourceIndex m_sourceIndex;
31
32 public CodeReader() {
33
34 setEditable(false);
35 setContentType("text/java");
36
37 // turn off token highlighting (it's wrong most of the time anyway...)
38 DefaultSyntaxKit kit = (DefaultSyntaxKit)getEditorKit();
39 kit.toggleComponent(this, "de.sciss.syntaxpane.components.TokenMarker");
40
41 m_highlightPainter = new SelectionHighlightPainter();
42 m_sourceIndex = null;
43 }
44
45 public void setCode(String code) {
46 // sadly, the java lexer is not thread safe, so we have to serialize all these calls
47 synchronized (m_lock) {
48 setText(code);
49 }
50 }
51
52 public void decompileClass(ClassEntry classEntry, Deobfuscator deobfuscator) {
53 decompileClass(classEntry, deobfuscator, null);
54 }
55
56 public void decompileClass(final ClassEntry classEntry, final Deobfuscator deobfuscator, final Runnable callback) {
57
58 if (classEntry == null) {
59 setCode(null);
60 return;
61 }
62
63 setCode("(decompiling...)");
64
65 // run decompilation in a separate thread to keep ui responsive
66 new Thread() {
67 @Override
68 public void run() {
69
70 // get the outermost class
71 ClassEntry outermostClassEntry = classEntry;
72 while (outermostClassEntry.isInnerClass()) {
73 outermostClassEntry = outermostClassEntry.getOuterClassEntry();
74 }
75
76 // decompile it
77 CompilationUnit sourceTree = deobfuscator.getSourceTree(outermostClassEntry.getName());
78 String source = deobfuscator.getSource(sourceTree);
79 setCode(source);
80 m_sourceIndex = deobfuscator.getSourceIndex(sourceTree, source);
81
82 if (callback != null) {
83 callback.run();
84 }
85 }
86 }.start();
87 }
88
89 public void navigateToClassDeclaration(ClassEntry classEntry) {
90
91 // navigate to the class declaration
92 Token token = m_sourceIndex.getDeclarationToken(classEntry);
93 if (token == null) {
94 // couldn't find the class declaration token, might be an anonymous class
95 // look for any declaration in that class instead
96 for (Entry entry : m_sourceIndex.declarations()) {
97 if (entry.getClassEntry().equals(classEntry)) {
98 token = m_sourceIndex.getDeclarationToken(entry);
99 break;
100 }
101 }
102 }
103
104 if (token != null) {
105 navigateToToken(token);
106 } else {
107 // couldn't find anything =(
108 System.out.println("Unable to find declaration in source for " + classEntry);
109 }
110 }
111
112 public void navigateToToken(final Token token) {
113 navigateToToken(this, token, m_highlightPainter);
114 }
115
116 // HACKHACK: someday we can update the main GUI to use this code reader
117 public static void navigateToToken(final JEditorPane editor, final Token token, final HighlightPainter highlightPainter) {
118
119 // set the caret position to the token
120 editor.setCaretPosition(token.start);
121 editor.grabFocus();
122
123 try {
124 // make sure the token is visible in the scroll window
125 Rectangle start = editor.modelToView(token.start);
126 Rectangle end = editor.modelToView(token.end);
127 final Rectangle show = start.union(end);
128 show.grow(start.width * 10, start.height * 6);
129 SwingUtilities.invokeLater(new Runnable() {
130 @Override
131 public void run() {
132 editor.scrollRectToVisible(show);
133 }
134 });
135 } catch (BadLocationException ex) {
136 throw new Error(ex);
137 }
138
139 // highlight the token momentarily
140 final Timer timer = new Timer(200, new ActionListener() {
141 private int m_counter = 0;
142 private Object m_highlight = null;
143
144 @Override
145 public void actionPerformed(ActionEvent event) {
146 if (m_counter % 2 == 0) {
147 try {
148 m_highlight = editor.getHighlighter().addHighlight(token.start, token.end, highlightPainter);
149 } catch (BadLocationException ex) {
150 // don't care
151 }
152 } else if (m_highlight != null) {
153 editor.getHighlighter().removeHighlight(m_highlight);
154 }
155
156 if (m_counter++ > 6) {
157 Timer timer = (Timer)event.getSource();
158 timer.stop();
159 }
160 }
161 });
162 timer.start();
163 }
164}
diff --git a/src/cuchaz/enigma/gui/FieldMatchingGui.java b/src/cuchaz/enigma/gui/FieldMatchingGui.java
new file mode 100644
index 00000000..de9ba142
--- /dev/null
+++ b/src/cuchaz/enigma/gui/FieldMatchingGui.java
@@ -0,0 +1,131 @@
1package cuchaz.enigma.gui;
2
3import java.awt.BorderLayout;
4import java.awt.Container;
5import java.awt.Dimension;
6import java.awt.FlowLayout;
7import java.util.Map;
8
9import javax.swing.BoxLayout;
10import javax.swing.JFrame;
11import javax.swing.JLabel;
12import javax.swing.JPanel;
13import javax.swing.JScrollPane;
14import javax.swing.JSplitPane;
15import javax.swing.WindowConstants;
16
17import cuchaz.enigma.Constants;
18import cuchaz.enigma.Deobfuscator;
19import cuchaz.enigma.convert.ClassMatches;
20import cuchaz.enigma.convert.FieldMatches;
21import cuchaz.enigma.gui.ClassSelector.ClassSelectionListener;
22import cuchaz.enigma.mapping.ClassEntry;
23import cuchaz.enigma.mapping.FieldEntry;
24import cuchaz.enigma.mapping.FieldMapping;
25import de.sciss.syntaxpane.DefaultSyntaxKit;
26
27
28public class FieldMatchingGui {
29
30 public static interface SaveListener {
31 public void save(FieldMatches matches);
32 }
33
34 // controls
35 private JFrame m_frame;
36 private ClassSelector m_sourceClasses;
37 private CodeReader m_sourceReader;
38 private CodeReader m_destReader;
39
40 private ClassMatches m_classMatches;
41 private FieldMatches m_fieldMatches;
42 private Map<FieldEntry,FieldMapping> m_droppedFieldMappings;
43 private Deobfuscator m_sourceDeobfuscator;
44 private Deobfuscator m_destDeobfuscator;
45 private SaveListener m_saveListener;
46
47 public FieldMatchingGui(ClassMatches classMatches, FieldMatches fieldMatches, Map<FieldEntry,FieldMapping> droppedFieldMappings, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) {
48
49 m_classMatches = classMatches;
50 m_fieldMatches = fieldMatches;
51 m_droppedFieldMappings = droppedFieldMappings;
52 m_sourceDeobfuscator = sourceDeobfuscator;
53 m_destDeobfuscator = destDeobfuscator;
54
55 // init frame
56 m_frame = new JFrame(Constants.Name + " - Field Matcher");
57 final Container pane = m_frame.getContentPane();
58 pane.setLayout(new BorderLayout());
59
60 // init classes side
61 JPanel classesPanel = new JPanel();
62 classesPanel.setLayout(new BoxLayout(classesPanel, BoxLayout.PAGE_AXIS));
63 classesPanel.setPreferredSize(new Dimension(200, 0));
64 pane.add(classesPanel, BorderLayout.WEST);
65 classesPanel.add(new JLabel("Classes"));
66
67 m_sourceClasses = new ClassSelector(ClassSelector.DeobfuscatedClassEntryComparator);
68 m_sourceClasses.setListener(new ClassSelectionListener() {
69 @Override
70 public void onSelectClass(ClassEntry classEntry) {
71 setSourceClass(classEntry);
72 }
73 });
74 JScrollPane sourceScroller = new JScrollPane(m_sourceClasses);
75 classesPanel.add(sourceScroller);
76
77 // init fields side
78 JPanel fieldsPanel = new JPanel();
79 fieldsPanel.setLayout(new BoxLayout(fieldsPanel, BoxLayout.PAGE_AXIS));
80 fieldsPanel.setPreferredSize(new Dimension(200, 0));
81 pane.add(fieldsPanel, BorderLayout.WEST);
82 fieldsPanel.add(new JLabel("Destination Fields"));
83
84 // init readers
85 DefaultSyntaxKit.initKit();
86 m_sourceReader = new CodeReader();
87 m_destReader = new CodeReader();
88
89 // init all the splits
90 JSplitPane splitLeft = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, classesPanel, new JScrollPane(m_sourceReader));
91 splitLeft.setResizeWeight(0); // let the right side take all the slack
92 JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, new JScrollPane(m_destReader), fieldsPanel);
93 splitRight.setResizeWeight(1); // let the left side take all the slack
94 JSplitPane splitCenter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, splitLeft, splitRight);
95 splitCenter.setResizeWeight(0.5); // resize 50:50
96 pane.add(splitCenter, BorderLayout.CENTER);
97 splitCenter.resetToPreferredSizes();
98
99 // init bottom panel
100 JPanel bottomPanel = new JPanel();
101 bottomPanel.setLayout(new FlowLayout());
102
103 // show the frame
104 pane.doLayout();
105 m_frame.setSize(1024, 576);
106 m_frame.setMinimumSize(new Dimension(640, 480));
107 m_frame.setVisible(true);
108 m_frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
109
110 // init state
111 m_saveListener = null;
112 m_fieldMatches.addUnmatchedSourceFields(droppedFieldMappings.keySet());
113 m_sourceClasses.setClasses(m_fieldMatches.getSourceClassesWithUnmatchedFields());
114 }
115
116 public void setSaveListener(SaveListener val) {
117 m_saveListener = val;
118 }
119
120 protected void setSourceClass(ClassEntry obfSourceClass) {
121
122 // get the matched dest class
123 final ClassEntry obfDestClass = m_classMatches.getUniqueMatches().get(obfSourceClass);
124 if (obfDestClass == null) {
125 throw new Error("No matching dest class for source class: " + obfSourceClass);
126 }
127
128 m_sourceReader.decompileClass(obfSourceClass, m_sourceDeobfuscator);
129 m_destReader.decompileClass(obfDestClass, m_destDeobfuscator);
130 }
131}
diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java
index 38a6ee9a..ea05d255 100644
--- a/src/cuchaz/enigma/gui/Gui.java
+++ b/src/cuchaz/enigma/gui/Gui.java
@@ -737,7 +737,7 @@ public class Gui {
737 if (token == null) { 737 if (token == null) {
738 throw new IllegalArgumentException("Token cannot be null!"); 738 throw new IllegalArgumentException("Token cannot be null!");
739 } 739 }
740 GuiTricks.navigateToToken(m_editor, token, m_selectionHighlightPainter); 740 CodeReader.navigateToToken(m_editor, token, m_selectionHighlightPainter);
741 redraw(); 741 redraw();
742 } 742 }
743 743
diff --git a/src/cuchaz/enigma/gui/GuiTricks.java b/src/cuchaz/enigma/gui/GuiTricks.java
index 5a3a01de..df9e2215 100644
--- a/src/cuchaz/enigma/gui/GuiTricks.java
+++ b/src/cuchaz/enigma/gui/GuiTricks.java
@@ -11,21 +11,11 @@
11package cuchaz.enigma.gui; 11package cuchaz.enigma.gui;
12 12
13import java.awt.Font; 13import java.awt.Font;
14import java.awt.Rectangle;
15import java.awt.event.ActionEvent;
16import java.awt.event.ActionListener;
17import java.awt.event.MouseEvent; 14import java.awt.event.MouseEvent;
18 15
19import javax.swing.JComponent; 16import javax.swing.JComponent;
20import javax.swing.JEditorPane;
21import javax.swing.JLabel; 17import javax.swing.JLabel;
22import javax.swing.SwingUtilities;
23import javax.swing.Timer;
24import javax.swing.ToolTipManager; 18import javax.swing.ToolTipManager;
25import javax.swing.text.BadLocationException;
26import javax.swing.text.Highlighter.HighlightPainter;
27
28import cuchaz.enigma.analysis.Token;
29 19
30public class GuiTricks { 20public class GuiTricks {
31 21
@@ -43,52 +33,4 @@ public class GuiTricks {
43 manager.mouseMoved(new MouseEvent(component, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, 0, 0, 0, false)); 33 manager.mouseMoved(new MouseEvent(component, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, 0, 0, 0, false));
44 manager.setInitialDelay(oldDelay); 34 manager.setInitialDelay(oldDelay);
45 } 35 }
46
47 public static void navigateToToken(final JEditorPane editor, final Token token, final HighlightPainter highlightPainter) {
48
49 // set the caret position to the token
50 editor.setCaretPosition(token.start);
51 editor.grabFocus();
52
53 try {
54 // make sure the token is visible in the scroll window
55 Rectangle start = editor.modelToView(token.start);
56 Rectangle end = editor.modelToView(token.end);
57 final Rectangle show = start.union(end);
58 show.grow(start.width * 10, start.height * 6);
59 SwingUtilities.invokeLater(new Runnable() {
60 @Override
61 public void run() {
62 editor.scrollRectToVisible(show);
63 }
64 });
65 } catch (BadLocationException ex) {
66 throw new Error(ex);
67 }
68
69 // highlight the token momentarily
70 final Timer timer = new Timer(200, new ActionListener() {
71 private int m_counter = 0;
72 private Object m_highlight = null;
73
74 @Override
75 public void actionPerformed(ActionEvent event) {
76 if (m_counter % 2 == 0) {
77 try {
78 m_highlight = editor.getHighlighter().addHighlight(token.start, token.end, highlightPainter);
79 } catch (BadLocationException ex) {
80 // don't care
81 }
82 } else if (m_highlight != null) {
83 editor.getHighlighter().removeHighlight(m_highlight);
84 }
85
86 if (m_counter++ > 6) {
87 Timer timer = (Timer)event.getSource();
88 timer.stop();
89 }
90 }
91 });
92 timer.start();
93 }
94} 36}