diff options
Diffstat (limited to 'src/cuchaz/enigma/convert/MappingsConverter.java')
| -rw-r--r-- | src/cuchaz/enigma/convert/MappingsConverter.java | 130 |
1 files changed, 95 insertions, 35 deletions
diff --git a/src/cuchaz/enigma/convert/MappingsConverter.java b/src/cuchaz/enigma/convert/MappingsConverter.java index 667ee9d..9ab1baa 100644 --- a/src/cuchaz/enigma/convert/MappingsConverter.java +++ b/src/cuchaz/enigma/convert/MappingsConverter.java | |||
| @@ -17,6 +17,7 @@ import java.util.LinkedHashMap; | |||
| 17 | import java.util.List; | 17 | import java.util.List; |
| 18 | import java.util.Map; | 18 | import java.util.Map; |
| 19 | import java.util.Map.Entry; | 19 | import java.util.Map.Entry; |
| 20 | import java.util.Set; | ||
| 20 | import java.util.jar.JarFile; | 21 | import java.util.jar.JarFile; |
| 21 | 22 | ||
| 22 | import com.beust.jcommander.internal.Lists; | 23 | import com.beust.jcommander.internal.Lists; |
| @@ -24,6 +25,7 @@ import com.google.common.collect.BiMap; | |||
| 24 | import com.google.common.collect.HashMultimap; | 25 | import com.google.common.collect.HashMultimap; |
| 25 | import com.google.common.collect.Maps; | 26 | import com.google.common.collect.Maps; |
| 26 | import com.google.common.collect.Multimap; | 27 | import com.google.common.collect.Multimap; |
| 28 | import com.google.common.collect.Sets; | ||
| 27 | 29 | ||
| 28 | import cuchaz.enigma.Deobfuscator; | 30 | import cuchaz.enigma.Deobfuscator; |
| 29 | import cuchaz.enigma.analysis.JarIndex; | 31 | import cuchaz.enigma.analysis.JarIndex; |
| @@ -31,13 +33,17 @@ import cuchaz.enigma.convert.ClassNamer.SidedClassNamer; | |||
| 31 | import cuchaz.enigma.mapping.ClassEntry; | 33 | import cuchaz.enigma.mapping.ClassEntry; |
| 32 | import cuchaz.enigma.mapping.ClassMapping; | 34 | import cuchaz.enigma.mapping.ClassMapping; |
| 33 | import cuchaz.enigma.mapping.ClassNameReplacer; | 35 | import cuchaz.enigma.mapping.ClassNameReplacer; |
| 36 | import cuchaz.enigma.mapping.EntryFactory; | ||
| 37 | import cuchaz.enigma.mapping.FieldEntry; | ||
| 34 | import cuchaz.enigma.mapping.FieldMapping; | 38 | import cuchaz.enigma.mapping.FieldMapping; |
| 35 | import cuchaz.enigma.mapping.Mappings; | 39 | import cuchaz.enigma.mapping.Mappings; |
| 40 | import cuchaz.enigma.mapping.MappingsChecker; | ||
| 36 | import cuchaz.enigma.mapping.MethodMapping; | 41 | import cuchaz.enigma.mapping.MethodMapping; |
| 42 | import cuchaz.enigma.mapping.Type; | ||
| 37 | 43 | ||
| 38 | public class MappingsConverter { | 44 | public class MappingsConverter { |
| 39 | 45 | ||
| 40 | public static ClassMatches computeMatches(JarFile sourceJar, JarFile destJar, Mappings mappings) { | 46 | public static ClassMatches computeClassMatches(JarFile sourceJar, JarFile destJar, Mappings mappings) { |
| 41 | 47 | ||
| 42 | // index jars | 48 | // index jars |
| 43 | System.out.println("Indexing source jar..."); | 49 | System.out.println("Indexing source jar..."); |
| @@ -245,47 +251,101 @@ public class MappingsConverter { | |||
| 245 | mappings.renameObfClass(entry.getKey().getName(), entry.getValue().getName()); | 251 | mappings.renameObfClass(entry.getKey().getName(), entry.getValue().getName()); |
| 246 | } | 252 | } |
| 247 | } | 253 | } |
| 248 | 254 | ||
| 249 | /* TODO: after we get a mapping, check to see that the other entries match | 255 | public static FieldMatches computeFieldMatches(Deobfuscator destDeobfuscator, Mappings destMappings, ClassMatches classMatches) { |
| 250 | public static void checkMethods() { | 256 | |
| 257 | FieldMatches fieldMatches = new FieldMatches(); | ||
| 258 | |||
| 259 | // unmatched source fields are easy | ||
| 260 | MappingsChecker checker = new MappingsChecker(destDeobfuscator.getJarIndex()); | ||
| 261 | checker.dropBrokenMappings(destMappings); | ||
| 262 | for (FieldEntry destObfField : checker.getDroppedFieldMappings().keySet()) { | ||
| 263 | FieldEntry srcObfField = translate(destObfField, classMatches.getUniqueMatches().inverse()); | ||
| 264 | fieldMatches.addUnmatchedSourceField(srcObfField); | ||
| 265 | } | ||
| 251 | 266 | ||
| 252 | // check the method matches | 267 | // get matched fields (anything that's left after the checks/drops is matched( |
| 253 | System.out.println("Checking methods..."); | 268 | for (ClassMapping classMapping : destMappings.classes()) { |
| 254 | for (ClassMapping classMapping : mappings.classes()) { | 269 | collectMatchedFields(fieldMatches, classMapping, classMatches); |
| 255 | ClassEntry classEntry = new ClassEntry(classMapping.getObfFullName()); | 270 | } |
| 256 | for (MethodMapping methodMapping : classMapping.methods()) { | 271 | |
| 272 | // get unmatched dest fields | ||
| 273 | for (FieldEntry destFieldEntry : destDeobfuscator.getJarIndex().getObfFieldEntries()) { | ||
| 274 | if (!fieldMatches.isMatchedDestField(destFieldEntry)) { | ||
| 275 | fieldMatches.addUnmatchedDestField(destFieldEntry); | ||
| 276 | } | ||
| 277 | } | ||
| 278 | |||
| 279 | System.out.println("Automatching " + fieldMatches.getUnmatchedSourceFields().size() + " unmatched source fields..."); | ||
| 280 | |||
| 281 | // go through the unmatched source fields and try to pick out the easy matches | ||
| 282 | for (ClassEntry obfSourceClass : Lists.newArrayList(fieldMatches.getSourceClassesWithUnmatchedFields())) { | ||
| 283 | for (FieldEntry obfSourceField : Lists.newArrayList(fieldMatches.getUnmatchedSourceFields(obfSourceClass))) { | ||
| 257 | 284 | ||
| 258 | // skip constructors | 285 | // get the possible dest matches |
| 259 | if (methodMapping.getObfName().equals("<init>")) { | 286 | ClassEntry obfDestClass = classMatches.getUniqueMatches().get(obfSourceClass); |
| 260 | continue; | ||
| 261 | } | ||
| 262 | 287 | ||
| 263 | MethodEntry methodEntry = new MethodEntry( | 288 | // filter by type |
| 264 | classEntry, | 289 | Set<FieldEntry> obfDestFields = Sets.newHashSet(); |
| 265 | methodMapping.getObfName(), | 290 | for (FieldEntry obfDestField : fieldMatches.getUnmatchedDestFields(obfDestClass)) { |
| 266 | methodMapping.getObfSignature() | 291 | Type translatedDestType = translate(obfDestField.getType(), classMatches.getUniqueMatches().inverse()); |
| 267 | ); | 292 | if (translatedDestType.equals(obfSourceField.getType())) { |
| 268 | if (!destIndex.containsObfBehavior(methodEntry)) { | 293 | obfDestFields.add(obfDestField); |
| 269 | System.err.println("WARNING: method doesn't match: " + methodEntry); | ||
| 270 | |||
| 271 | // TODO: show methods if needed | ||
| 272 | // show the available methods | ||
| 273 | System.err.println("\tAvailable dest methods:"); | ||
| 274 | CtClass c = destLoader.loadClass(classMapping.getObfFullName()); | ||
| 275 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { | ||
| 276 | System.err.println("\t\t" + EntryFactory.getBehaviorEntry(behavior)); | ||
| 277 | } | ||
| 278 | |||
| 279 | System.err.println("\tAvailable source methods:"); | ||
| 280 | c = sourceLoader.loadClass(matchedClassNames.inverse().get(classMapping.getObfFullName())); | ||
| 281 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { | ||
| 282 | System.err.println("\t\t" + EntryFactory.getBehaviorEntry(behavior)); | ||
| 283 | } | 294 | } |
| 284 | } | 295 | } |
| 296 | |||
| 297 | if (obfDestFields.size() == 1) { | ||
| 298 | // make the easy match | ||
| 299 | FieldEntry obfDestField = obfDestFields.iterator().next(); | ||
| 300 | fieldMatches.makeMatch(obfSourceField, obfDestField); | ||
| 301 | } else if (obfDestFields.isEmpty()) { | ||
| 302 | // no match is possible =( | ||
| 303 | fieldMatches.makeSourceUnmatchable(obfSourceField); | ||
| 304 | } | ||
| 285 | } | 305 | } |
| 286 | } | 306 | } |
| 287 | 307 | ||
| 288 | System.out.println("Done!"); | 308 | System.out.println(String.format("Ended up with %d ambiguous and %d unmatchable source fields", |
| 309 | fieldMatches.getUnmatchedSourceFields().size(), | ||
| 310 | fieldMatches.getUnmatchableSourceFields().size() | ||
| 311 | )); | ||
| 312 | |||
| 313 | return fieldMatches; | ||
| 314 | } | ||
| 315 | |||
| 316 | private static void collectMatchedFields(FieldMatches fieldMatches, ClassMapping destClassMapping, ClassMatches classMatches) { | ||
| 317 | |||
| 318 | // get the fields for this class | ||
| 319 | for (FieldMapping destFieldMapping : destClassMapping.fields()) { | ||
| 320 | FieldEntry destObfField = EntryFactory.getObfFieldEntry(destClassMapping, destFieldMapping); | ||
| 321 | FieldEntry srcObfField = translate(destObfField, classMatches.getUniqueMatches().inverse()); | ||
| 322 | fieldMatches.addMatch(srcObfField, destObfField); | ||
| 323 | } | ||
| 324 | |||
| 325 | // recurse | ||
| 326 | for (ClassMapping destInnerClassMapping : destClassMapping.innerClasses()) { | ||
| 327 | collectMatchedFields(fieldMatches, destInnerClassMapping, classMatches); | ||
| 328 | } | ||
| 329 | } | ||
| 330 | |||
| 331 | private static FieldEntry translate(FieldEntry in, BiMap<ClassEntry,ClassEntry> map) { | ||
| 332 | return new FieldEntry( | ||
| 333 | map.get(in.getClassEntry()), | ||
| 334 | in.getName(), | ||
| 335 | translate(in.getType(), map) | ||
| 336 | ); | ||
| 337 | } | ||
| 338 | |||
| 339 | private static Type translate(Type type, final BiMap<ClassEntry,ClassEntry> map) { | ||
| 340 | return new Type(type, new ClassNameReplacer() { | ||
| 341 | @Override | ||
| 342 | public String replace(String inClassName) { | ||
| 343 | ClassEntry outClassEntry = map.get(new ClassEntry(inClassName)); | ||
| 344 | if (outClassEntry == null) { | ||
| 345 | return null; | ||
| 346 | } | ||
| 347 | return outClassEntry.getName(); | ||
| 348 | } | ||
| 349 | }); | ||
| 289 | } | 350 | } |
| 290 | */ | ||
| 291 | } | 351 | } |