summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar jeff2015-03-11 11:03:16 -0400
committerGravatar jeff2015-03-11 11:03:16 -0400
commite33b4003a5c423894e7aef575faff359dd1d33b1 (patch)
tree6fa674b5ff8dbc699a44b6423149ad7e6eaae250 /src
parentnothing of consequence (diff)
downloadenigma-e33b4003a5c423894e7aef575faff359dd1d33b1.tar.gz
enigma-e33b4003a5c423894e7aef575faff359dd1d33b1.tar.xz
enigma-e33b4003a5c423894e7aef575faff359dd1d33b1.zip
generalized field matching
added method matching
Diffstat (limited to 'src')
-rw-r--r--src/cuchaz/enigma/ConvertMain.java82
-rw-r--r--src/cuchaz/enigma/convert/MappingsConverter.java196
-rw-r--r--src/cuchaz/enigma/convert/MatchesReader.java46
-rw-r--r--src/cuchaz/enigma/convert/MatchesWriter.java50
-rw-r--r--src/cuchaz/enigma/convert/MemberMatches.java145
-rw-r--r--src/cuchaz/enigma/gui/MemberMatchingGui.java (renamed from src/cuchaz/enigma/gui/FieldMatchingGui.java)153
-rw-r--r--src/cuchaz/enigma/mapping/ClassMapping.java4
-rw-r--r--src/cuchaz/enigma/mapping/EntryFactory.java12
-rw-r--r--src/cuchaz/enigma/mapping/FieldMapping.java7
-rw-r--r--src/cuchaz/enigma/mapping/MemberMapping.java6
-rw-r--r--src/cuchaz/enigma/mapping/MethodMapping.java11
11 files changed, 552 insertions, 160 deletions
diff --git a/src/cuchaz/enigma/ConvertMain.java b/src/cuchaz/enigma/ConvertMain.java
index e012f197..c3a2ad5c 100644
--- a/src/cuchaz/enigma/ConvertMain.java
+++ b/src/cuchaz/enigma/ConvertMain.java
@@ -7,12 +7,14 @@ import java.io.IOException;
7import java.util.jar.JarFile; 7import java.util.jar.JarFile;
8 8
9import cuchaz.enigma.convert.ClassMatches; 9import cuchaz.enigma.convert.ClassMatches;
10import cuchaz.enigma.convert.FieldMatches;
11import cuchaz.enigma.convert.MappingsConverter; 10import cuchaz.enigma.convert.MappingsConverter;
12import cuchaz.enigma.convert.MatchesReader; 11import cuchaz.enigma.convert.MatchesReader;
13import cuchaz.enigma.convert.MatchesWriter; 12import cuchaz.enigma.convert.MatchesWriter;
13import cuchaz.enigma.convert.MemberMatches;
14import cuchaz.enigma.gui.ClassMatchingGui; 14import cuchaz.enigma.gui.ClassMatchingGui;
15import cuchaz.enigma.gui.FieldMatchingGui; 15import cuchaz.enigma.gui.MemberMatchingGui;
16import cuchaz.enigma.mapping.BehaviorEntry;
17import cuchaz.enigma.mapping.FieldEntry;
16import cuchaz.enigma.mapping.MappingParseException; 18import cuchaz.enigma.mapping.MappingParseException;
17import cuchaz.enigma.mapping.Mappings; 19import cuchaz.enigma.mapping.Mappings;
18import cuchaz.enigma.mapping.MappingsChecker; 20import cuchaz.enigma.mapping.MappingsChecker;
@@ -34,13 +36,21 @@ public class ConvertMain {
34 Mappings mappings = new MappingsReader().read(new FileReader(inMappingsFile)); 36 Mappings mappings = new MappingsReader().read(new FileReader(inMappingsFile));
35 File classMatchesFile = new File(inMappingsFile.getName() + ".class.matches"); 37 File classMatchesFile = new File(inMappingsFile.getName() + ".class.matches");
36 File fieldMatchesFile = new File(inMappingsFile.getName() + ".field.matches"); 38 File fieldMatchesFile = new File(inMappingsFile.getName() + ".field.matches");
39 File methodMatchesFile = new File(inMappingsFile.getName() + ".method.matches");
37 40
41 // match classes
38 //computeClassMatches(classMatchesFile, sourceJar, destJar, mappings); 42 //computeClassMatches(classMatchesFile, sourceJar, destJar, mappings);
39 editClasssMatches(classMatchesFile, sourceJar, destJar, mappings); 43 //editClasssMatches(classMatchesFile, sourceJar, destJar, mappings);
40 //convertMappings(outMappingsFile, sourceJar, destJar, mappings, classMatchesFile); 44 //convertMappings(outMappingsFile, sourceJar, destJar, mappings, classMatchesFile);
45
46 // match fields
41 //computeFieldMatches(fieldMatchesFile, destJar, outMappingsFile, classMatchesFile); 47 //computeFieldMatches(fieldMatchesFile, destJar, outMappingsFile, classMatchesFile);
42 //editFieldMatches(sourceJar, destJar, outMappingsFile, mappings, classMatchesFile, fieldMatchesFile); 48 //editFieldMatches(sourceJar, destJar, outMappingsFile, mappings, classMatchesFile, fieldMatchesFile);
43 49
50 // match methods/constructors
51 //computeMethodMatches(methodMatchesFile, destJar, outMappingsFile, classMatchesFile);
52 editMethodMatches(sourceJar, destJar, outMappingsFile, mappings, classMatchesFile, methodMatchesFile);
53
44 /* TODO 54 /* TODO
45 // write out the converted mappings 55 // write out the converted mappings
46 FileWriter writer = new FileWriter(outMappingsFile); 56 FileWriter writer = new FileWriter(outMappingsFile);
@@ -91,7 +101,7 @@ public class ConvertMain {
91 System.out.println("Write converted mappings to: " + outMappingsFile.getAbsolutePath()); 101 System.out.println("Write converted mappings to: " + outMappingsFile.getAbsolutePath());
92 } 102 }
93 103
94 private static void computeFieldMatches(File fieldMatchesFile, JarFile destJar, File destMappingsFile, File classMatchesFile) 104 private static void computeFieldMatches(File memberMatchesFile, JarFile destJar, File destMappingsFile, File classMatchesFile)
95 throws IOException, MappingParseException { 105 throws IOException, MappingParseException {
96 106
97 System.out.println("Reading class matches..."); 107 System.out.println("Reading class matches...");
@@ -101,13 +111,13 @@ public class ConvertMain {
101 System.out.println("Indexing dest jar..."); 111 System.out.println("Indexing dest jar...");
102 Deobfuscator destDeobfuscator = new Deobfuscator(destJar); 112 Deobfuscator destDeobfuscator = new Deobfuscator(destJar);
103 113
104 System.out.println("Writing field matches..."); 114 System.out.println("Writing matches...");
105 115
106 // get the matched and unmatched field mappings 116 // get the matched and unmatched mappings
107 FieldMatches fieldMatches = MappingsConverter.computeFieldMatches(destDeobfuscator, destMappings, classMatches); 117 MemberMatches<FieldEntry> fieldMatches = MappingsConverter.computeFieldMatches(destDeobfuscator, destMappings, classMatches);
108 118
109 MatchesWriter.writeFields(fieldMatches, fieldMatchesFile); 119 MatchesWriter.writeMembers(fieldMatches, memberMatchesFile);
110 System.out.println("Wrote:\n\t" + fieldMatchesFile.getAbsolutePath()); 120 System.out.println("Wrote:\n\t" + memberMatchesFile.getAbsolutePath());
111 } 121 }
112 122
113 private static void editFieldMatches(JarFile sourceJar, JarFile destJar, File destMappingsFile, Mappings sourceMappings, File classMatchesFile, final File fieldMatchesFile) 123 private static void editFieldMatches(JarFile sourceJar, JarFile destJar, File destMappingsFile, Mappings sourceMappings, File classMatchesFile, final File fieldMatchesFile)
@@ -115,7 +125,7 @@ public class ConvertMain {
115 125
116 System.out.println("Reading matches..."); 126 System.out.println("Reading matches...");
117 ClassMatches classMatches = MatchesReader.readClasses(classMatchesFile); 127 ClassMatches classMatches = MatchesReader.readClasses(classMatchesFile);
118 FieldMatches fieldMatches = MatchesReader.readFields(fieldMatchesFile); 128 MemberMatches<FieldEntry> fieldMatches = MatchesReader.readMembers(fieldMatchesFile);
119 129
120 // prep deobfuscators 130 // prep deobfuscators
121 Deobfuscators deobfuscators = new Deobfuscators(sourceJar, destJar); 131 Deobfuscators deobfuscators = new Deobfuscators(sourceJar, destJar);
@@ -125,18 +135,64 @@ public class ConvertMain {
125 checker.dropBrokenMappings(destMappings); 135 checker.dropBrokenMappings(destMappings);
126 deobfuscators.dest.setMappings(destMappings); 136 deobfuscators.dest.setMappings(destMappings);
127 137
128 new FieldMatchingGui(classMatches, fieldMatches, deobfuscators.source, deobfuscators.dest).setSaveListener(new FieldMatchingGui.SaveListener() { 138 new MemberMatchingGui<FieldEntry>(classMatches, fieldMatches, deobfuscators.source, deobfuscators.dest).setSaveListener(new MemberMatchingGui.SaveListener<FieldEntry>() {
129 @Override 139 @Override
130 public void save(FieldMatches matches) { 140 public void save(MemberMatches<FieldEntry> matches) {
131 try { 141 try {
132 MatchesWriter.writeFields(matches, fieldMatchesFile); 142 MatchesWriter.writeMembers(matches, fieldMatchesFile);
133 } catch (IOException ex) { 143 } catch (IOException ex) {
134 throw new Error(ex); 144 throw new Error(ex);
135 } 145 }
136 } 146 }
137 }); 147 });
138 } 148 }
149
150 private static void computeMethodMatches(File methodMatchesFile, JarFile destJar, File destMappingsFile, File classMatchesFile)
151 throws IOException, MappingParseException {
152
153 System.out.println("Reading class matches...");
154 ClassMatches classMatches = MatchesReader.readClasses(classMatchesFile);
155 System.out.println("Reading mappings...");
156 Mappings destMappings = new MappingsReader().read(new FileReader(destMappingsFile));
157 System.out.println("Indexing dest jar...");
158 Deobfuscator destDeobfuscator = new Deobfuscator(destJar);
159
160 System.out.println("Writing method matches...");
161
162 // get the matched and unmatched mappings
163 MemberMatches<BehaviorEntry> methodMatches = MappingsConverter.computeBehaviorMatches(destDeobfuscator, destMappings, classMatches);
164
165 MatchesWriter.writeMembers(methodMatches, methodMatchesFile);
166 System.out.println("Wrote:\n\t" + methodMatchesFile.getAbsolutePath());
167 }
139 168
169 private static void editMethodMatches(JarFile sourceJar, JarFile destJar, File destMappingsFile, Mappings sourceMappings, File classMatchesFile, final File methodMatchesFile)
170 throws IOException, MappingParseException {
171
172 System.out.println("Reading matches...");
173 ClassMatches classMatches = MatchesReader.readClasses(classMatchesFile);
174 MemberMatches<BehaviorEntry> methodMatches = MatchesReader.readMembers(methodMatchesFile);
175
176 // prep deobfuscators
177 Deobfuscators deobfuscators = new Deobfuscators(sourceJar, destJar);
178 deobfuscators.source.setMappings(sourceMappings);
179 Mappings destMappings = new MappingsReader().read(new FileReader(destMappingsFile));
180 MappingsChecker checker = new MappingsChecker(deobfuscators.dest.getJarIndex());
181 checker.dropBrokenMappings(destMappings);
182 deobfuscators.dest.setMappings(destMappings);
183
184 new MemberMatchingGui<BehaviorEntry>(classMatches, methodMatches, deobfuscators.source, deobfuscators.dest).setSaveListener(new MemberMatchingGui.SaveListener<BehaviorEntry>() {
185 @Override
186 public void save(MemberMatches<BehaviorEntry> matches) {
187 try {
188 MatchesWriter.writeMembers(matches, methodMatchesFile);
189 } catch (IOException ex) {
190 throw new Error(ex);
191 }
192 }
193 });
194 }
195
140 private static class Deobfuscators { 196 private static class Deobfuscators {
141 197
142 public Deobfuscator source; 198 public Deobfuscator source;
diff --git a/src/cuchaz/enigma/convert/MappingsConverter.java b/src/cuchaz/enigma/convert/MappingsConverter.java
index 9ab1baa3..2987ea08 100644
--- a/src/cuchaz/enigma/convert/MappingsConverter.java
+++ b/src/cuchaz/enigma/convert/MappingsConverter.java
@@ -11,12 +11,12 @@
11package cuchaz.enigma.convert; 11package cuchaz.enigma.convert;
12 12
13import java.util.Arrays; 13import java.util.Arrays;
14import java.util.Collection;
14import java.util.Collections; 15import java.util.Collections;
15import java.util.Iterator; 16import java.util.Iterator;
16import java.util.LinkedHashMap; 17import java.util.LinkedHashMap;
17import java.util.List; 18import java.util.List;
18import java.util.Map; 19import java.util.Map;
19import java.util.Map.Entry;
20import java.util.Set; 20import java.util.Set;
21import java.util.jar.JarFile; 21import java.util.jar.JarFile;
22 22
@@ -30,15 +30,20 @@ import com.google.common.collect.Sets;
30import cuchaz.enigma.Deobfuscator; 30import cuchaz.enigma.Deobfuscator;
31import cuchaz.enigma.analysis.JarIndex; 31import cuchaz.enigma.analysis.JarIndex;
32import cuchaz.enigma.convert.ClassNamer.SidedClassNamer; 32import cuchaz.enigma.convert.ClassNamer.SidedClassNamer;
33import cuchaz.enigma.mapping.BehaviorEntry;
33import cuchaz.enigma.mapping.ClassEntry; 34import cuchaz.enigma.mapping.ClassEntry;
34import cuchaz.enigma.mapping.ClassMapping; 35import cuchaz.enigma.mapping.ClassMapping;
35import cuchaz.enigma.mapping.ClassNameReplacer; 36import cuchaz.enigma.mapping.ClassNameReplacer;
36import cuchaz.enigma.mapping.EntryFactory; 37import cuchaz.enigma.mapping.ConstructorEntry;
38import cuchaz.enigma.mapping.Entry;
37import cuchaz.enigma.mapping.FieldEntry; 39import cuchaz.enigma.mapping.FieldEntry;
38import cuchaz.enigma.mapping.FieldMapping; 40import cuchaz.enigma.mapping.FieldMapping;
39import cuchaz.enigma.mapping.Mappings; 41import cuchaz.enigma.mapping.Mappings;
40import cuchaz.enigma.mapping.MappingsChecker; 42import cuchaz.enigma.mapping.MappingsChecker;
43import cuchaz.enigma.mapping.MemberMapping;
44import cuchaz.enigma.mapping.MethodEntry;
41import cuchaz.enigma.mapping.MethodMapping; 45import cuchaz.enigma.mapping.MethodMapping;
46import cuchaz.enigma.mapping.Signature;
42import cuchaz.enigma.mapping.Type; 47import cuchaz.enigma.mapping.Type;
43 48
44public class MappingsConverter { 49public class MappingsConverter {
@@ -124,8 +129,8 @@ public class MappingsConverter {
124 public static Mappings newMappings(ClassMatches matches, Mappings oldMappings, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) { 129 public static Mappings newMappings(ClassMatches matches, Mappings oldMappings, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) {
125 130
126 // sort the unique matches by size of inner class chain 131 // sort the unique matches by size of inner class chain
127 Multimap<Integer,Entry<ClassEntry,ClassEntry>> matchesByDestChainSize = HashMultimap.create(); 132 Multimap<Integer,java.util.Map.Entry<ClassEntry,ClassEntry>> matchesByDestChainSize = HashMultimap.create();
128 for (Entry<ClassEntry,ClassEntry> match : matches.getUniqueMatches().entrySet()) { 133 for (java.util.Map.Entry<ClassEntry,ClassEntry> match : matches.getUniqueMatches().entrySet()) {
129 int chainSize = destDeobfuscator.getJarIndex().getObfClassChain(match.getValue()).size(); 134 int chainSize = destDeobfuscator.getJarIndex().getObfClassChain(match.getValue()).size();
130 matchesByDestChainSize.put(chainSize, match); 135 matchesByDestChainSize.put(chainSize, match);
131 } 136 }
@@ -135,7 +140,7 @@ public class MappingsConverter {
135 List<Integer> chainSizes = Lists.newArrayList(matchesByDestChainSize.keySet()); 140 List<Integer> chainSizes = Lists.newArrayList(matchesByDestChainSize.keySet());
136 Collections.sort(chainSizes); 141 Collections.sort(chainSizes);
137 for (int chainSize : chainSizes) { 142 for (int chainSize : chainSizes) {
138 for (Entry<ClassEntry,ClassEntry> match : matchesByDestChainSize.get(chainSize)) { 143 for (java.util.Map.Entry<ClassEntry,ClassEntry> match : matchesByDestChainSize.get(chainSize)) {
139 144
140 // get class info 145 // get class info
141 ClassEntry obfSourceClassEntry = match.getKey(); 146 ClassEntry obfSourceClassEntry = match.getKey();
@@ -251,89 +256,172 @@ public class MappingsConverter {
251 mappings.renameObfClass(entry.getKey().getName(), entry.getValue().getName()); 256 mappings.renameObfClass(entry.getKey().getName(), entry.getValue().getName());
252 } 257 }
253 } 258 }
259
260 public static interface Doer<T extends Entry> {
261 Collection<T> getDroppedEntries(MappingsChecker checker);
262 Collection<T> getObfEntries(JarIndex jarIndex);
263 Collection<? extends MemberMapping<T>> getMappings(ClassMapping destClassMapping);
264 Set<T> filterEntries(Collection<T> obfEntries, T obfSourceEntry, ClassMatches classMatches);
265 }
266
267 public static MemberMatches<FieldEntry> computeFieldMatches(Deobfuscator destDeobfuscator, Mappings destMappings, ClassMatches classMatches) {
268 return computeMemberMatches(destDeobfuscator, destMappings, classMatches, new Doer<FieldEntry>() {
269
270 @Override
271 public Collection<FieldEntry> getDroppedEntries(MappingsChecker checker) {
272 return checker.getDroppedFieldMappings().keySet();
273 }
274
275 @Override
276 public Collection<FieldEntry> getObfEntries(JarIndex jarIndex) {
277 return jarIndex.getObfFieldEntries();
278 }
279
280 @Override
281 public Collection<? extends MemberMapping<FieldEntry>> getMappings(ClassMapping destClassMapping) {
282 return (Collection<? extends MemberMapping<FieldEntry>>)destClassMapping.fields();
283 }
284
285 @Override
286 public Set<FieldEntry> filterEntries(Collection<FieldEntry> obfDestFields, FieldEntry obfSourceField, ClassMatches classMatches) {
287 Set<FieldEntry> out = Sets.newHashSet();
288 for (FieldEntry obfDestField : obfDestFields) {
289 Type translatedDestType = translate(obfDestField.getType(), classMatches.getUniqueMatches().inverse());
290 if (translatedDestType.equals(obfSourceField.getType())) {
291 out.add(obfDestField);
292 }
293 }
294 return out;
295 }
296 });
297 }
298
299 public static MemberMatches<BehaviorEntry> computeBehaviorMatches(Deobfuscator destDeobfuscator, Mappings destMappings, ClassMatches classMatches) {
300 return computeMemberMatches(destDeobfuscator, destMappings, classMatches, new Doer<BehaviorEntry>() {
301
302 @Override
303 public Collection<BehaviorEntry> getDroppedEntries(MappingsChecker checker) {
304 return checker.getDroppedMethodMappings().keySet();
305 }
306
307 @Override
308 public Collection<BehaviorEntry> getObfEntries(JarIndex jarIndex) {
309 return jarIndex.getObfBehaviorEntries();
310 }
254 311
255 public static FieldMatches computeFieldMatches(Deobfuscator destDeobfuscator, Mappings destMappings, ClassMatches classMatches) { 312 @Override
313 public Collection<? extends MemberMapping<BehaviorEntry>> getMappings(ClassMapping destClassMapping) {
314 return (Collection<? extends MemberMapping<BehaviorEntry>>)destClassMapping.methods();
315 }
316
317 @Override
318 public Set<BehaviorEntry> filterEntries(Collection<BehaviorEntry> obfDestFields, BehaviorEntry obfSourceField, ClassMatches classMatches) {
319 Set<BehaviorEntry> out = Sets.newHashSet();
320 for (BehaviorEntry obfDestField : obfDestFields) {
321 Signature translatedDestSignature = translate(obfDestField.getSignature(), classMatches.getUniqueMatches().inverse());
322 if (translatedDestSignature == null && obfSourceField.getSignature() == null) {
323 out.add(obfDestField);
324 } else if (translatedDestSignature == null || obfSourceField.getSignature() == null) {
325 // skip it
326 } else if (translatedDestSignature.equals(obfSourceField.getSignature())) {
327 out.add(obfDestField);
328 }
329 }
330 return out;
331 }
332 });
333 }
334
335 public static <T extends Entry> MemberMatches<T> computeMemberMatches(Deobfuscator destDeobfuscator, Mappings destMappings, ClassMatches classMatches, Doer<T> doer) {
256 336
257 FieldMatches fieldMatches = new FieldMatches(); 337 MemberMatches<T> memberMatches = new MemberMatches<T>();
258 338
259 // unmatched source fields are easy 339 // unmatched source fields are easy
260 MappingsChecker checker = new MappingsChecker(destDeobfuscator.getJarIndex()); 340 MappingsChecker checker = new MappingsChecker(destDeobfuscator.getJarIndex());
261 checker.dropBrokenMappings(destMappings); 341 checker.dropBrokenMappings(destMappings);
262 for (FieldEntry destObfField : checker.getDroppedFieldMappings().keySet()) { 342 for (T destObfEntry : doer.getDroppedEntries(checker)) {
263 FieldEntry srcObfField = translate(destObfField, classMatches.getUniqueMatches().inverse()); 343 T srcObfEntry = translate(destObfEntry, classMatches.getUniqueMatches().inverse());
264 fieldMatches.addUnmatchedSourceField(srcObfField); 344 memberMatches.addUnmatchedSourceEntry(srcObfEntry);
265 } 345 }
266 346
267 // get matched fields (anything that's left after the checks/drops is matched( 347 // get matched fields (anything that's left after the checks/drops is matched(
268 for (ClassMapping classMapping : destMappings.classes()) { 348 for (ClassMapping classMapping : destMappings.classes()) {
269 collectMatchedFields(fieldMatches, classMapping, classMatches); 349 collectMatchedFields(memberMatches, classMapping, classMatches, doer);
270 } 350 }
271 351
272 // get unmatched dest fields 352 // get unmatched dest fields
273 for (FieldEntry destFieldEntry : destDeobfuscator.getJarIndex().getObfFieldEntries()) { 353 for (T destEntry : doer.getObfEntries(destDeobfuscator.getJarIndex())) {
274 if (!fieldMatches.isMatchedDestField(destFieldEntry)) { 354 if (!memberMatches.isMatchedDestEntry(destEntry)) {
275 fieldMatches.addUnmatchedDestField(destFieldEntry); 355 memberMatches.addUnmatchedDestEntry(destEntry);
276 } 356 }
277 } 357 }
278 358
279 System.out.println("Automatching " + fieldMatches.getUnmatchedSourceFields().size() + " unmatched source fields..."); 359 System.out.println("Automatching " + memberMatches.getUnmatchedSourceEntries().size() + " unmatched source entries...");
280 360
281 // go through the unmatched source fields and try to pick out the easy matches 361 // go through the unmatched source fields and try to pick out the easy matches
282 for (ClassEntry obfSourceClass : Lists.newArrayList(fieldMatches.getSourceClassesWithUnmatchedFields())) { 362 for (ClassEntry obfSourceClass : Lists.newArrayList(memberMatches.getSourceClassesWithUnmatchedEntries())) {
283 for (FieldEntry obfSourceField : Lists.newArrayList(fieldMatches.getUnmatchedSourceFields(obfSourceClass))) { 363 for (T obfSourceEntry : Lists.newArrayList(memberMatches.getUnmatchedSourceEntries(obfSourceClass))) {
284 364
285 // get the possible dest matches 365 // get the possible dest matches
286 ClassEntry obfDestClass = classMatches.getUniqueMatches().get(obfSourceClass); 366 ClassEntry obfDestClass = classMatches.getUniqueMatches().get(obfSourceClass);
287 367
288 // filter by type 368 // filter by type/signature
289 Set<FieldEntry> obfDestFields = Sets.newHashSet(); 369 Set<T> obfDestEntries = doer.filterEntries(memberMatches.getUnmatchedDestEntries(obfDestClass), obfSourceEntry, classMatches);
290 for (FieldEntry obfDestField : fieldMatches.getUnmatchedDestFields(obfDestClass)) {
291 Type translatedDestType = translate(obfDestField.getType(), classMatches.getUniqueMatches().inverse());
292 if (translatedDestType.equals(obfSourceField.getType())) {
293 obfDestFields.add(obfDestField);
294 }
295 }
296 370
297 if (obfDestFields.size() == 1) { 371 if (obfDestEntries.size() == 1) {
298 // make the easy match 372 // make the easy match
299 FieldEntry obfDestField = obfDestFields.iterator().next(); 373 memberMatches.makeMatch(obfSourceEntry, obfDestEntries.iterator().next());
300 fieldMatches.makeMatch(obfSourceField, obfDestField); 374 } else if (obfDestEntries.isEmpty()) {
301 } else if (obfDestFields.isEmpty()) {
302 // no match is possible =( 375 // no match is possible =(
303 fieldMatches.makeSourceUnmatchable(obfSourceField); 376 memberMatches.makeSourceUnmatchable(obfSourceEntry);
304 } 377 }
305 } 378 }
306 } 379 }
307 380
308 System.out.println(String.format("Ended up with %d ambiguous and %d unmatchable source fields", 381 System.out.println(String.format("Ended up with %d ambiguous and %d unmatchable source entries",
309 fieldMatches.getUnmatchedSourceFields().size(), 382 memberMatches.getUnmatchedSourceEntries().size(),
310 fieldMatches.getUnmatchableSourceFields().size() 383 memberMatches.getUnmatchableSourceEntries().size()
311 )); 384 ));
312 385
313 return fieldMatches; 386 return memberMatches;
314 } 387 }
315 388
316 private static void collectMatchedFields(FieldMatches fieldMatches, ClassMapping destClassMapping, ClassMatches classMatches) { 389 private static <T extends Entry> void collectMatchedFields(MemberMatches<T> memberMatches, ClassMapping destClassMapping, ClassMatches classMatches, Doer<T> doer) {
317 390
318 // get the fields for this class 391 // get the fields for this class
319 for (FieldMapping destFieldMapping : destClassMapping.fields()) { 392 for (MemberMapping<T> destEntryMapping : doer.getMappings(destClassMapping)) {
320 FieldEntry destObfField = EntryFactory.getObfFieldEntry(destClassMapping, destFieldMapping); 393 T destObfField = destEntryMapping.getObfEntry(destClassMapping.getObfEntry());
321 FieldEntry srcObfField = translate(destObfField, classMatches.getUniqueMatches().inverse()); 394 T srcObfField = translate(destObfField, classMatches.getUniqueMatches().inverse());
322 fieldMatches.addMatch(srcObfField, destObfField); 395 memberMatches.addMatch(srcObfField, destObfField);
323 } 396 }
324 397
325 // recurse 398 // recurse
326 for (ClassMapping destInnerClassMapping : destClassMapping.innerClasses()) { 399 for (ClassMapping destInnerClassMapping : destClassMapping.innerClasses()) {
327 collectMatchedFields(fieldMatches, destInnerClassMapping, classMatches); 400 collectMatchedFields(memberMatches, destInnerClassMapping, classMatches, doer);
328 } 401 }
329 } 402 }
330 403
331 private static FieldEntry translate(FieldEntry in, BiMap<ClassEntry,ClassEntry> map) { 404 @SuppressWarnings("unchecked")
332 return new FieldEntry( 405 private static <T extends Entry> T translate(T in, BiMap<ClassEntry,ClassEntry> map) {
333 map.get(in.getClassEntry()), 406 if (in instanceof FieldEntry) {
334 in.getName(), 407 return (T)new FieldEntry(
335 translate(in.getType(), map) 408 map.get(in.getClassEntry()),
336 ); 409 in.getName(),
410 translate(((FieldEntry)in).getType(), map)
411 );
412 } else if (in instanceof MethodEntry) {
413 return (T)new MethodEntry(
414 map.get(in.getClassEntry()),
415 in.getName(),
416 translate(((MethodEntry)in).getSignature(), map)
417 );
418 } else if (in instanceof ConstructorEntry) {
419 return (T)new ConstructorEntry(
420 map.get(in.getClassEntry()),
421 translate(((ConstructorEntry)in).getSignature(), map)
422 );
423 }
424 throw new Error("Unhandled entry type: " + in.getClass());
337 } 425 }
338 426
339 private static Type translate(Type type, final BiMap<ClassEntry,ClassEntry> map) { 427 private static Type translate(Type type, final BiMap<ClassEntry,ClassEntry> map) {
@@ -348,4 +436,20 @@ public class MappingsConverter {
348 } 436 }
349 }); 437 });
350 } 438 }
439
440 private static Signature translate(Signature signature, final BiMap<ClassEntry,ClassEntry> map) {
441 if (signature == null) {
442 return null;
443 }
444 return new Signature(signature, new ClassNameReplacer() {
445 @Override
446 public String replace(String inClassName) {
447 ClassEntry outClassEntry = map.get(new ClassEntry(inClassName));
448 if (outClassEntry == null) {
449 return null;
450 }
451 return outClassEntry.getName();
452 }
453 });
454 }
351} 455}
diff --git a/src/cuchaz/enigma/convert/MatchesReader.java b/src/cuchaz/enigma/convert/MatchesReader.java
index 921ab1d0..dac2f057 100644
--- a/src/cuchaz/enigma/convert/MatchesReader.java
+++ b/src/cuchaz/enigma/convert/MatchesReader.java
@@ -10,6 +10,8 @@ import java.util.List;
10import com.beust.jcommander.internal.Lists; 10import com.beust.jcommander.internal.Lists;
11 11
12import cuchaz.enigma.mapping.ClassEntry; 12import cuchaz.enigma.mapping.ClassEntry;
13import cuchaz.enigma.mapping.Entry;
14import cuchaz.enigma.mapping.EntryFactory;
13import cuchaz.enigma.mapping.FieldEntry; 15import cuchaz.enigma.mapping.FieldEntry;
14import cuchaz.enigma.mapping.Type; 16import cuchaz.enigma.mapping.Type;
15 17
@@ -45,45 +47,57 @@ public class MatchesReader {
45 return entries; 47 return entries;
46 } 48 }
47 49
48 public static FieldMatches readFields(File file) 50 public static <T extends Entry> MemberMatches<T> readMembers(File file)
49 throws IOException { 51 throws IOException {
50 try (BufferedReader in = new BufferedReader(new FileReader(file))) { 52 try (BufferedReader in = new BufferedReader(new FileReader(file))) {
51 FieldMatches matches = new FieldMatches(); 53 MemberMatches<T> matches = new MemberMatches<T>();
52 String line = null; 54 String line = null;
53 while ((line = in.readLine()) != null) { 55 while ((line = in.readLine()) != null) {
54 readFieldMatch(matches, line); 56 readMemberMatch(matches, line);
55 } 57 }
56 return matches; 58 return matches;
57 } 59 }
58 } 60 }
59 61
60 private static void readFieldMatch(FieldMatches matches, String line) { 62 private static <T extends Entry> void readMemberMatch(MemberMatches<T> matches, String line) {
61 if (line.startsWith("!")) { 63 if (line.startsWith("!")) {
62 matches.addUnmatchableSourceField(readField(line.substring(1))); 64 T source = readEntry(line.substring(1));
65 matches.addUnmatchableSourceEntry(source);
63 } else { 66 } else {
64 String[] parts = line.split(":", 2); 67 String[] parts = line.split(":", 2);
65 FieldEntry source = readField(parts[0]); 68 T source = readEntry(parts[0]);
66 FieldEntry dest = readField(parts[1]); 69 T dest = readEntry(parts[1]);
67 if (source != null && dest != null) { 70 if (source != null && dest != null) {
68 matches.addMatch(source, dest); 71 matches.addMatch(source, dest);
69 } else if (source != null) { 72 } else if (source != null) {
70 matches.addUnmatchedSourceField(source); 73 matches.addUnmatchedSourceEntry(source);
71 } else if (dest != null) { 74 } else if (dest != null) {
72 matches.addUnmatchedDestField(dest); 75 matches.addUnmatchedDestEntry(dest);
73 } 76 }
74 } 77 }
75 } 78 }
76 79
77 private static FieldEntry readField(String in) { 80 @SuppressWarnings("unchecked")
81 private static <T extends Entry> T readEntry(String in) {
78 if (in.length() <= 0) { 82 if (in.length() <= 0) {
79 return null; 83 return null;
80 } 84 }
81 String[] parts = in.split(" "); 85 String[] parts = in.split(" ");
82 assert(parts.length == 3); 86 if (parts.length == 3 && parts[2].indexOf('(') < 0) {
83 return new FieldEntry( 87 return (T)new FieldEntry(
84 new ClassEntry(parts[0]), 88 new ClassEntry(parts[0]),
85 parts[1], 89 parts[1],
86 new Type(parts[2]) 90 new Type(parts[2])
87 ); 91 );
92 } else {
93 assert(parts.length == 2 || parts.length == 3);
94 if (parts.length == 2) {
95 return (T)EntryFactory.getBehaviorEntry(parts[0], parts[1]);
96 } else if (parts.length == 3) {
97 return (T)EntryFactory.getBehaviorEntry(parts[0], parts[1], parts[2]);
98 } else {
99 throw new Error("Malformed behavior entry: " + in);
100 }
101 }
88 } 102 }
89} 103}
diff --git a/src/cuchaz/enigma/convert/MatchesWriter.java b/src/cuchaz/enigma/convert/MatchesWriter.java
index 2118dd08..9e9ead02 100644
--- a/src/cuchaz/enigma/convert/MatchesWriter.java
+++ b/src/cuchaz/enigma/convert/MatchesWriter.java
@@ -5,7 +5,9 @@ import java.io.FileWriter;
5import java.io.IOException; 5import java.io.IOException;
6import java.util.Map; 6import java.util.Map;
7 7
8import cuchaz.enigma.mapping.BehaviorEntry;
8import cuchaz.enigma.mapping.ClassEntry; 9import cuchaz.enigma.mapping.ClassEntry;
10import cuchaz.enigma.mapping.Entry;
9import cuchaz.enigma.mapping.FieldEntry; 11import cuchaz.enigma.mapping.FieldEntry;
10 12
11 13
@@ -41,43 +43,52 @@ public class MatchesWriter {
41 } 43 }
42 } 44 }
43 45
44 public static void writeFields(FieldMatches fieldMatches, File file) 46 public static <T extends Entry> void writeMembers(MemberMatches<T> matches, File file)
45 throws IOException { 47 throws IOException {
46 try (FileWriter out = new FileWriter(file)) { 48 try (FileWriter out = new FileWriter(file)) {
47 for (Map.Entry<FieldEntry,FieldEntry> match : fieldMatches.matches().entrySet()) { 49 for (Map.Entry<T,T> match : matches.matches().entrySet()) {
48 writeFieldMatch(out, match.getKey(), match.getValue()); 50 writeMemberMatch(out, match.getKey(), match.getValue());
49 } 51 }
50 for (FieldEntry fieldEntry : fieldMatches.getUnmatchedSourceFields()) { 52 for (T entry : matches.getUnmatchedSourceEntries()) {
51 writeFieldMatch(out, fieldEntry, null); 53 writeMemberMatch(out, entry, null);
52 } 54 }
53 for (FieldEntry fieldEntry : fieldMatches.getUnmatchedDestFields()) { 55 for (T entry : matches.getUnmatchedDestEntries()) {
54 writeFieldMatch(out, null, fieldEntry); 56 writeMemberMatch(out, null, entry);
55 } 57 }
56 for (FieldEntry fieldEntry : fieldMatches.getUnmatchableSourceFields()) { 58 for (T entry : matches.getUnmatchableSourceEntries()) {
57 writeUnmatchableField(out, fieldEntry); 59 writeUnmatchableEntry(out, entry);
58 } 60 }
59 } 61 }
60 } 62 }
61 63
62 private static void writeFieldMatch(FileWriter out, FieldEntry source, FieldEntry dest) 64 private static <T extends Entry> void writeMemberMatch(FileWriter out, T source, T dest)
63 throws IOException { 65 throws IOException {
64 if (source != null) { 66 if (source != null) {
65 writeField(out, source); 67 writeEntry(out, source);
66 } 68 }
67 out.write(":"); 69 out.write(":");
68 if (dest != null) { 70 if (dest != null) {
69 writeField(out, dest); 71 writeEntry(out, dest);
70 } 72 }
71 out.write("\n"); 73 out.write("\n");
72 } 74 }
73 75
74 private static void writeUnmatchableField(FileWriter out, FieldEntry fieldEntry) 76 private static <T extends Entry> void writeUnmatchableEntry(FileWriter out, T entry)
75 throws IOException { 77 throws IOException {
76 out.write("!"); 78 out.write("!");
77 writeField(out, fieldEntry); 79 writeEntry(out, entry);
78 out.write("\n"); 80 out.write("\n");
79 } 81 }
80 82
83 private static <T extends Entry> void writeEntry(FileWriter out, T entry)
84 throws IOException {
85 if (entry instanceof FieldEntry) {
86 writeField(out, (FieldEntry)entry);
87 } else if (entry instanceof BehaviorEntry) {
88 writeBehavior(out, (BehaviorEntry)entry);
89 }
90 }
91
81 private static void writeField(FileWriter out, FieldEntry fieldEntry) 92 private static void writeField(FileWriter out, FieldEntry fieldEntry)
82 throws IOException { 93 throws IOException {
83 out.write(fieldEntry.getClassName()); 94 out.write(fieldEntry.getClassName());
@@ -86,4 +97,15 @@ public class MatchesWriter {
86 out.write(" "); 97 out.write(" ");
87 out.write(fieldEntry.getType().toString()); 98 out.write(fieldEntry.getType().toString());
88 } 99 }
100
101 private static void writeBehavior(FileWriter out, BehaviorEntry behaviorEntry)
102 throws IOException {
103 out.write(behaviorEntry.getClassName());
104 out.write(" ");
105 out.write(behaviorEntry.getName());
106 out.write(" ");
107 if (behaviorEntry.getSignature() != null) {
108 out.write(behaviorEntry.getSignature().toString());
109 }
110 }
89} 111}
diff --git a/src/cuchaz/enigma/convert/MemberMatches.java b/src/cuchaz/enigma/convert/MemberMatches.java
new file mode 100644
index 00000000..1078ab75
--- /dev/null
+++ b/src/cuchaz/enigma/convert/MemberMatches.java
@@ -0,0 +1,145 @@
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.HashMultimap;
9import com.google.common.collect.Multimap;
10import com.google.common.collect.Sets;
11
12import cuchaz.enigma.mapping.ClassEntry;
13import cuchaz.enigma.mapping.Entry;
14
15
16public class MemberMatches<T extends Entry> {
17
18 private BiMap<T,T> m_matches;
19 private Multimap<ClassEntry,T> m_matchedSourceEntries;
20 private Multimap<ClassEntry,T> m_unmatchedSourceEntries;
21 private Multimap<ClassEntry,T> m_unmatchedDestEntries;
22 private Multimap<ClassEntry,T> m_unmatchableSourceEntries;
23
24 public MemberMatches() {
25 m_matches = HashBiMap.create();
26 m_matchedSourceEntries = HashMultimap.create();
27 m_unmatchedSourceEntries = HashMultimap.create();
28 m_unmatchedDestEntries = HashMultimap.create();
29 m_unmatchableSourceEntries = HashMultimap.create();
30 }
31
32 public void addMatch(T srcEntry, T destEntry) {
33 boolean wasAdded = m_matches.put(srcEntry, destEntry) == null;
34 assert (wasAdded);
35 wasAdded = m_matchedSourceEntries.put(srcEntry.getClassEntry(), srcEntry);
36 assert (wasAdded);
37 }
38
39 public void addUnmatchedSourceEntry(T sourceEntry) {
40 boolean wasAdded = m_unmatchedSourceEntries.put(sourceEntry.getClassEntry(), sourceEntry);
41 assert (wasAdded);
42 }
43
44 public void addUnmatchedSourceEntries(Iterable<T> sourceEntries) {
45 for (T sourceEntry : sourceEntries) {
46 addUnmatchedSourceEntry(sourceEntry);
47 }
48 }
49
50 public void addUnmatchedDestEntry(T destEntry) {
51 boolean wasAdded = m_unmatchedDestEntries.put(destEntry.getClassEntry(), destEntry);
52 assert (wasAdded);
53 }
54
55 public void addUnmatchedDestEntries(Iterable<T> destEntriesntries) {
56 for (T entry : destEntriesntries) {
57 addUnmatchedDestEntry(entry);
58 }
59 }
60
61 public void addUnmatchableSourceEntry(T sourceEntry) {
62 boolean wasAdded = m_unmatchableSourceEntries.put(sourceEntry.getClassEntry(), sourceEntry);
63 assert (wasAdded);
64 }
65
66 public Set<ClassEntry> getSourceClassesWithUnmatchedEntries() {
67 return m_unmatchedSourceEntries.keySet();
68 }
69
70 public Collection<ClassEntry> getSourceClassesWithoutUnmatchedEntries() {
71 Set<ClassEntry> out = Sets.newHashSet();
72 out.addAll(m_matchedSourceEntries.keySet());
73 out.removeAll(m_unmatchedSourceEntries.keySet());
74 return out;
75 }
76
77 public Collection<T> getUnmatchedSourceEntries() {
78 return m_unmatchedSourceEntries.values();
79 }
80
81 public Collection<T> getUnmatchedSourceEntries(ClassEntry sourceClass) {
82 return m_unmatchedSourceEntries.get(sourceClass);
83 }
84
85 public Collection<T> getUnmatchedDestEntries() {
86 return m_unmatchedDestEntries.values();
87 }
88
89 public Collection<T> getUnmatchedDestEntries(ClassEntry destClass) {
90 return m_unmatchedDestEntries.get(destClass);
91 }
92
93 public Collection<T> getUnmatchableSourceEntries() {
94 return m_unmatchableSourceEntries.values();
95 }
96
97 public boolean hasSource(T sourceEntry) {
98 return m_matches.containsKey(sourceEntry) || m_unmatchedSourceEntries.containsValue(sourceEntry);
99 }
100
101 public boolean hasDest(T destEntry) {
102 return m_matches.containsValue(destEntry) || m_unmatchedDestEntries.containsValue(destEntry);
103 }
104
105 public BiMap<T,T> matches() {
106 return m_matches;
107 }
108
109 public boolean isMatchedSourceEntry(T sourceEntry) {
110 return m_matches.containsKey(sourceEntry);
111 }
112
113 public boolean isMatchedDestEntry(T destEntry) {
114 return m_matches.containsValue(destEntry);
115 }
116
117 public void makeMatch(T sourceEntry, T destEntry) {
118 boolean wasRemoved = m_unmatchedSourceEntries.remove(sourceEntry.getClassEntry(), sourceEntry);
119 assert (wasRemoved);
120 wasRemoved = m_unmatchedDestEntries.remove(destEntry.getClassEntry(), destEntry);
121 assert (wasRemoved);
122 addMatch(sourceEntry, destEntry);
123 }
124
125 public boolean isMatched(T sourceEntry, T destEntry) {
126 T match = m_matches.get(sourceEntry);
127 return match != null && match.equals(destEntry);
128 }
129
130 public void unmakeMatch(T sourceEntry, T destEntry) {
131 boolean wasRemoved = m_matches.remove(sourceEntry) != null;
132 assert (wasRemoved);
133 wasRemoved = m_matchedSourceEntries.remove(sourceEntry.getClassEntry(), sourceEntry);
134 assert (wasRemoved);
135 addUnmatchedSourceEntry(sourceEntry);
136 addUnmatchedDestEntry(destEntry);
137 }
138
139 public void makeSourceUnmatchable(T sourceEntry) {
140 assert(!isMatchedSourceEntry(sourceEntry));
141 boolean wasRemoved = m_unmatchedSourceEntries.remove(sourceEntry.getClassEntry(), sourceEntry);
142 assert (wasRemoved);
143 addUnmatchableSourceEntry(sourceEntry);
144 }
145}
diff --git a/src/cuchaz/enigma/gui/FieldMatchingGui.java b/src/cuchaz/enigma/gui/MemberMatchingGui.java
index 3f4a378c..52545b33 100644
--- a/src/cuchaz/enigma/gui/FieldMatchingGui.java
+++ b/src/cuchaz/enigma/gui/MemberMatchingGui.java
@@ -33,29 +33,28 @@ import cuchaz.enigma.analysis.EntryReference;
33import cuchaz.enigma.analysis.SourceIndex; 33import cuchaz.enigma.analysis.SourceIndex;
34import cuchaz.enigma.analysis.Token; 34import cuchaz.enigma.analysis.Token;
35import cuchaz.enigma.convert.ClassMatches; 35import cuchaz.enigma.convert.ClassMatches;
36import cuchaz.enigma.convert.FieldMatches; 36import cuchaz.enigma.convert.MemberMatches;
37import cuchaz.enigma.gui.ClassSelector.ClassSelectionListener; 37import cuchaz.enigma.gui.ClassSelector.ClassSelectionListener;
38import cuchaz.enigma.mapping.ClassEntry; 38import cuchaz.enigma.mapping.ClassEntry;
39import cuchaz.enigma.mapping.Entry; 39import cuchaz.enigma.mapping.Entry;
40import cuchaz.enigma.mapping.FieldEntry;
41import de.sciss.syntaxpane.DefaultSyntaxKit; 40import de.sciss.syntaxpane.DefaultSyntaxKit;
42 41
43 42
44public class FieldMatchingGui { 43public class MemberMatchingGui<T extends Entry> {
45 44
46 private static enum SourceType { 45 private static enum SourceType {
47 Matched { 46 Matched {
48 47
49 @Override 48 @Override
50 public Collection<ClassEntry> getObfSourceClasses(FieldMatches matches) { 49 public <T extends Entry> Collection<ClassEntry> getObfSourceClasses(MemberMatches<T> matches) {
51 return matches.getSourceClassesWithoutUnmatchedFields(); 50 return matches.getSourceClassesWithoutUnmatchedEntries();
52 } 51 }
53 }, 52 },
54 Unmatched { 53 Unmatched {
55 54
56 @Override 55 @Override
57 public Collection<ClassEntry> getObfSourceClasses(FieldMatches matches) { 56 public <T extends Entry> Collection<ClassEntry> getObfSourceClasses(MemberMatches<T> matches) {
58 return matches.getSourceClassesWithUnmatchedFields(); 57 return matches.getSourceClassesWithUnmatchedEntries();
59 } 58 }
60 }; 59 };
61 60
@@ -67,15 +66,15 @@ public class FieldMatchingGui {
67 return button; 66 return button;
68 } 67 }
69 68
70 public abstract Collection<ClassEntry> getObfSourceClasses(FieldMatches matches); 69 public abstract <T extends Entry> Collection<ClassEntry> getObfSourceClasses(MemberMatches<T> matches);
71 70
72 public static SourceType getDefault() { 71 public static SourceType getDefault() {
73 return values()[0]; 72 return values()[0];
74 } 73 }
75 } 74 }
76 75
77 public static interface SaveListener { 76 public static interface SaveListener<T extends Entry> {
78 public void save(FieldMatches matches); 77 public void save(MemberMatches<T> matches);
79 } 78 }
80 79
81 // controls 80 // controls
@@ -92,25 +91,25 @@ public class FieldMatchingGui {
92 private HighlightPainter m_matchedHighlightPainter; 91 private HighlightPainter m_matchedHighlightPainter;
93 92
94 private ClassMatches m_classMatches; 93 private ClassMatches m_classMatches;
95 private FieldMatches m_fieldMatches; 94 private MemberMatches<T> m_memberMatches;
96 private Deobfuscator m_sourceDeobfuscator; 95 private Deobfuscator m_sourceDeobfuscator;
97 private Deobfuscator m_destDeobfuscator; 96 private Deobfuscator m_destDeobfuscator;
98 private SaveListener m_saveListener; 97 private SaveListener<T> m_saveListener;
99 private SourceType m_sourceType; 98 private SourceType m_sourceType;
100 private ClassEntry m_obfSourceClass; 99 private ClassEntry m_obfSourceClass;
101 private ClassEntry m_obfDestClass; 100 private ClassEntry m_obfDestClass;
102 private FieldEntry m_obfSourceField; 101 private T m_obfSourceEntry;
103 private FieldEntry m_obfDestField; 102 private T m_obfDestEntry;
104 103
105 public FieldMatchingGui(ClassMatches classMatches, FieldMatches fieldMatches, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) { 104 public MemberMatchingGui(ClassMatches classMatches, MemberMatches<T> fieldMatches, Deobfuscator sourceDeobfuscator, Deobfuscator destDeobfuscator) {
106 105
107 m_classMatches = classMatches; 106 m_classMatches = classMatches;
108 m_fieldMatches = fieldMatches; 107 m_memberMatches = fieldMatches;
109 m_sourceDeobfuscator = sourceDeobfuscator; 108 m_sourceDeobfuscator = sourceDeobfuscator;
110 m_destDeobfuscator = destDeobfuscator; 109 m_destDeobfuscator = destDeobfuscator;
111 110
112 // init frame 111 // init frame
113 m_frame = new JFrame(Constants.Name + " - Field Matcher"); 112 m_frame = new JFrame(Constants.Name + " - Member Matcher");
114 final Container pane = m_frame.getContentPane(); 113 final Container pane = m_frame.getContentPane();
115 pane.setLayout(new BorderLayout()); 114 pane.setLayout(new BorderLayout());
116 115
@@ -225,8 +224,8 @@ public class FieldMatchingGui {
225 m_saveListener = null; 224 m_saveListener = null;
226 m_obfSourceClass = null; 225 m_obfSourceClass = null;
227 m_obfDestClass = null; 226 m_obfDestClass = null;
228 m_obfSourceField = null; 227 m_obfSourceEntry = null;
229 m_obfDestField = null; 228 m_obfDestEntry = null;
230 setSourceType(SourceType.getDefault()); 229 setSourceType(SourceType.getDefault());
231 updateButtons(); 230 updateButtons();
232 } 231 }
@@ -236,7 +235,7 @@ public class FieldMatchingGui {
236 updateSourceClasses(); 235 updateSourceClasses();
237 } 236 }
238 237
239 public void setSaveListener(SaveListener val) { 238 public void setSaveListener(SaveListener<T> val) {
240 m_saveListener = val; 239 m_saveListener = val;
241 } 240 }
242 241
@@ -245,7 +244,7 @@ public class FieldMatchingGui {
245 String selectedPackage = m_sourceClasses.getSelectedPackage(); 244 String selectedPackage = m_sourceClasses.getSelectedPackage();
246 245
247 List<ClassEntry> deobfClassEntries = Lists.newArrayList(); 246 List<ClassEntry> deobfClassEntries = Lists.newArrayList();
248 for (ClassEntry entry : m_sourceType.getObfSourceClasses(m_fieldMatches)) { 247 for (ClassEntry entry : m_sourceType.getObfSourceClasses(m_memberMatches)) {
249 deobfClassEntries.add(m_sourceDeobfuscator.deobfuscateEntry(entry)); 248 deobfClassEntries.add(m_sourceDeobfuscator.deobfuscateEntry(entry));
250 } 249 }
251 m_sourceClasses.setClasses(deobfClassEntries); 250 m_sourceClasses.setClasses(deobfClassEntries);
@@ -256,7 +255,7 @@ public class FieldMatchingGui {
256 255
257 for (SourceType sourceType : SourceType.values()) { 256 for (SourceType sourceType : SourceType.values()) {
258 m_sourceTypeButtons.get(sourceType).setText(String.format("%s (%d)", 257 m_sourceTypeButtons.get(sourceType).setText(String.format("%s (%d)",
259 sourceType.name(), sourceType.getObfSourceClasses(m_fieldMatches).size() 258 sourceType.name(), sourceType.getObfSourceClasses(m_memberMatches).size()
260 )); 259 ));
261 } 260 }
262 } 261 }
@@ -284,30 +283,30 @@ public class FieldMatchingGui {
284 } 283 }
285 284
286 protected void updateSourceHighlights() { 285 protected void updateSourceHighlights() {
287 highlightFields(m_sourceReader, m_sourceDeobfuscator, m_fieldMatches.matches().keySet(), m_fieldMatches.getUnmatchedSourceFields()); 286 highlightEntries(m_sourceReader, m_sourceDeobfuscator, m_memberMatches.matches().keySet(), m_memberMatches.getUnmatchedSourceEntries());
288 } 287 }
289 288
290 protected void updateDestHighlights() { 289 protected void updateDestHighlights() {
291 highlightFields(m_destReader, m_destDeobfuscator, m_fieldMatches.matches().values(), m_fieldMatches.getUnmatchedDestFields()); 290 highlightEntries(m_destReader, m_destDeobfuscator, m_memberMatches.matches().values(), m_memberMatches.getUnmatchedDestEntries());
292 } 291 }
293 292
294 private void highlightFields(CodeReader reader, Deobfuscator deobfuscator, Collection<FieldEntry> obfMatchedFields, Collection<FieldEntry> obfUnmatchedFields) { 293 private void highlightEntries(CodeReader reader, Deobfuscator deobfuscator, Collection<T> obfMatchedEntries, Collection<T> obfUnmatchedEntries) {
295 reader.clearHighlights(); 294 reader.clearHighlights();
296 SourceIndex index = reader.getSourceIndex(); 295 SourceIndex index = reader.getSourceIndex();
297 296
298 // matched fields 297 // matched fields
299 for (FieldEntry obfFieldEntry : obfMatchedFields) { 298 for (T obfT : obfMatchedEntries) {
300 FieldEntry deobfFieldEntry = deobfuscator.deobfuscateEntry(obfFieldEntry); 299 T deobfT = deobfuscator.deobfuscateEntry(obfT);
301 Token token = index.getDeclarationToken(deobfFieldEntry); 300 Token token = index.getDeclarationToken(deobfT);
302 if (token != null) { 301 if (token != null) {
303 reader.setHighlightedToken(token, m_matchedHighlightPainter); 302 reader.setHighlightedToken(token, m_matchedHighlightPainter);
304 } 303 }
305 } 304 }
306 305
307 // unmatched fields 306 // unmatched fields
308 for (FieldEntry obfFieldEntry : obfUnmatchedFields) { 307 for (T obfT : obfUnmatchedEntries) {
309 FieldEntry deobfFieldEntry = deobfuscator.deobfuscateEntry(obfFieldEntry); 308 T deobfT = deobfuscator.deobfuscateEntry(obfT);
310 Token token = index.getDeclarationToken(deobfFieldEntry); 309 Token token = index.getDeclarationToken(deobfT);
311 if (token != null) { 310 if (token != null) {
312 reader.setHighlightedToken(token, m_unmatchedHighlightPainter); 311 reader.setHighlightedToken(token, m_unmatchedHighlightPainter);
313 } 312 }
@@ -315,8 +314,8 @@ public class FieldMatchingGui {
315 } 314 }
316 315
317 private boolean isSelectionMatched() { 316 private boolean isSelectionMatched() {
318 return m_obfSourceField != null && m_obfDestField != null 317 return m_obfSourceEntry != null && m_obfDestEntry != null
319 && m_fieldMatches.isMatched(m_obfSourceField, m_obfDestField); 318 && m_memberMatches.isMatched(m_obfSourceEntry, m_obfDestEntry);
320 } 319 }
321 320
322 protected void onSelectSource(Entry source) { 321 protected void onSelectSource(Entry source) {
@@ -328,16 +327,22 @@ public class FieldMatchingGui {
328 setSource(null); 327 setSource(null);
329 328
330 // then look for a valid source selection 329 // then look for a valid source selection
331 if (source != null && source instanceof FieldEntry) { 330 if (source != null) {
332 FieldEntry sourceField = (FieldEntry)source; 331
333 FieldEntry obfSourceField = m_sourceDeobfuscator.obfuscateEntry(sourceField); 332 // this looks really scary, but it's actually ok
334 if (m_fieldMatches.hasSource(obfSourceField)) { 333 // Deobfuscator.obfuscateEntry can handle all implementations of Entry
335 setSource(obfSourceField); 334 // and MemberMatches.hasSource() will only pass entries that actually match T
335 @SuppressWarnings("unchecked")
336 T sourceEntry = (T)source;
337
338 T obfSourceEntry = m_sourceDeobfuscator.obfuscateEntry(sourceEntry);
339 if (m_memberMatches.hasSource(obfSourceEntry)) {
340 setSource(obfSourceEntry);
336 341
337 // look for a matched dest too 342 // look for a matched dest too
338 FieldEntry obfDestField = m_fieldMatches.matches().get(obfSourceField); 343 T obfDestEntry = m_memberMatches.matches().get(obfSourceEntry);
339 if (obfDestField != null) { 344 if (obfDestEntry != null) {
340 setDest(obfDestField); 345 setDest(obfDestEntry);
341 } 346 }
342 } 347 }
343 } 348 }
@@ -354,16 +359,22 @@ public class FieldMatchingGui {
354 setDest(null); 359 setDest(null);
355 360
356 // then look for a valid dest selection 361 // then look for a valid dest selection
357 if (dest != null && dest instanceof FieldEntry) { 362 if (dest != null) {
358 FieldEntry destField = (FieldEntry)dest; 363
359 FieldEntry obfDestField = m_destDeobfuscator.obfuscateEntry(destField); 364 // this looks really scary, but it's actually ok
360 if (m_fieldMatches.hasDest(obfDestField)) { 365 // Deobfuscator.obfuscateEntry can handle all implementations of Entry
361 setDest(obfDestField); 366 // and MemberMatches.hasSource() will only pass entries that actually match T
367 @SuppressWarnings("unchecked")
368 T destEntry = (T)dest;
369
370 T obfDestEntry = m_destDeobfuscator.obfuscateEntry(destEntry);
371 if (m_memberMatches.hasDest(obfDestEntry)) {
372 setDest(obfDestEntry);
362 373
363 // look for a matched source too 374 // look for a matched source too
364 FieldEntry obfSourceField = m_fieldMatches.matches().inverse().get(obfDestField); 375 T obfSourceEntry = m_memberMatches.matches().inverse().get(obfDestEntry);
365 if (obfSourceField != null) { 376 if (obfSourceEntry != null) {
366 setSource(obfSourceField); 377 setSource(obfSourceEntry);
367 } 378 }
368 } 379 }
369 } 380 }
@@ -371,42 +382,46 @@ public class FieldMatchingGui {
371 updateButtons(); 382 updateButtons();
372 } 383 }
373 384
374 private void setSource(FieldEntry obfField) { 385 private void setSource(T obfEntry) {
375 if (obfField == null) { 386 if (obfEntry == null) {
376 m_obfSourceField = obfField; 387 m_obfSourceEntry = obfEntry;
377 m_sourceLabel.setText(""); 388 m_sourceLabel.setText("");
378 } else { 389 } else {
379 m_obfSourceField = obfField; 390 m_obfSourceEntry = obfEntry;
380 FieldEntry deobfField = m_sourceDeobfuscator.deobfuscateEntry(obfField); 391 m_sourceLabel.setText(getEntryLabel(obfEntry, m_sourceDeobfuscator));
381 m_sourceLabel.setText(deobfField.getName() + " " + deobfField.getType().toString());
382 } 392 }
383 } 393 }
384 394
385 private void setDest(FieldEntry obfField) { 395 private void setDest(T obfEntry) {
386 if (obfField == null) { 396 if (obfEntry == null) {
387 m_obfDestField = obfField; 397 m_obfDestEntry = obfEntry;
388 m_destLabel.setText(""); 398 m_destLabel.setText("");
389 } else { 399 } else {
390 m_obfDestField = obfField; 400 m_obfDestEntry = obfEntry;
391 FieldEntry deobfField = m_destDeobfuscator.deobfuscateEntry(obfField); 401 m_destLabel.setText(getEntryLabel(obfEntry, m_destDeobfuscator));
392 m_destLabel.setText(deobfField.getName() + " " + deobfField.getType().toString());
393 } 402 }
394 } 403 }
395 404
405 private String getEntryLabel(T obfEntry, Deobfuscator deobfuscator) {
406 // deobfuscate, then take off the class name
407 T deobfEntry = deobfuscator.deobfuscateEntry(obfEntry);
408 return deobfEntry.toString().substring(deobfEntry.getClassName().length() + 1);
409 }
410
396 private void updateButtons() { 411 private void updateButtons() {
397 412
398 GuiTricks.deactivateButton(m_matchButton); 413 GuiTricks.deactivateButton(m_matchButton);
399 GuiTricks.deactivateButton(m_unmatchableButton); 414 GuiTricks.deactivateButton(m_unmatchableButton);
400 415
401 if (m_obfSourceField != null && m_obfDestField != null) { 416 if (m_obfSourceEntry != null && m_obfDestEntry != null) {
402 if (m_fieldMatches.isMatched(m_obfSourceField, m_obfDestField)) { 417 if (m_memberMatches.isMatched(m_obfSourceEntry, m_obfDestEntry)) {
403 GuiTricks.activateButton(m_matchButton, "Unmatch", new ActionListener() { 418 GuiTricks.activateButton(m_matchButton, "Unmatch", new ActionListener() {
404 @Override 419 @Override
405 public void actionPerformed(ActionEvent event) { 420 public void actionPerformed(ActionEvent event) {
406 unmatch(); 421 unmatch();
407 } 422 }
408 }); 423 });
409 } else if (!m_fieldMatches.isMatchedSourceField(m_obfSourceField) && !m_fieldMatches.isMatchedDestField(m_obfDestField)) { 424 } else if (!m_memberMatches.isMatchedSourceEntry(m_obfSourceEntry) && !m_memberMatches.isMatchedDestEntry(m_obfDestEntry)) {
410 GuiTricks.activateButton(m_matchButton, "Match", new ActionListener() { 425 GuiTricks.activateButton(m_matchButton, "Match", new ActionListener() {
411 @Override 426 @Override
412 public void actionPerformed(ActionEvent event) { 427 public void actionPerformed(ActionEvent event) {
@@ -414,7 +429,7 @@ public class FieldMatchingGui {
414 } 429 }
415 }); 430 });
416 } 431 }
417 } else if (m_obfSourceField != null) { 432 } else if (m_obfSourceEntry != null) {
418 GuiTricks.activateButton(m_unmatchableButton, "Set Unmatchable", new ActionListener() { 433 GuiTricks.activateButton(m_unmatchableButton, "Set Unmatchable", new ActionListener() {
419 @Override 434 @Override
420 public void actionPerformed(ActionEvent event) { 435 public void actionPerformed(ActionEvent event) {
@@ -427,7 +442,7 @@ public class FieldMatchingGui {
427 protected void match() { 442 protected void match() {
428 443
429 // update the field matches 444 // update the field matches
430 m_fieldMatches.makeMatch(m_obfSourceField, m_obfDestField); 445 m_memberMatches.makeMatch(m_obfSourceEntry, m_obfDestEntry);
431 save(); 446 save();
432 447
433 // update the ui 448 // update the ui
@@ -441,7 +456,7 @@ public class FieldMatchingGui {
441 protected void unmatch() { 456 protected void unmatch() {
442 457
443 // update the field matches 458 // update the field matches
444 m_fieldMatches.unmakeMatch(m_obfSourceField, m_obfDestField); 459 m_memberMatches.unmakeMatch(m_obfSourceEntry, m_obfDestEntry);
445 save(); 460 save();
446 461
447 // update the ui 462 // update the ui
@@ -455,7 +470,7 @@ public class FieldMatchingGui {
455 protected void unmatchable() { 470 protected void unmatchable() {
456 471
457 // update the field matches 472 // update the field matches
458 m_fieldMatches.makeSourceUnmatchable(m_obfSourceField); 473 m_memberMatches.makeSourceUnmatchable(m_obfSourceEntry);
459 save(); 474 save();
460 475
461 // update the ui 476 // update the ui
@@ -468,7 +483,7 @@ public class FieldMatchingGui {
468 483
469 private void save() { 484 private void save() {
470 if (m_saveListener != null) { 485 if (m_saveListener != null) {
471 m_saveListener.save(m_fieldMatches); 486 m_saveListener.save(m_memberMatches);
472 } 487 }
473 } 488 }
474} 489}
diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java
index 43605e59..07fed32a 100644
--- a/src/cuchaz/enigma/mapping/ClassMapping.java
+++ b/src/cuchaz/enigma/mapping/ClassMapping.java
@@ -434,4 +434,8 @@ public class ClassMapping implements Serializable, Comparable<ClassMapping> {
434 public static boolean isSimpleClassName(String name) { 434 public static boolean isSimpleClassName(String name) {
435 return name.indexOf('/') < 0 && name.indexOf('$') < 0; 435 return name.indexOf('/') < 0 && name.indexOf('$') < 0;
436 } 436 }
437
438 public ClassEntry getObfEntry() {
439 return new ClassEntry(m_obfFullName);
440 }
437} 441}
diff --git a/src/cuchaz/enigma/mapping/EntryFactory.java b/src/cuchaz/enigma/mapping/EntryFactory.java
index 333bb09b..7bc61839 100644
--- a/src/cuchaz/enigma/mapping/EntryFactory.java
+++ b/src/cuchaz/enigma/mapping/EntryFactory.java
@@ -138,6 +138,10 @@ public class EntryFactory {
138 public static BehaviorEntry getBehaviorEntry(String className, String behaviorName, String behaviorSignature) { 138 public static BehaviorEntry getBehaviorEntry(String className, String behaviorName, String behaviorSignature) {
139 return getBehaviorEntry(new ClassEntry(className), behaviorName, new Signature(behaviorSignature)); 139 return getBehaviorEntry(new ClassEntry(className), behaviorName, new Signature(behaviorSignature));
140 } 140 }
141
142 public static BehaviorEntry getBehaviorEntry(String className, String behaviorName) {
143 return getBehaviorEntry(new ClassEntry(className), behaviorName);
144 }
141 145
142 public static BehaviorEntry getBehaviorEntry(ClassEntry classEntry, String behaviorName, Signature behaviorSignature) { 146 public static BehaviorEntry getBehaviorEntry(ClassEntry classEntry, String behaviorName, Signature behaviorSignature) {
143 if (behaviorName.equals("<init>")) { 147 if (behaviorName.equals("<init>")) {
@@ -149,6 +153,14 @@ public class EntryFactory {
149 } 153 }
150 } 154 }
151 155
156 public static BehaviorEntry getBehaviorEntry(ClassEntry classEntry, String behaviorName) {
157 if(behaviorName.equals("<clinit>")) {
158 return new ConstructorEntry(classEntry);
159 } else {
160 throw new IllegalArgumentException("Only class initializers don't have signatures");
161 }
162 }
163
152 public static BehaviorEntry getBehaviorEntry(MethodDefinition def) { 164 public static BehaviorEntry getBehaviorEntry(MethodDefinition def) {
153 if (def.isConstructor() || def.isTypeInitializer()) { 165 if (def.isConstructor() || def.isTypeInitializer()) {
154 return getConstructorEntry(def); 166 return getConstructorEntry(def);
diff --git a/src/cuchaz/enigma/mapping/FieldMapping.java b/src/cuchaz/enigma/mapping/FieldMapping.java
index 55b0a195..1289351d 100644
--- a/src/cuchaz/enigma/mapping/FieldMapping.java
+++ b/src/cuchaz/enigma/mapping/FieldMapping.java
@@ -12,7 +12,7 @@ package cuchaz.enigma.mapping;
12 12
13import java.io.Serializable; 13import java.io.Serializable;
14 14
15public class FieldMapping implements Serializable, Comparable<FieldMapping> { 15public class FieldMapping implements Serializable, Comparable<FieldMapping>, MemberMapping<FieldEntry> {
16 16
17 private static final long serialVersionUID = 8610742471440861315L; 17 private static final long serialVersionUID = 8610742471440861315L;
18 18
@@ -72,4 +72,9 @@ public class FieldMapping implements Serializable, Comparable<FieldMapping> {
72 } 72 }
73 return false; 73 return false;
74 } 74 }
75
76 @Override
77 public FieldEntry getObfEntry(ClassEntry classEntry) {
78 return new FieldEntry(classEntry, m_obfName, new Type(m_obfType));
79 }
75} 80}
diff --git a/src/cuchaz/enigma/mapping/MemberMapping.java b/src/cuchaz/enigma/mapping/MemberMapping.java
new file mode 100644
index 00000000..d62a7c10
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/MemberMapping.java
@@ -0,0 +1,6 @@
1package cuchaz.enigma.mapping;
2
3
4public interface MemberMapping<T extends Entry> {
5 T getObfEntry(ClassEntry classEntry);
6}
diff --git a/src/cuchaz/enigma/mapping/MethodMapping.java b/src/cuchaz/enigma/mapping/MethodMapping.java
index bf8a94f3..bf6dacca 100644
--- a/src/cuchaz/enigma/mapping/MethodMapping.java
+++ b/src/cuchaz/enigma/mapping/MethodMapping.java
@@ -16,7 +16,7 @@ import java.util.Map.Entry;
16 16
17import com.google.common.collect.Maps; 17import com.google.common.collect.Maps;
18 18
19public class MethodMapping implements Serializable, Comparable<MethodMapping> { 19public class MethodMapping implements Serializable, Comparable<MethodMapping>, MemberMapping<BehaviorEntry> {
20 20
21 private static final long serialVersionUID = -4409570216084263978L; 21 private static final long serialVersionUID = -4409570216084263978L;
22 22
@@ -170,4 +170,13 @@ public class MethodMapping implements Serializable, Comparable<MethodMapping> {
170 } 170 }
171 return false; 171 return false;
172 } 172 }
173
174 @Override
175 public BehaviorEntry getObfEntry(ClassEntry classEntry) {
176 if (isConstructor()) {
177 return new ConstructorEntry(classEntry, m_obfSignature);
178 } else {
179 return new MethodEntry(classEntry, m_obfName, m_obfSignature);
180 }
181 }
173} 182}