summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/convert/MappingsConverter.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/cuchaz/enigma/convert/MappingsConverter.java')
-rw-r--r--src/cuchaz/enigma/convert/MappingsConverter.java196
1 files changed, 150 insertions, 46 deletions
diff --git a/src/cuchaz/enigma/convert/MappingsConverter.java b/src/cuchaz/enigma/convert/MappingsConverter.java
index 9ab1baa..2987ea0 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}