diff options
| author | 2015-02-09 22:23:45 -0500 | |
|---|---|---|
| committer | 2015-02-09 22:23:45 -0500 | |
| commit | af1041731c8c0ce1846ff7e7b6052ed7327a5dbc (patch) | |
| tree | e781b93f526a6c1ba7b6f5e14c319450199aa1df | |
| parent | Don't automatically move mappings around. We're more interested in stability ... (diff) | |
| download | enigma-af1041731c8c0ce1846ff7e7b6052ed7327a5dbc.tar.gz enigma-af1041731c8c0ce1846ff7e7b6052ed7327a5dbc.tar.xz enigma-af1041731c8c0ce1846ff7e7b6052ed7327a5dbc.zip | |
fix translation issues, particularly with fields
27 files changed, 507 insertions, 243 deletions
diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index b4ac501f..b54a94ac 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java | |||
| @@ -42,16 +42,17 @@ import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor; | |||
| 42 | import cuchaz.enigma.analysis.EntryReference; | 42 | import cuchaz.enigma.analysis.EntryReference; |
| 43 | import cuchaz.enigma.analysis.JarClassIterator; | 43 | import cuchaz.enigma.analysis.JarClassIterator; |
| 44 | import cuchaz.enigma.analysis.JarIndex; | 44 | import cuchaz.enigma.analysis.JarIndex; |
| 45 | import cuchaz.enigma.analysis.RelatedMethodChecker; | ||
| 45 | import cuchaz.enigma.analysis.SourceIndex; | 46 | import cuchaz.enigma.analysis.SourceIndex; |
| 46 | import cuchaz.enigma.analysis.SourceIndexVisitor; | 47 | import cuchaz.enigma.analysis.SourceIndexVisitor; |
| 47 | import cuchaz.enigma.analysis.Token; | 48 | import cuchaz.enigma.analysis.Token; |
| 48 | import cuchaz.enigma.mapping.ArgumentEntry; | 49 | import cuchaz.enigma.mapping.ArgumentEntry; |
| 49 | import cuchaz.enigma.mapping.BehaviorEntry; | 50 | import cuchaz.enigma.mapping.BehaviorEntry; |
| 50 | import cuchaz.enigma.mapping.BehaviorEntryFactory; | ||
| 51 | import cuchaz.enigma.mapping.ClassEntry; | 51 | import cuchaz.enigma.mapping.ClassEntry; |
| 52 | import cuchaz.enigma.mapping.ClassMapping; | 52 | import cuchaz.enigma.mapping.ClassMapping; |
| 53 | import cuchaz.enigma.mapping.ConstructorEntry; | 53 | import cuchaz.enigma.mapping.ConstructorEntry; |
| 54 | import cuchaz.enigma.mapping.Entry; | 54 | import cuchaz.enigma.mapping.Entry; |
| 55 | import cuchaz.enigma.mapping.EntryFactory; | ||
| 55 | import cuchaz.enigma.mapping.FieldEntry; | 56 | import cuchaz.enigma.mapping.FieldEntry; |
| 56 | import cuchaz.enigma.mapping.FieldMapping; | 57 | import cuchaz.enigma.mapping.FieldMapping; |
| 57 | import cuchaz.enigma.mapping.Mappings; | 58 | import cuchaz.enigma.mapping.Mappings; |
| @@ -115,25 +116,27 @@ public class Deobfuscator { | |||
| 115 | } | 116 | } |
| 116 | 117 | ||
| 117 | // drop mappings that don't match the jar | 118 | // drop mappings that don't match the jar |
| 119 | RelatedMethodChecker relatedMethodChecker = new RelatedMethodChecker(m_jarIndex); | ||
| 118 | for (ClassMapping classMapping : Lists.newArrayList(val.classes())) { | 120 | for (ClassMapping classMapping : Lists.newArrayList(val.classes())) { |
| 119 | if (!checkClassMapping(classMapping)) { | 121 | if (!checkClassMapping(relatedMethodChecker, classMapping)) { |
| 120 | val.removeClassMapping(classMapping); | 122 | val.removeClassMapping(classMapping); |
| 121 | } | 123 | } |
| 122 | } | 124 | } |
| 123 | 125 | ||
| 126 | // check for related method inconsistencies | ||
| 127 | if (relatedMethodChecker.hasProblems()) { | ||
| 128 | throw new Error("Related methods are inconsistent! Need to fix the mappings manually.\n" + relatedMethodChecker.getReport()); | ||
| 129 | } | ||
| 130 | |||
| 124 | m_mappings = val; | 131 | m_mappings = val; |
| 125 | m_renamer = new MappingsRenamer(m_jarIndex, val); | 132 | m_renamer = new MappingsRenamer(m_jarIndex, val); |
| 126 | m_translatorCache.clear(); | 133 | m_translatorCache.clear(); |
| 127 | } | 134 | } |
| 128 | 135 | ||
| 129 | private boolean checkClassMapping(ClassMapping classMapping) { | 136 | private boolean checkClassMapping(RelatedMethodChecker relatedMethodChecker, ClassMapping classMapping) { |
| 130 | 137 | ||
| 131 | // check the class | 138 | // check the class |
| 132 | ClassEntry classEntry = new ClassEntry(classMapping.getObfName()); | 139 | ClassEntry classEntry = EntryFactory.getObfClassEntry(m_jarIndex, classMapping); |
| 133 | String outerClassName = m_jarIndex.getOuterClass(classEntry.getSimpleName()); | ||
| 134 | if (outerClassName != null) { | ||
| 135 | classEntry = new ClassEntry(outerClassName + "$" + classMapping.getObfName()); | ||
| 136 | } | ||
| 137 | if (!m_jarIndex.getObfClassEntries().contains(classEntry)) { | 140 | if (!m_jarIndex.getObfClassEntries().contains(classEntry)) { |
| 138 | return false; | 141 | return false; |
| 139 | } | 142 | } |
| @@ -149,16 +152,18 @@ public class Deobfuscator { | |||
| 149 | 152 | ||
| 150 | // check methods | 153 | // check methods |
| 151 | for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) { | 154 | for (MethodMapping methodMapping : Lists.newArrayList(classMapping.methods())) { |
| 152 | BehaviorEntry obfBehaviorEntry = BehaviorEntryFactory.createObf(classEntry, methodMapping); | 155 | BehaviorEntry obfBehaviorEntry = EntryFactory.getObfBehaviorEntry(classEntry, methodMapping); |
| 153 | if (!m_jarIndex.containsObfBehavior(obfBehaviorEntry)) { | 156 | if (!m_jarIndex.containsObfBehavior(obfBehaviorEntry)) { |
| 154 | System.err.println("WARNING: unable to find behavior " + obfBehaviorEntry + ". dropping mapping."); | 157 | System.err.println("WARNING: unable to find behavior " + obfBehaviorEntry + ". dropping mapping."); |
| 155 | classMapping.removeMethodMapping(methodMapping); | 158 | classMapping.removeMethodMapping(methodMapping); |
| 156 | } | 159 | } |
| 160 | |||
| 161 | relatedMethodChecker.checkMethod(classEntry, methodMapping); | ||
| 157 | } | 162 | } |
| 158 | 163 | ||
| 159 | // check inner classes | 164 | // check inner classes |
| 160 | for (ClassMapping innerClassMapping : classMapping.innerClasses()) { | 165 | for (ClassMapping innerClassMapping : classMapping.innerClasses()) { |
| 161 | if (!checkClassMapping(innerClassMapping)) { | 166 | if (!checkClassMapping(relatedMethodChecker, innerClassMapping)) { |
| 162 | System.err.println("WARNING: unable to find inner class " + innerClassMapping + ". dropping mapping."); | 167 | System.err.println("WARNING: unable to find inner class " + innerClassMapping + ". dropping mapping."); |
| 163 | classMapping.removeInnerClassMapping(innerClassMapping); | 168 | classMapping.removeInnerClassMapping(innerClassMapping); |
| 164 | } | 169 | } |
diff --git a/src/cuchaz/enigma/MainFormatConverter.java b/src/cuchaz/enigma/MainFormatConverter.java index 1848144d..d4bb2db3 100644 --- a/src/cuchaz/enigma/MainFormatConverter.java +++ b/src/cuchaz/enigma/MainFormatConverter.java | |||
| @@ -18,7 +18,7 @@ import cuchaz.enigma.mapping.ClassMapping; | |||
| 18 | import cuchaz.enigma.mapping.ClassNameReplacer; | 18 | import cuchaz.enigma.mapping.ClassNameReplacer; |
| 19 | import cuchaz.enigma.mapping.FieldEntry; | 19 | import cuchaz.enigma.mapping.FieldEntry; |
| 20 | import cuchaz.enigma.mapping.FieldMapping; | 20 | import cuchaz.enigma.mapping.FieldMapping; |
| 21 | import cuchaz.enigma.mapping.JavassistUtil; | 21 | import cuchaz.enigma.mapping.EntryFactory; |
| 22 | import cuchaz.enigma.mapping.Mappings; | 22 | import cuchaz.enigma.mapping.Mappings; |
| 23 | import cuchaz.enigma.mapping.MappingsReader; | 23 | import cuchaz.enigma.mapping.MappingsReader; |
| 24 | import cuchaz.enigma.mapping.MappingsWriter; | 24 | import cuchaz.enigma.mapping.MappingsWriter; |
| @@ -35,7 +35,7 @@ public class MainFormatConverter { | |||
| 35 | Map<String,Type> fieldTypes = Maps.newHashMap(); | 35 | Map<String,Type> fieldTypes = Maps.newHashMap(); |
| 36 | for (CtClass c : JarClassIterator.classes(jar)) { | 36 | for (CtClass c : JarClassIterator.classes(jar)) { |
| 37 | for (CtField field : c.getDeclaredFields()) { | 37 | for (CtField field : c.getDeclaredFields()) { |
| 38 | FieldEntry fieldEntry = JavassistUtil.getFieldEntry(field); | 38 | FieldEntry fieldEntry = EntryFactory.getFieldEntry(field); |
| 39 | fieldTypes.put(getFieldKey(fieldEntry), moveClasssesOutOfDefaultPackage(fieldEntry.getType())); | 39 | fieldTypes.put(getFieldKey(fieldEntry), moveClasssesOutOfDefaultPackage(fieldEntry.getType())); |
| 40 | } | 40 | } |
| 41 | } | 41 | } |
diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index f54bedad..24d110ee 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java | |||
| @@ -42,12 +42,11 @@ import cuchaz.enigma.Constants; | |||
| 42 | import cuchaz.enigma.bytecode.ClassRenamer; | 42 | import cuchaz.enigma.bytecode.ClassRenamer; |
| 43 | import cuchaz.enigma.mapping.ArgumentEntry; | 43 | import cuchaz.enigma.mapping.ArgumentEntry; |
| 44 | import cuchaz.enigma.mapping.BehaviorEntry; | 44 | import cuchaz.enigma.mapping.BehaviorEntry; |
| 45 | import cuchaz.enigma.mapping.BehaviorEntryFactory; | ||
| 46 | import cuchaz.enigma.mapping.ClassEntry; | 45 | import cuchaz.enigma.mapping.ClassEntry; |
| 47 | import cuchaz.enigma.mapping.ConstructorEntry; | 46 | import cuchaz.enigma.mapping.ConstructorEntry; |
| 48 | import cuchaz.enigma.mapping.Entry; | 47 | import cuchaz.enigma.mapping.Entry; |
| 48 | import cuchaz.enigma.mapping.EntryFactory; | ||
| 49 | import cuchaz.enigma.mapping.FieldEntry; | 49 | import cuchaz.enigma.mapping.FieldEntry; |
| 50 | import cuchaz.enigma.mapping.JavassistUtil; | ||
| 51 | import cuchaz.enigma.mapping.MethodEntry; | 50 | import cuchaz.enigma.mapping.MethodEntry; |
| 52 | import cuchaz.enigma.mapping.Translator; | 51 | import cuchaz.enigma.mapping.Translator; |
| 53 | 52 | ||
| @@ -92,10 +91,10 @@ public class JarIndex { | |||
| 92 | for (CtClass c : JarClassIterator.classes(jar)) { | 91 | for (CtClass c : JarClassIterator.classes(jar)) { |
| 93 | ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); | 92 | ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NonePackage); |
| 94 | for (CtField field : c.getDeclaredFields()) { | 93 | for (CtField field : c.getDeclaredFields()) { |
| 95 | m_access.put(JavassistUtil.getFieldEntry(field), Access.get(field)); | 94 | m_access.put(EntryFactory.getFieldEntry(field), Access.get(field)); |
| 96 | } | 95 | } |
| 97 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { | 96 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { |
| 98 | m_access.put(JavassistUtil.getBehaviorEntry(behavior), Access.get(behavior)); | 97 | m_access.put(EntryFactory.getBehaviorEntry(behavior), Access.get(behavior)); |
| 99 | } | 98 | } |
| 100 | } | 99 | } |
| 101 | 100 | ||
| @@ -166,7 +165,7 @@ public class JarIndex { | |||
| 166 | 165 | ||
| 167 | private void indexBehavior(CtBehavior behavior) { | 166 | private void indexBehavior(CtBehavior behavior) { |
| 168 | // get the behavior entry | 167 | // get the behavior entry |
| 169 | final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(behavior); | 168 | final BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); |
| 170 | if (behaviorEntry instanceof MethodEntry) { | 169 | if (behaviorEntry instanceof MethodEntry) { |
| 171 | MethodEntry methodEntry = (MethodEntry)behaviorEntry; | 170 | MethodEntry methodEntry = (MethodEntry)behaviorEntry; |
| 172 | 171 | ||
| @@ -178,12 +177,12 @@ public class JarIndex { | |||
| 178 | 177 | ||
| 179 | private void indexBehaviorReferences(CtBehavior behavior) { | 178 | private void indexBehaviorReferences(CtBehavior behavior) { |
| 180 | // index method calls | 179 | // index method calls |
| 181 | final BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(behavior); | 180 | final BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); |
| 182 | try { | 181 | try { |
| 183 | behavior.instrument(new ExprEditor() { | 182 | behavior.instrument(new ExprEditor() { |
| 184 | @Override | 183 | @Override |
| 185 | public void edit(MethodCall call) { | 184 | public void edit(MethodCall call) { |
| 186 | MethodEntry calledMethodEntry = JavassistUtil.getMethodEntry(call); | 185 | MethodEntry calledMethodEntry = EntryFactory.getMethodEntry(call); |
| 187 | ClassEntry resolvedClassEntry = m_translationIndex.resolveEntryClass(calledMethodEntry); | 186 | ClassEntry resolvedClassEntry = m_translationIndex.resolveEntryClass(calledMethodEntry); |
| 188 | if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledMethodEntry.getClassEntry())) { | 187 | if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledMethodEntry.getClassEntry())) { |
| 189 | calledMethodEntry = new MethodEntry( | 188 | calledMethodEntry = new MethodEntry( |
| @@ -202,7 +201,7 @@ public class JarIndex { | |||
| 202 | 201 | ||
| 203 | @Override | 202 | @Override |
| 204 | public void edit(FieldAccess call) { | 203 | public void edit(FieldAccess call) { |
| 205 | FieldEntry calledFieldEntry = JavassistUtil.getFieldEntry(call); | 204 | FieldEntry calledFieldEntry = EntryFactory.getFieldEntry(call); |
| 206 | ClassEntry resolvedClassEntry = m_translationIndex.resolveEntryClass(calledFieldEntry); | 205 | ClassEntry resolvedClassEntry = m_translationIndex.resolveEntryClass(calledFieldEntry); |
| 207 | if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledFieldEntry.getClassEntry())) { | 206 | if (resolvedClassEntry != null && !resolvedClassEntry.equals(calledFieldEntry.getClassEntry())) { |
| 208 | calledFieldEntry = new FieldEntry(calledFieldEntry, resolvedClassEntry); | 207 | calledFieldEntry = new FieldEntry(calledFieldEntry, resolvedClassEntry); |
| @@ -217,7 +216,7 @@ public class JarIndex { | |||
| 217 | 216 | ||
| 218 | @Override | 217 | @Override |
| 219 | public void edit(ConstructorCall call) { | 218 | public void edit(ConstructorCall call) { |
| 220 | ConstructorEntry calledConstructorEntry = JavassistUtil.getConstructorEntry(call); | 219 | ConstructorEntry calledConstructorEntry = EntryFactory.getConstructorEntry(call); |
| 221 | EntryReference<BehaviorEntry,BehaviorEntry> reference = new EntryReference<BehaviorEntry,BehaviorEntry>( | 220 | EntryReference<BehaviorEntry,BehaviorEntry> reference = new EntryReference<BehaviorEntry,BehaviorEntry>( |
| 222 | calledConstructorEntry, | 221 | calledConstructorEntry, |
| 223 | call.getMethodName(), | 222 | call.getMethodName(), |
| @@ -228,7 +227,7 @@ public class JarIndex { | |||
| 228 | 227 | ||
| 229 | @Override | 228 | @Override |
| 230 | public void edit(NewExpr call) { | 229 | public void edit(NewExpr call) { |
| 231 | ConstructorEntry calledConstructorEntry = JavassistUtil.getConstructorEntry(call); | 230 | ConstructorEntry calledConstructorEntry = EntryFactory.getConstructorEntry(call); |
| 232 | EntryReference<BehaviorEntry,BehaviorEntry> reference = new EntryReference<BehaviorEntry,BehaviorEntry>( | 231 | EntryReference<BehaviorEntry,BehaviorEntry> reference = new EntryReference<BehaviorEntry,BehaviorEntry>( |
| 233 | calledConstructorEntry, | 232 | calledConstructorEntry, |
| 234 | call.getClassName(), | 233 | call.getClassName(), |
| @@ -256,7 +255,7 @@ public class JarIndex { | |||
| 256 | } | 255 | } |
| 257 | 256 | ||
| 258 | ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); | 257 | ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); |
| 259 | ConstructorEntry constructorEntry = JavassistUtil.getConstructorEntry(constructor); | 258 | ConstructorEntry constructorEntry = EntryFactory.getConstructorEntry(constructor); |
| 260 | 259 | ||
| 261 | // gather the classes from the illegally-set synthetic fields | 260 | // gather the classes from the illegally-set synthetic fields |
| 262 | Set<ClassEntry> illegallySetClasses = Sets.newHashSet(); | 261 | Set<ClassEntry> illegallySetClasses = Sets.newHashSet(); |
| @@ -422,7 +421,7 @@ public class JarIndex { | |||
| 422 | CtConstructor constructor = c.getDeclaredConstructors()[0]; | 421 | CtConstructor constructor = c.getDeclaredConstructors()[0]; |
| 423 | 422 | ||
| 424 | // is this constructor called exactly once? | 423 | // is this constructor called exactly once? |
| 425 | ConstructorEntry constructorEntry = JavassistUtil.getConstructorEntry(constructor); | 424 | ConstructorEntry constructorEntry = EntryFactory.getConstructorEntry(constructor); |
| 426 | Collection<EntryReference<BehaviorEntry,BehaviorEntry>> references = getBehaviorReferences(constructorEntry); | 425 | Collection<EntryReference<BehaviorEntry,BehaviorEntry>> references = getBehaviorReferences(constructorEntry); |
| 427 | if (references.size() != 1) { | 426 | if (references.size() != 1) { |
| 428 | return null; | 427 | return null; |
| @@ -520,17 +519,17 @@ public class JarIndex { | |||
| 520 | return rootNode; | 519 | return rootNode; |
| 521 | } | 520 | } |
| 522 | 521 | ||
| 523 | public MethodImplementationsTreeNode getMethodImplementations(Translator deobfuscatingTranslator, MethodEntry obfMethodEntry) { | 522 | public List<MethodImplementationsTreeNode> getMethodImplementations(Translator deobfuscatingTranslator, MethodEntry obfMethodEntry) { |
| 524 | 523 | ||
| 525 | MethodEntry interfaceMethodEntry; | 524 | List<MethodEntry> interfaceMethodEntries = Lists.newArrayList(); |
| 526 | 525 | ||
| 527 | // is this method on an interface? | 526 | // is this method on an interface? |
| 528 | if (isInterface(obfMethodEntry.getClassName())) { | 527 | if (isInterface(obfMethodEntry.getClassName())) { |
| 529 | interfaceMethodEntry = obfMethodEntry; | 528 | interfaceMethodEntries.add(obfMethodEntry); |
| 530 | } else { | 529 | } else { |
| 531 | // get the interface class | 530 | // get the interface class |
| 532 | List<MethodEntry> methodInterfaces = Lists.newArrayList(); | ||
| 533 | for (String interfaceName : getInterfaces(obfMethodEntry.getClassName())) { | 531 | for (String interfaceName : getInterfaces(obfMethodEntry.getClassName())) { |
| 532 | |||
| 534 | // is this method defined in this interface? | 533 | // is this method defined in this interface? |
| 535 | MethodEntry methodInterface = new MethodEntry( | 534 | MethodEntry methodInterface = new MethodEntry( |
| 536 | new ClassEntry(interfaceName), | 535 | new ClassEntry(interfaceName), |
| @@ -538,21 +537,20 @@ public class JarIndex { | |||
| 538 | obfMethodEntry.getSignature() | 537 | obfMethodEntry.getSignature() |
| 539 | ); | 538 | ); |
| 540 | if (containsObfBehavior(methodInterface)) { | 539 | if (containsObfBehavior(methodInterface)) { |
| 541 | methodInterfaces.add(methodInterface); | 540 | interfaceMethodEntries.add(methodInterface); |
| 542 | } | 541 | } |
| 543 | } | 542 | } |
| 544 | if (methodInterfaces.isEmpty()) { | ||
| 545 | return null; | ||
| 546 | } | ||
| 547 | if (methodInterfaces.size() > 1) { | ||
| 548 | throw new Error("Too many interfaces define this method! This is not yet supported by Enigma!"); | ||
| 549 | } | ||
| 550 | interfaceMethodEntry = methodInterfaces.get(0); | ||
| 551 | } | 543 | } |
| 552 | 544 | ||
| 553 | MethodImplementationsTreeNode rootNode = new MethodImplementationsTreeNode(deobfuscatingTranslator, interfaceMethodEntry); | 545 | List<MethodImplementationsTreeNode> nodes = Lists.newArrayList(); |
| 554 | rootNode.load(this); | 546 | if (!interfaceMethodEntries.isEmpty()) { |
| 555 | return rootNode; | 547 | for (MethodEntry interfaceMethodEntry : interfaceMethodEntries) { |
| 548 | MethodImplementationsTreeNode node = new MethodImplementationsTreeNode(deobfuscatingTranslator, interfaceMethodEntry); | ||
| 549 | node.load(this); | ||
| 550 | nodes.add(node); | ||
| 551 | } | ||
| 552 | } | ||
| 553 | return nodes; | ||
| 556 | } | 554 | } |
| 557 | 555 | ||
| 558 | public Set<MethodEntry> getRelatedMethodImplementations(MethodEntry obfMethodEntry) { | 556 | public Set<MethodEntry> getRelatedMethodImplementations(MethodEntry obfMethodEntry) { |
| @@ -569,9 +567,8 @@ public class JarIndex { | |||
| 569 | } | 567 | } |
| 570 | 568 | ||
| 571 | // look at interface methods too | 569 | // look at interface methods too |
| 572 | MethodImplementationsTreeNode implementations = getMethodImplementations(null, methodEntry); | 570 | for (MethodImplementationsTreeNode implementationsNode : getMethodImplementations(null, methodEntry)) { |
| 573 | if (implementations != null) { | 571 | getRelatedMethodImplementations(methodEntries, implementationsNode); |
| 574 | getRelatedMethodImplementations(methodEntries, implementations); | ||
| 575 | } | 572 | } |
| 576 | 573 | ||
| 577 | // recurse | 574 | // recurse |
diff --git a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java index 10092268..6cafc55b 100644 --- a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java +++ b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java | |||
| @@ -63,6 +63,7 @@ public class MethodImplementationsTreeNode extends DefaultMutableTreeNode { | |||
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | public void load(JarIndex index) { | 65 | public void load(JarIndex index) { |
| 66 | |||
| 66 | // get all method implementations | 67 | // get all method implementations |
| 67 | List<MethodImplementationsTreeNode> nodes = Lists.newArrayList(); | 68 | List<MethodImplementationsTreeNode> nodes = Lists.newArrayList(); |
| 68 | for (String implementingClassName : index.getImplementingClasses(m_entry.getClassName())) { | 69 | for (String implementingClassName : index.getImplementingClasses(m_entry.getClassName())) { |
diff --git a/src/cuchaz/enigma/analysis/RelatedMethodChecker.java b/src/cuchaz/enigma/analysis/RelatedMethodChecker.java new file mode 100644 index 00000000..5bd67a0a --- /dev/null +++ b/src/cuchaz/enigma/analysis/RelatedMethodChecker.java | |||
| @@ -0,0 +1,96 @@ | |||
| 1 | package cuchaz.enigma.analysis; | ||
| 2 | |||
| 3 | import java.util.Map; | ||
| 4 | import java.util.Set; | ||
| 5 | |||
| 6 | import com.beust.jcommander.internal.Maps; | ||
| 7 | import com.google.common.collect.Sets; | ||
| 8 | |||
| 9 | import cuchaz.enigma.mapping.BehaviorEntry; | ||
| 10 | import cuchaz.enigma.mapping.ClassEntry; | ||
| 11 | import cuchaz.enigma.mapping.EntryFactory; | ||
| 12 | import cuchaz.enigma.mapping.MethodEntry; | ||
| 13 | import cuchaz.enigma.mapping.MethodMapping; | ||
| 14 | |||
| 15 | public class RelatedMethodChecker { | ||
| 16 | |||
| 17 | private JarIndex m_jarIndex; | ||
| 18 | private Map<Set<MethodEntry>,String> m_deobfNamesByGroup; | ||
| 19 | private Map<MethodEntry,String> m_deobfNamesByObfMethod; | ||
| 20 | private Map<MethodEntry,Set<MethodEntry>> m_groupsByObfMethod; | ||
| 21 | private Set<Set<MethodEntry>> m_inconsistentGroups; | ||
| 22 | |||
| 23 | public RelatedMethodChecker(JarIndex jarIndex) { | ||
| 24 | m_jarIndex = jarIndex; | ||
| 25 | m_deobfNamesByGroup = Maps.newHashMap(); | ||
| 26 | m_deobfNamesByObfMethod = Maps.newHashMap(); | ||
| 27 | m_groupsByObfMethod = Maps.newHashMap(); | ||
| 28 | m_inconsistentGroups = Sets.newHashSet(); | ||
| 29 | } | ||
| 30 | |||
| 31 | public void checkMethod(ClassEntry classEntry, MethodMapping methodMapping) { | ||
| 32 | |||
| 33 | // TEMP: disable the expensive check for now, maybe we can optimize it later, or just use it for debugging | ||
| 34 | if (true) return; | ||
| 35 | |||
| 36 | BehaviorEntry obfBehaviorEntry = EntryFactory.getObfBehaviorEntry(classEntry, methodMapping); | ||
| 37 | if (!(obfBehaviorEntry instanceof MethodEntry)) { | ||
| 38 | // only methods have related implementations | ||
| 39 | return; | ||
| 40 | } | ||
| 41 | MethodEntry obfMethodEntry = (MethodEntry)obfBehaviorEntry; | ||
| 42 | String deobfName = methodMapping.getDeobfName(); | ||
| 43 | m_deobfNamesByObfMethod.put(obfMethodEntry, deobfName); | ||
| 44 | |||
| 45 | // have we seen this method's group before? | ||
| 46 | Set<MethodEntry> group = m_groupsByObfMethod.get(obfMethodEntry); | ||
| 47 | if (group == null) { | ||
| 48 | |||
| 49 | // no, compute the group and save the name | ||
| 50 | group = m_jarIndex.getRelatedMethodImplementations(obfMethodEntry); | ||
| 51 | m_deobfNamesByGroup.put(group, deobfName); | ||
| 52 | |||
| 53 | assert(group.contains(obfMethodEntry)); | ||
| 54 | for (MethodEntry relatedMethodEntry : group) { | ||
| 55 | m_groupsByObfMethod.put(relatedMethodEntry, group); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | // check the name | ||
| 60 | if (!sameName(m_deobfNamesByGroup.get(group), deobfName)) { | ||
| 61 | m_inconsistentGroups.add(group); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | private boolean sameName(String a, String b) { | ||
| 66 | if (a == null && b == null) { | ||
| 67 | return true; | ||
| 68 | } else if (a != null && b != null) { | ||
| 69 | return a.equals(b); | ||
| 70 | } | ||
| 71 | return false; | ||
| 72 | } | ||
| 73 | |||
| 74 | public boolean hasProblems() { | ||
| 75 | return m_inconsistentGroups.size() > 0; | ||
| 76 | } | ||
| 77 | |||
| 78 | public String getReport() { | ||
| 79 | StringBuilder buf = new StringBuilder(); | ||
| 80 | buf.append(m_inconsistentGroups.size()); | ||
| 81 | buf.append(" groups of methods related by inheritance and/or interfaces have different deobf names!\n"); | ||
| 82 | for (Set<MethodEntry> group : m_inconsistentGroups) { | ||
| 83 | buf.append("\tGroup with "); | ||
| 84 | buf.append(group.size()); | ||
| 85 | buf.append(" methods:\n"); | ||
| 86 | for (MethodEntry methodEntry : group) { | ||
| 87 | buf.append("\t\t"); | ||
| 88 | buf.append(methodEntry.toString()); | ||
| 89 | buf.append(" => "); | ||
| 90 | buf.append(m_deobfNamesByObfMethod.get(methodEntry)); | ||
| 91 | buf.append("\n"); | ||
| 92 | } | ||
| 93 | } | ||
| 94 | return buf.toString(); | ||
| 95 | } | ||
| 96 | } | ||
diff --git a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java index e2ff3004..d6692f60 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexClassVisitor.java | |||
| @@ -26,11 +26,10 @@ import com.strobel.decompiler.languages.java.ast.TypeDeclaration; | |||
| 26 | import com.strobel.decompiler.languages.java.ast.VariableInitializer; | 26 | import com.strobel.decompiler.languages.java.ast.VariableInitializer; |
| 27 | 27 | ||
| 28 | import cuchaz.enigma.mapping.BehaviorEntry; | 28 | import cuchaz.enigma.mapping.BehaviorEntry; |
| 29 | import cuchaz.enigma.mapping.BehaviorEntryFactory; | ||
| 30 | import cuchaz.enigma.mapping.ClassEntry; | 29 | import cuchaz.enigma.mapping.ClassEntry; |
| 31 | import cuchaz.enigma.mapping.ConstructorEntry; | 30 | import cuchaz.enigma.mapping.ConstructorEntry; |
| 31 | import cuchaz.enigma.mapping.EntryFactory; | ||
| 32 | import cuchaz.enigma.mapping.FieldEntry; | 32 | import cuchaz.enigma.mapping.FieldEntry; |
| 33 | import cuchaz.enigma.mapping.Signature; | ||
| 34 | import cuchaz.enigma.mapping.Type; | 33 | import cuchaz.enigma.mapping.Type; |
| 35 | 34 | ||
| 36 | public class SourceIndexClassVisitor extends SourceIndexVisitor { | 35 | public class SourceIndexClassVisitor extends SourceIndexVisitor { |
| @@ -69,12 +68,13 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor { | |||
| 69 | @Override | 68 | @Override |
| 70 | public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) { | 69 | public Void visitMethodDeclaration(MethodDeclaration node, SourceIndex index) { |
| 71 | MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); | 70 | MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); |
| 72 | ClassEntry classEntry = new ClassEntry(def.getDeclaringType().getInternalName()); | 71 | BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(def); |
| 73 | BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(classEntry, def.getName(), def.getSignature()); | ||
| 74 | AstNode tokenNode = node.getNameToken(); | 72 | AstNode tokenNode = node.getNameToken(); |
| 73 | |||
| 75 | if (behaviorEntry instanceof ConstructorEntry) { | 74 | if (behaviorEntry instanceof ConstructorEntry) { |
| 76 | ConstructorEntry constructorEntry = (ConstructorEntry)behaviorEntry; | 75 | ConstructorEntry constructorEntry = (ConstructorEntry)behaviorEntry; |
| 77 | if (constructorEntry.isStatic()) { | 76 | if (constructorEntry.isStatic()) { |
| 77 | // for static initializers, check elsewhere for the token node | ||
| 78 | tokenNode = node.getModifiers().firstOrNullObject(); | 78 | tokenNode = node.getModifiers().firstOrNullObject(); |
| 79 | } | 79 | } |
| 80 | } | 80 | } |
| @@ -85,8 +85,7 @@ public class SourceIndexClassVisitor extends SourceIndexVisitor { | |||
| 85 | @Override | 85 | @Override |
| 86 | public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) { | 86 | public Void visitConstructorDeclaration(ConstructorDeclaration node, SourceIndex index) { |
| 87 | MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); | 87 | MethodDefinition def = node.getUserData(Keys.METHOD_DEFINITION); |
| 88 | ClassEntry classEntry = new ClassEntry(def.getDeclaringType().getInternalName()); | 88 | ConstructorEntry constructorEntry = EntryFactory.getConstructorEntry(def); |
| 89 | ConstructorEntry constructorEntry = new ConstructorEntry(classEntry, new Signature(def.getSignature())); | ||
| 90 | index.addDeclaration(node.getNameToken(), constructorEntry); | 89 | index.addDeclaration(node.getNameToken(), constructorEntry); |
| 91 | return node.acceptVisitor(new SourceIndexBehaviorVisitor(constructorEntry), index); | 90 | return node.acceptVisitor(new SourceIndexBehaviorVisitor(constructorEntry), index); |
| 92 | } | 91 | } |
diff --git a/src/cuchaz/enigma/analysis/TranslationIndex.java b/src/cuchaz/enigma/analysis/TranslationIndex.java index 7597c3ae..8651ebd6 100644 --- a/src/cuchaz/enigma/analysis/TranslationIndex.java +++ b/src/cuchaz/enigma/analysis/TranslationIndex.java | |||
| @@ -37,7 +37,7 @@ import cuchaz.enigma.mapping.BehaviorEntry; | |||
| 37 | import cuchaz.enigma.mapping.ClassEntry; | 37 | import cuchaz.enigma.mapping.ClassEntry; |
| 38 | import cuchaz.enigma.mapping.Entry; | 38 | import cuchaz.enigma.mapping.Entry; |
| 39 | import cuchaz.enigma.mapping.FieldEntry; | 39 | import cuchaz.enigma.mapping.FieldEntry; |
| 40 | import cuchaz.enigma.mapping.JavassistUtil; | 40 | import cuchaz.enigma.mapping.EntryFactory; |
| 41 | import cuchaz.enigma.mapping.Translator; | 41 | import cuchaz.enigma.mapping.Translator; |
| 42 | 42 | ||
| 43 | public class TranslationIndex implements Serializable { | 43 | public class TranslationIndex implements Serializable { |
| @@ -85,23 +85,23 @@ public class TranslationIndex implements Serializable { | |||
| 85 | 85 | ||
| 86 | public void indexClass(CtClass c) { | 86 | public void indexClass(CtClass c) { |
| 87 | 87 | ||
| 88 | ClassEntry classEntry = JavassistUtil.getClassEntry(c); | 88 | ClassEntry classEntry = EntryFactory.getClassEntry(c); |
| 89 | 89 | ||
| 90 | // add the superclass | 90 | // add the superclass |
| 91 | ClassEntry superclassEntry = JavassistUtil.getSuperclassEntry(c); | 91 | ClassEntry superclassEntry = EntryFactory.getSuperclassEntry(c); |
| 92 | if (!isJre(classEntry) && superclassEntry != null && !isJre(superclassEntry)) { | 92 | if (!isJre(classEntry) && superclassEntry != null && !isJre(superclassEntry)) { |
| 93 | m_superclasses.put(classEntry, superclassEntry); | 93 | m_superclasses.put(classEntry, superclassEntry); |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | // add fields | 96 | // add fields |
| 97 | for (CtField field : c.getDeclaredFields()) { | 97 | for (CtField field : c.getDeclaredFields()) { |
| 98 | FieldEntry fieldEntry = JavassistUtil.getFieldEntry(field); | 98 | FieldEntry fieldEntry = EntryFactory.getFieldEntry(field); |
| 99 | m_fieldEntries.put(fieldEntry.getClassEntry(), fieldEntry); | 99 | m_fieldEntries.put(fieldEntry.getClassEntry(), fieldEntry); |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | // add behaviors | 102 | // add behaviors |
| 103 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { | 103 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { |
| 104 | BehaviorEntry behaviorEntry = JavassistUtil.getBehaviorEntry(behavior); | 104 | BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); |
| 105 | m_behaviorEntries.put(behaviorEntry.getClassEntry(), behaviorEntry); | 105 | m_behaviorEntries.put(behaviorEntry.getClassEntry(), behaviorEntry); |
| 106 | } | 106 | } |
| 107 | } | 107 | } |
diff --git a/src/cuchaz/enigma/bytecode/ClassTranslator.java b/src/cuchaz/enigma/bytecode/ClassTranslator.java index 4dba0d87..4167731a 100644 --- a/src/cuchaz/enigma/bytecode/ClassTranslator.java +++ b/src/cuchaz/enigma/bytecode/ClassTranslator.java | |||
| @@ -23,10 +23,9 @@ import javassist.bytecode.SourceFileAttribute; | |||
| 23 | import com.google.common.collect.Maps; | 23 | import com.google.common.collect.Maps; |
| 24 | 24 | ||
| 25 | import cuchaz.enigma.mapping.BehaviorEntry; | 25 | import cuchaz.enigma.mapping.BehaviorEntry; |
| 26 | import cuchaz.enigma.mapping.BehaviorEntryFactory; | ||
| 27 | import cuchaz.enigma.mapping.ClassEntry; | 26 | import cuchaz.enigma.mapping.ClassEntry; |
| 27 | import cuchaz.enigma.mapping.EntryFactory; | ||
| 28 | import cuchaz.enigma.mapping.FieldEntry; | 28 | import cuchaz.enigma.mapping.FieldEntry; |
| 29 | import cuchaz.enigma.mapping.JavassistUtil; | ||
| 30 | import cuchaz.enigma.mapping.MethodEntry; | 29 | import cuchaz.enigma.mapping.MethodEntry; |
| 31 | import cuchaz.enigma.mapping.Signature; | 30 | import cuchaz.enigma.mapping.Signature; |
| 32 | import cuchaz.enigma.mapping.Translator; | 31 | import cuchaz.enigma.mapping.Translator; |
| @@ -74,7 +73,7 @@ public class ClassTranslator { | |||
| 74 | case ConstPool.CONST_InterfaceMethodref: { | 73 | case ConstPool.CONST_InterfaceMethodref: { |
| 75 | 74 | ||
| 76 | // translate the name and type | 75 | // translate the name and type |
| 77 | BehaviorEntry entry = BehaviorEntryFactory.create( | 76 | BehaviorEntry entry = EntryFactory.getBehaviorEntry( |
| 78 | Descriptor.toJvmName(editor.getMemberrefClassname(i)), | 77 | Descriptor.toJvmName(editor.getMemberrefClassname(i)), |
| 79 | editor.getMemberrefName(i), | 78 | editor.getMemberrefName(i), |
| 80 | editor.getMemberrefType(i) | 79 | editor.getMemberrefType(i) |
| @@ -95,7 +94,7 @@ public class ClassTranslator { | |||
| 95 | for (CtField field : c.getDeclaredFields()) { | 94 | for (CtField field : c.getDeclaredFields()) { |
| 96 | 95 | ||
| 97 | // translate the name | 96 | // translate the name |
| 98 | FieldEntry entry = JavassistUtil.getFieldEntry(field); | 97 | FieldEntry entry = EntryFactory.getFieldEntry(field); |
| 99 | String translatedName = m_translator.translate(entry); | 98 | String translatedName = m_translator.translate(entry); |
| 100 | if (translatedName != null) { | 99 | if (translatedName != null) { |
| 101 | field.setName(translatedName); | 100 | field.setName(translatedName); |
| @@ -112,7 +111,7 @@ public class ClassTranslator { | |||
| 112 | CtMethod method = (CtMethod)behavior; | 111 | CtMethod method = (CtMethod)behavior; |
| 113 | 112 | ||
| 114 | // translate the name | 113 | // translate the name |
| 115 | MethodEntry entry = JavassistUtil.getMethodEntry(method); | 114 | MethodEntry entry = EntryFactory.getMethodEntry(method); |
| 116 | String translatedName = m_translator.translate(entry); | 115 | String translatedName = m_translator.translate(entry); |
| 117 | if (translatedName != null) { | 116 | if (translatedName != null) { |
| 118 | method.setName(translatedName); | 117 | method.setName(translatedName); |
diff --git a/src/cuchaz/enigma/bytecode/MethodParameterWriter.java b/src/cuchaz/enigma/bytecode/MethodParameterWriter.java index 853928c7..f64ca02a 100644 --- a/src/cuchaz/enigma/bytecode/MethodParameterWriter.java +++ b/src/cuchaz/enigma/bytecode/MethodParameterWriter.java | |||
| @@ -17,7 +17,7 @@ import javassist.CtBehavior; | |||
| 17 | import javassist.CtClass; | 17 | import javassist.CtClass; |
| 18 | import cuchaz.enigma.mapping.ArgumentEntry; | 18 | import cuchaz.enigma.mapping.ArgumentEntry; |
| 19 | import cuchaz.enigma.mapping.BehaviorEntry; | 19 | import cuchaz.enigma.mapping.BehaviorEntry; |
| 20 | import cuchaz.enigma.mapping.BehaviorEntryFactory; | 20 | import cuchaz.enigma.mapping.EntryFactory; |
| 21 | import cuchaz.enigma.mapping.Signature; | 21 | import cuchaz.enigma.mapping.Signature; |
| 22 | import cuchaz.enigma.mapping.Translator; | 22 | import cuchaz.enigma.mapping.Translator; |
| 23 | 23 | ||
| @@ -33,7 +33,7 @@ public class MethodParameterWriter { | |||
| 33 | 33 | ||
| 34 | // Procyon will read method arguments from the "MethodParameters" attribute, so write those | 34 | // Procyon will read method arguments from the "MethodParameters" attribute, so write those |
| 35 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { | 35 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { |
| 36 | BehaviorEntry behaviorEntry = BehaviorEntryFactory.create(behavior); | 36 | BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); |
| 37 | 37 | ||
| 38 | // get the number of arguments | 38 | // get the number of arguments |
| 39 | Signature signature = behaviorEntry.getSignature(); | 39 | Signature signature = behaviorEntry.getSignature(); |
diff --git a/src/cuchaz/enigma/convert/ClassIdentity.java b/src/cuchaz/enigma/convert/ClassIdentity.java index bb729a36..b5140124 100644 --- a/src/cuchaz/enigma/convert/ClassIdentity.java +++ b/src/cuchaz/enigma/convert/ClassIdentity.java | |||
| @@ -53,7 +53,7 @@ import cuchaz.enigma.mapping.ClassEntry; | |||
| 53 | import cuchaz.enigma.mapping.ClassNameReplacer; | 53 | import cuchaz.enigma.mapping.ClassNameReplacer; |
| 54 | import cuchaz.enigma.mapping.Entry; | 54 | import cuchaz.enigma.mapping.Entry; |
| 55 | import cuchaz.enigma.mapping.FieldEntry; | 55 | import cuchaz.enigma.mapping.FieldEntry; |
| 56 | import cuchaz.enigma.mapping.JavassistUtil; | 56 | import cuchaz.enigma.mapping.EntryFactory; |
| 57 | import cuchaz.enigma.mapping.Signature; | 57 | import cuchaz.enigma.mapping.Signature; |
| 58 | 58 | ||
| 59 | public class ClassIdentity { | 59 | public class ClassIdentity { |
| @@ -116,13 +116,13 @@ public class ClassIdentity { | |||
| 116 | m_references = HashMultiset.create(); | 116 | m_references = HashMultiset.create(); |
| 117 | if (useReferences) { | 117 | if (useReferences) { |
| 118 | for (CtField field : c.getDeclaredFields()) { | 118 | for (CtField field : c.getDeclaredFields()) { |
| 119 | FieldEntry fieldEntry = JavassistUtil.getFieldEntry(field); | 119 | FieldEntry fieldEntry = EntryFactory.getFieldEntry(field); |
| 120 | for (EntryReference<FieldEntry,BehaviorEntry> reference : index.getFieldReferences(fieldEntry)) { | 120 | for (EntryReference<FieldEntry,BehaviorEntry> reference : index.getFieldReferences(fieldEntry)) { |
| 121 | addReference(reference); | 121 | addReference(reference); |
| 122 | } | 122 | } |
| 123 | } | 123 | } |
| 124 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { | 124 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { |
| 125 | BehaviorEntry behaviorEntry = JavassistUtil.getBehaviorEntry(behavior); | 125 | BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior); |
| 126 | for (EntryReference<BehaviorEntry,BehaviorEntry> reference : index.getBehaviorReferences(behaviorEntry)) { | 126 | for (EntryReference<BehaviorEntry,BehaviorEntry> reference : index.getBehaviorReferences(behaviorEntry)) { |
| 127 | addReference(reference); | 127 | addReference(reference); |
| 128 | } | 128 | } |
diff --git a/src/cuchaz/enigma/convert/ClassMatcher.java b/src/cuchaz/enigma/convert/ClassMatcher.java index ccf6b787..d70b8ebb 100644 --- a/src/cuchaz/enigma/convert/ClassMatcher.java +++ b/src/cuchaz/enigma/convert/ClassMatcher.java | |||
| @@ -42,7 +42,7 @@ import cuchaz.enigma.analysis.JarIndex; | |||
| 42 | import cuchaz.enigma.convert.ClassNamer.SidedClassNamer; | 42 | import cuchaz.enigma.convert.ClassNamer.SidedClassNamer; |
| 43 | import cuchaz.enigma.mapping.ClassEntry; | 43 | import cuchaz.enigma.mapping.ClassEntry; |
| 44 | import cuchaz.enigma.mapping.ClassMapping; | 44 | import cuchaz.enigma.mapping.ClassMapping; |
| 45 | import cuchaz.enigma.mapping.JavassistUtil; | 45 | import cuchaz.enigma.mapping.EntryFactory; |
| 46 | import cuchaz.enigma.mapping.MappingParseException; | 46 | import cuchaz.enigma.mapping.MappingParseException; |
| 47 | import cuchaz.enigma.mapping.Mappings; | 47 | import cuchaz.enigma.mapping.Mappings; |
| 48 | import cuchaz.enigma.mapping.MappingsReader; | 48 | import cuchaz.enigma.mapping.MappingsReader; |
| @@ -242,13 +242,13 @@ public class ClassMatcher { | |||
| 242 | System.err.println("\tAvailable dest methods:"); | 242 | System.err.println("\tAvailable dest methods:"); |
| 243 | CtClass c = destLoader.loadClass(classMapping.getObfName()); | 243 | CtClass c = destLoader.loadClass(classMapping.getObfName()); |
| 244 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { | 244 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { |
| 245 | System.err.println("\t\t" + JavassistUtil.getBehaviorEntry(behavior)); | 245 | System.err.println("\t\t" + EntryFactory.getBehaviorEntry(behavior)); |
| 246 | } | 246 | } |
| 247 | 247 | ||
| 248 | System.err.println("\tAvailable source methods:"); | 248 | System.err.println("\tAvailable source methods:"); |
| 249 | c = sourceLoader.loadClass(matchedClassNames.inverse().get(classMapping.getObfName())); | 249 | c = sourceLoader.loadClass(matchedClassNames.inverse().get(classMapping.getObfName())); |
| 250 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { | 250 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { |
| 251 | System.err.println("\t\t" + JavassistUtil.getBehaviorEntry(behavior)); | 251 | System.err.println("\t\t" + EntryFactory.getBehaviorEntry(behavior)); |
| 252 | } | 252 | } |
| 253 | } | 253 | } |
| 254 | } | 254 | } |
diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 61fea9c0..9fa633eb 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java | |||
| @@ -186,14 +186,17 @@ public class GuiController { | |||
| 186 | 186 | ||
| 187 | public MethodImplementationsTreeNode getMethodImplementations(MethodEntry deobfMethodEntry) { | 187 | public MethodImplementationsTreeNode getMethodImplementations(MethodEntry deobfMethodEntry) { |
| 188 | MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry(deobfMethodEntry); | 188 | MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry(deobfMethodEntry); |
| 189 | MethodImplementationsTreeNode rootNode = m_deobfuscator.getJarIndex().getMethodImplementations( | 189 | List<MethodImplementationsTreeNode> rootNodes = m_deobfuscator.getJarIndex().getMethodImplementations( |
| 190 | m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating), | 190 | m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating), |
| 191 | obfMethodEntry | 191 | obfMethodEntry |
| 192 | ); | 192 | ); |
| 193 | if (rootNode == null) { | 193 | if (rootNodes.isEmpty()) { |
| 194 | return null; | 194 | return null; |
| 195 | } | 195 | } |
| 196 | return MethodImplementationsTreeNode.findNode(rootNode, obfMethodEntry); | 196 | if (rootNodes.size() > 1) { |
| 197 | System.err.println("WARNING: Method " + deobfMethodEntry + " implements multiple interfaces. Only showing first one."); | ||
| 198 | } | ||
| 199 | return MethodImplementationsTreeNode.findNode(rootNodes.get(0), obfMethodEntry); | ||
| 197 | } | 200 | } |
| 198 | 201 | ||
| 199 | public FieldReferenceTreeNode getFieldReferences(FieldEntry deobfFieldEntry) { | 202 | public FieldReferenceTreeNode getFieldReferences(FieldEntry deobfFieldEntry) { |
diff --git a/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java b/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java deleted file mode 100644 index 61e501b7..00000000 --- a/src/cuchaz/enigma/mapping/BehaviorEntryFactory.java +++ /dev/null | |||
| @@ -1,57 +0,0 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2014 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Public License v3.0 | ||
| 5 | * which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/gpl.html | ||
| 7 | * | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.mapping; | ||
| 12 | |||
| 13 | import javassist.CtBehavior; | ||
| 14 | import javassist.CtConstructor; | ||
| 15 | import javassist.CtMethod; | ||
| 16 | import javassist.bytecode.Descriptor; | ||
| 17 | |||
| 18 | public class BehaviorEntryFactory { | ||
| 19 | |||
| 20 | public static BehaviorEntry create(String className, String name, String signature) { | ||
| 21 | return create(new ClassEntry(className), name, signature); | ||
| 22 | } | ||
| 23 | |||
| 24 | public static BehaviorEntry create(ClassEntry classEntry, String name, String signature) { | ||
| 25 | if (name.equals("<init>")) { | ||
| 26 | return new ConstructorEntry(classEntry, new Signature(signature)); | ||
| 27 | } else if (name.equals("<clinit>")) { | ||
| 28 | return new ConstructorEntry(classEntry); | ||
| 29 | } else { | ||
| 30 | return new MethodEntry(classEntry, name, new Signature(signature)); | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | public static BehaviorEntry create(CtBehavior behavior) { | ||
| 35 | String className = Descriptor.toJvmName(behavior.getDeclaringClass().getName()); | ||
| 36 | if (behavior instanceof CtMethod) { | ||
| 37 | return create(className, behavior.getName(), behavior.getSignature()); | ||
| 38 | } else if (behavior instanceof CtConstructor) { | ||
| 39 | CtConstructor constructor = (CtConstructor)behavior; | ||
| 40 | if (constructor.isClassInitializer()) { | ||
| 41 | return create(className, "<clinit>", null); | ||
| 42 | } else { | ||
| 43 | return create(className, "<init>", constructor.getSignature()); | ||
| 44 | } | ||
| 45 | } else { | ||
| 46 | throw new IllegalArgumentException("Unable to create BehaviorEntry from " + behavior); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | public static BehaviorEntry createObf(ClassEntry classEntry, MethodMapping methodMapping) { | ||
| 51 | return create(classEntry, methodMapping.getObfName(), methodMapping.getObfSignature().toString()); | ||
| 52 | } | ||
| 53 | |||
| 54 | public static BehaviorEntry createDeobf(ClassEntry classEntry, MethodMapping methodMapping) { | ||
| 55 | return create(classEntry, methodMapping.getDeobfName(), methodMapping.getObfSignature().toString()); | ||
| 56 | } | ||
| 57 | } | ||
diff --git a/src/cuchaz/enigma/mapping/EntryFactory.java b/src/cuchaz/enigma/mapping/EntryFactory.java new file mode 100644 index 00000000..dceea29d --- /dev/null +++ b/src/cuchaz/enigma/mapping/EntryFactory.java | |||
| @@ -0,0 +1,184 @@ | |||
| 1 | package cuchaz.enigma.mapping; | ||
| 2 | |||
| 3 | import java.util.List; | ||
| 4 | |||
| 5 | import javassist.CtBehavior; | ||
| 6 | import javassist.CtClass; | ||
| 7 | import javassist.CtConstructor; | ||
| 8 | import javassist.CtField; | ||
| 9 | import javassist.CtMethod; | ||
| 10 | import javassist.bytecode.Descriptor; | ||
| 11 | import javassist.expr.ConstructorCall; | ||
| 12 | import javassist.expr.FieldAccess; | ||
| 13 | import javassist.expr.MethodCall; | ||
| 14 | import javassist.expr.NewExpr; | ||
| 15 | |||
| 16 | import com.beust.jcommander.internal.Lists; | ||
| 17 | import com.strobel.assembler.metadata.MethodDefinition; | ||
| 18 | |||
| 19 | import cuchaz.enigma.analysis.JarIndex; | ||
| 20 | |||
| 21 | public class EntryFactory { | ||
| 22 | |||
| 23 | public static ClassEntry getClassEntry(CtClass c) { | ||
| 24 | return new ClassEntry(Descriptor.toJvmName(c.getName())); | ||
| 25 | } | ||
| 26 | |||
| 27 | public static ClassEntry getObfClassEntry(JarIndex jarIndex, ClassMapping classMapping) { | ||
| 28 | return new ClassEntry(getChainedOuterClassName(jarIndex, classMapping.getObfName())); | ||
| 29 | } | ||
| 30 | |||
| 31 | private static String getChainedOuterClassName(JarIndex jarIndex, String obfClassName) { | ||
| 32 | |||
| 33 | // lookup the chain of outer classes | ||
| 34 | List<String> obfOuterClassNames = Lists.newArrayList(); | ||
| 35 | String checkName = obfClassName; | ||
| 36 | while (true) { | ||
| 37 | |||
| 38 | // if this class name has a package, then it can't be an inner class | ||
| 39 | if (!new ClassEntry(checkName).isInDefaultPackage()) { | ||
| 40 | break; | ||
| 41 | } | ||
| 42 | |||
| 43 | String obfOuterClassName = jarIndex.getOuterClass(checkName); | ||
| 44 | if (obfOuterClassName != null) { | ||
| 45 | obfOuterClassNames.add(obfOuterClassName); | ||
| 46 | checkName = obfOuterClassName; | ||
| 47 | } else { | ||
| 48 | break; | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | // build the chained class name | ||
| 53 | StringBuilder buf = new StringBuilder(); | ||
| 54 | for (int i=obfOuterClassNames.size()-1; i>=0; i--) { | ||
| 55 | buf.append(obfOuterClassNames.get(i)); | ||
| 56 | buf.append("$"); | ||
| 57 | } | ||
| 58 | buf.append(obfClassName); | ||
| 59 | return buf.toString(); | ||
| 60 | } | ||
| 61 | |||
| 62 | public static ClassEntry getDeobfClassEntry(ClassMapping classMapping) { | ||
| 63 | return new ClassEntry(classMapping.getDeobfName()); | ||
| 64 | } | ||
| 65 | |||
| 66 | public static ClassEntry getSuperclassEntry(CtClass c) { | ||
| 67 | return new ClassEntry(Descriptor.toJvmName(c.getClassFile().getSuperclass())); | ||
| 68 | } | ||
| 69 | |||
| 70 | public static FieldEntry getFieldEntry(CtField field) { | ||
| 71 | return new FieldEntry( | ||
| 72 | getClassEntry(field.getDeclaringClass()), | ||
| 73 | field.getName(), | ||
| 74 | new Type(field.getFieldInfo().getDescriptor()) | ||
| 75 | ); | ||
| 76 | } | ||
| 77 | |||
| 78 | public static FieldEntry getFieldEntry(FieldAccess call) { | ||
| 79 | return new FieldEntry( | ||
| 80 | new ClassEntry(Descriptor.toJvmName(call.getClassName())), | ||
| 81 | call.getFieldName(), | ||
| 82 | new Type(call.getSignature()) | ||
| 83 | ); | ||
| 84 | } | ||
| 85 | |||
| 86 | public static MethodEntry getMethodEntry(CtMethod method) { | ||
| 87 | return new MethodEntry( | ||
| 88 | getClassEntry(method.getDeclaringClass()), | ||
| 89 | method.getName(), | ||
| 90 | new Signature(method.getMethodInfo().getDescriptor()) | ||
| 91 | ); | ||
| 92 | } | ||
| 93 | |||
| 94 | public static MethodEntry getMethodEntry(MethodCall call) { | ||
| 95 | return new MethodEntry( | ||
| 96 | new ClassEntry(Descriptor.toJvmName(call.getClassName())), | ||
| 97 | call.getMethodName(), | ||
| 98 | new Signature(call.getSignature()) | ||
| 99 | ); | ||
| 100 | } | ||
| 101 | |||
| 102 | public static MethodEntry getMethodEntry(MethodDefinition def) { | ||
| 103 | return new MethodEntry( | ||
| 104 | new ClassEntry(def.getDeclaringType().getInternalName()), | ||
| 105 | def.getName(), | ||
| 106 | new Signature(def.getSignature()) | ||
| 107 | ); | ||
| 108 | } | ||
| 109 | |||
| 110 | public static ConstructorEntry getConstructorEntry(CtConstructor constructor) { | ||
| 111 | if (constructor.isClassInitializer()) { | ||
| 112 | return new ConstructorEntry( | ||
| 113 | getClassEntry(constructor.getDeclaringClass()) | ||
| 114 | ); | ||
| 115 | } else { | ||
| 116 | return new ConstructorEntry( | ||
| 117 | getClassEntry(constructor.getDeclaringClass()), | ||
| 118 | new Signature(constructor.getMethodInfo().getDescriptor()) | ||
| 119 | ); | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | public static ConstructorEntry getConstructorEntry(ConstructorCall call) { | ||
| 124 | return new ConstructorEntry( | ||
| 125 | new ClassEntry(Descriptor.toJvmName(call.getClassName())), | ||
| 126 | new Signature(call.getSignature()) | ||
| 127 | ); | ||
| 128 | } | ||
| 129 | |||
| 130 | public static ConstructorEntry getConstructorEntry(NewExpr call) { | ||
| 131 | return new ConstructorEntry( | ||
| 132 | new ClassEntry(Descriptor.toJvmName(call.getClassName())), | ||
| 133 | new Signature(call.getSignature()) | ||
| 134 | ); | ||
| 135 | } | ||
| 136 | |||
| 137 | public static ConstructorEntry getConstructorEntry(MethodDefinition def) { | ||
| 138 | if (def.isTypeInitializer()) { | ||
| 139 | return new ConstructorEntry( | ||
| 140 | new ClassEntry(def.getDeclaringType().getInternalName()) | ||
| 141 | ); | ||
| 142 | } else { | ||
| 143 | return new ConstructorEntry( | ||
| 144 | new ClassEntry(def.getDeclaringType().getInternalName()), | ||
| 145 | new Signature(def.getSignature()) | ||
| 146 | ); | ||
| 147 | } | ||
| 148 | } | ||
| 149 | |||
| 150 | public static BehaviorEntry getBehaviorEntry(CtBehavior behavior) { | ||
| 151 | if (behavior instanceof CtMethod) { | ||
| 152 | return getMethodEntry((CtMethod)behavior); | ||
| 153 | } else if (behavior instanceof CtConstructor) { | ||
| 154 | return getConstructorEntry((CtConstructor)behavior); | ||
| 155 | } | ||
| 156 | throw new Error("behavior is neither Method nor Constructor!"); | ||
| 157 | } | ||
| 158 | |||
| 159 | public static BehaviorEntry getBehaviorEntry(String className, String behaviorName, String behaviorSignature) { | ||
| 160 | return getBehaviorEntry(new ClassEntry(className), behaviorName, new Signature(behaviorSignature)); | ||
| 161 | } | ||
| 162 | |||
| 163 | public static BehaviorEntry getBehaviorEntry(ClassEntry classEntry, String behaviorName, Signature behaviorSignature) { | ||
| 164 | if (behaviorName.equals("<init>")) { | ||
| 165 | return new ConstructorEntry(classEntry, behaviorSignature); | ||
| 166 | } else if(behaviorName.equals("<clinit>")) { | ||
| 167 | return new ConstructorEntry(classEntry); | ||
| 168 | } else { | ||
| 169 | return new MethodEntry(classEntry, behaviorName, behaviorSignature); | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | public static BehaviorEntry getBehaviorEntry(MethodDefinition def) { | ||
| 174 | if (def.isConstructor() || def.isTypeInitializer()) { | ||
| 175 | return getConstructorEntry(def); | ||
| 176 | } else { | ||
| 177 | return getMethodEntry(def); | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | public static BehaviorEntry getObfBehaviorEntry(ClassEntry classEntry, MethodMapping methodMapping) { | ||
| 182 | return getBehaviorEntry(classEntry, methodMapping.getObfName(), methodMapping.getObfSignature()); | ||
| 183 | } | ||
| 184 | } | ||
diff --git a/src/cuchaz/enigma/mapping/JavassistUtil.java b/src/cuchaz/enigma/mapping/JavassistUtil.java deleted file mode 100644 index 0d6ce6a1..00000000 --- a/src/cuchaz/enigma/mapping/JavassistUtil.java +++ /dev/null | |||
| @@ -1,85 +0,0 @@ | |||
| 1 | package cuchaz.enigma.mapping; | ||
| 2 | |||
| 3 | import javassist.CtBehavior; | ||
| 4 | import javassist.CtClass; | ||
| 5 | import javassist.CtConstructor; | ||
| 6 | import javassist.CtField; | ||
| 7 | import javassist.CtMethod; | ||
| 8 | import javassist.bytecode.Descriptor; | ||
| 9 | import javassist.expr.ConstructorCall; | ||
| 10 | import javassist.expr.FieldAccess; | ||
| 11 | import javassist.expr.MethodCall; | ||
| 12 | import javassist.expr.NewExpr; | ||
| 13 | |||
| 14 | public class JavassistUtil { | ||
| 15 | |||
| 16 | public static ClassEntry getClassEntry(CtClass c) { | ||
| 17 | return new ClassEntry(Descriptor.toJvmName(c.getName())); | ||
| 18 | } | ||
| 19 | |||
| 20 | public static ClassEntry getSuperclassEntry(CtClass c) { | ||
| 21 | return new ClassEntry(Descriptor.toJvmName(c.getClassFile().getSuperclass())); | ||
| 22 | } | ||
| 23 | |||
| 24 | public static MethodEntry getMethodEntry(CtMethod method) { | ||
| 25 | return new MethodEntry( | ||
| 26 | getClassEntry(method.getDeclaringClass()), | ||
| 27 | method.getName(), | ||
| 28 | new Signature(method.getMethodInfo().getDescriptor()) | ||
| 29 | ); | ||
| 30 | } | ||
| 31 | |||
| 32 | public static MethodEntry getMethodEntry(MethodCall call) { | ||
| 33 | return new MethodEntry( | ||
| 34 | new ClassEntry(Descriptor.toJvmName(call.getClassName())), | ||
| 35 | call.getMethodName(), | ||
| 36 | new Signature(call.getSignature()) | ||
| 37 | ); | ||
| 38 | } | ||
| 39 | |||
| 40 | public static ConstructorEntry getConstructorEntry(CtConstructor constructor) { | ||
| 41 | return new ConstructorEntry( | ||
| 42 | getClassEntry(constructor.getDeclaringClass()), | ||
| 43 | new Signature(constructor.getMethodInfo().getDescriptor()) | ||
| 44 | ); | ||
| 45 | } | ||
| 46 | |||
| 47 | public static ConstructorEntry getConstructorEntry(ConstructorCall call) { | ||
| 48 | return new ConstructorEntry( | ||
| 49 | new ClassEntry(Descriptor.toJvmName(call.getClassName())), | ||
| 50 | new Signature(call.getSignature()) | ||
| 51 | ); | ||
| 52 | } | ||
| 53 | |||
| 54 | public static ConstructorEntry getConstructorEntry(NewExpr call) { | ||
| 55 | return new ConstructorEntry( | ||
| 56 | new ClassEntry(Descriptor.toJvmName(call.getClassName())), | ||
| 57 | new Signature(call.getSignature()) | ||
| 58 | ); | ||
| 59 | } | ||
| 60 | |||
| 61 | public static BehaviorEntry getBehaviorEntry(CtBehavior behavior) { | ||
| 62 | if (behavior instanceof CtMethod) { | ||
| 63 | return getMethodEntry((CtMethod)behavior); | ||
| 64 | } else if (behavior instanceof CtConstructor) { | ||
| 65 | return getConstructorEntry((CtConstructor)behavior); | ||
| 66 | } | ||
| 67 | throw new Error("behavior is neither Method nor Constructor!"); | ||
| 68 | } | ||
| 69 | |||
| 70 | public static FieldEntry getFieldEntry(CtField field) { | ||
| 71 | return new FieldEntry( | ||
| 72 | getClassEntry(field.getDeclaringClass()), | ||
| 73 | field.getName(), | ||
| 74 | new Type(field.getFieldInfo().getDescriptor()) | ||
| 75 | ); | ||
| 76 | } | ||
| 77 | |||
| 78 | public static FieldEntry getFieldEntry(FieldAccess call) { | ||
| 79 | return new FieldEntry( | ||
| 80 | new ClassEntry(Descriptor.toJvmName(call.getClassName())), | ||
| 81 | call.getFieldName(), | ||
| 82 | new Type(call.getSignature()) | ||
| 83 | ); | ||
| 84 | } | ||
| 85 | } | ||
diff --git a/test/cuchaz/enigma/EntryFactory.java b/test/cuchaz/enigma/TestEntryFactory.java index 8c94bdf3..754f3081 100644 --- a/test/cuchaz/enigma/EntryFactory.java +++ b/test/cuchaz/enigma/TestEntryFactory.java | |||
| @@ -20,7 +20,7 @@ import cuchaz.enigma.mapping.MethodEntry; | |||
| 20 | import cuchaz.enigma.mapping.Signature; | 20 | import cuchaz.enigma.mapping.Signature; |
| 21 | import cuchaz.enigma.mapping.Type; | 21 | import cuchaz.enigma.mapping.Type; |
| 22 | 22 | ||
| 23 | public class EntryFactory { | 23 | public class TestEntryFactory { |
| 24 | 24 | ||
| 25 | public static ClassEntry newClass(String name) { | 25 | public static ClassEntry newClass(String name) { |
| 26 | return new ClassEntry(name); | 26 | return new ClassEntry(name); |
diff --git a/test/cuchaz/enigma/TestJarIndexConstructorReferences.java b/test/cuchaz/enigma/TestJarIndexConstructorReferences.java index 22812fea..e1a30226 100644 --- a/test/cuchaz/enigma/TestJarIndexConstructorReferences.java +++ b/test/cuchaz/enigma/TestJarIndexConstructorReferences.java | |||
| @@ -10,7 +10,7 @@ | |||
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | package cuchaz.enigma; | 11 | package cuchaz.enigma; |
| 12 | 12 | ||
| 13 | import static cuchaz.enigma.EntryFactory.*; | 13 | import static cuchaz.enigma.TestEntryFactory.*; |
| 14 | import static org.hamcrest.MatcherAssert.*; | 14 | import static org.hamcrest.MatcherAssert.*; |
| 15 | import static org.hamcrest.Matchers.*; | 15 | import static org.hamcrest.Matchers.*; |
| 16 | 16 | ||
diff --git a/test/cuchaz/enigma/TestJarIndexInheritanceTree.java b/test/cuchaz/enigma/TestJarIndexInheritanceTree.java index 349d33b1..6e2c1ad3 100644 --- a/test/cuchaz/enigma/TestJarIndexInheritanceTree.java +++ b/test/cuchaz/enigma/TestJarIndexInheritanceTree.java | |||
| @@ -10,7 +10,7 @@ | |||
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | package cuchaz.enigma; | 11 | package cuchaz.enigma; |
| 12 | 12 | ||
| 13 | import static cuchaz.enigma.EntryFactory.*; | 13 | import static cuchaz.enigma.TestEntryFactory.*; |
| 14 | import static org.hamcrest.MatcherAssert.*; | 14 | import static org.hamcrest.MatcherAssert.*; |
| 15 | import static org.hamcrest.Matchers.*; | 15 | import static org.hamcrest.Matchers.*; |
| 16 | 16 | ||
diff --git a/test/cuchaz/enigma/TestJarIndexLoneClass.java b/test/cuchaz/enigma/TestJarIndexLoneClass.java index c0ac8d7d..768284f9 100644 --- a/test/cuchaz/enigma/TestJarIndexLoneClass.java +++ b/test/cuchaz/enigma/TestJarIndexLoneClass.java | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | ******************************************************************************/ | 11 | ******************************************************************************/ |
| 12 | package cuchaz.enigma; | 12 | package cuchaz.enigma; |
| 13 | 13 | ||
| 14 | import static cuchaz.enigma.EntryFactory.*; | 14 | import static cuchaz.enigma.TestEntryFactory.*; |
| 15 | import static org.hamcrest.MatcherAssert.*; | 15 | import static org.hamcrest.MatcherAssert.*; |
| 16 | import static org.hamcrest.Matchers.*; | 16 | import static org.hamcrest.Matchers.*; |
| 17 | 17 | ||
| @@ -96,8 +96,7 @@ public class TestJarIndexLoneClass { | |||
| 96 | @Test | 96 | @Test |
| 97 | public void methodImplementations() { | 97 | public void methodImplementations() { |
| 98 | MethodEntry source = newMethod("none/a", "a", "()Ljava/lang/String;"); | 98 | MethodEntry source = newMethod("none/a", "a", "()Ljava/lang/String;"); |
| 99 | MethodImplementationsTreeNode node = m_index.getMethodImplementations(new Translator(), source); | 99 | assertThat(m_index.getMethodImplementations(new Translator(), source), is(empty())); |
| 100 | assertThat(node, is(nullValue())); | ||
| 101 | } | 100 | } |
| 102 | 101 | ||
| 103 | @Test | 102 | @Test |
diff --git a/test/cuchaz/enigma/TestTokensConstructors.java b/test/cuchaz/enigma/TestTokensConstructors.java index 6758d2a7..a563f832 100644 --- a/test/cuchaz/enigma/TestTokensConstructors.java +++ b/test/cuchaz/enigma/TestTokensConstructors.java | |||
| @@ -10,7 +10,7 @@ | |||
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | package cuchaz.enigma; | 11 | package cuchaz.enigma; |
| 12 | 12 | ||
| 13 | import static cuchaz.enigma.EntryFactory.*; | 13 | import static cuchaz.enigma.TestEntryFactory.*; |
| 14 | import static org.hamcrest.MatcherAssert.*; | 14 | import static org.hamcrest.MatcherAssert.*; |
| 15 | import static org.hamcrest.Matchers.*; | 15 | import static org.hamcrest.Matchers.*; |
| 16 | 16 | ||
diff --git a/test/cuchaz/enigma/TestTranslator.java b/test/cuchaz/enigma/TestTranslator.java index f91c5852..3fe1680f 100644 --- a/test/cuchaz/enigma/TestTranslator.java +++ b/test/cuchaz/enigma/TestTranslator.java | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | package cuchaz.enigma; | 1 | package cuchaz.enigma; |
| 2 | 2 | ||
| 3 | import static cuchaz.enigma.EntryFactory.*; | 3 | import static cuchaz.enigma.TestEntryFactory.*; |
| 4 | import static org.hamcrest.MatcherAssert.*; | 4 | import static org.hamcrest.MatcherAssert.*; |
| 5 | import static org.hamcrest.Matchers.*; | 5 | import static org.hamcrest.Matchers.*; |
| 6 | 6 | ||
| @@ -8,8 +8,10 @@ import java.io.InputStream; | |||
| 8 | import java.io.InputStreamReader; | 8 | import java.io.InputStreamReader; |
| 9 | import java.util.jar.JarFile; | 9 | import java.util.jar.JarFile; |
| 10 | 10 | ||
| 11 | import org.junit.BeforeClass; | ||
| 11 | import org.junit.Test; | 12 | import org.junit.Test; |
| 12 | 13 | ||
| 14 | import cuchaz.enigma.mapping.Entry; | ||
| 13 | import cuchaz.enigma.mapping.Mappings; | 15 | import cuchaz.enigma.mapping.Mappings; |
| 14 | import cuchaz.enigma.mapping.MappingsReader; | 16 | import cuchaz.enigma.mapping.MappingsReader; |
| 15 | import cuchaz.enigma.mapping.TranslationDirection; | 17 | import cuchaz.enigma.mapping.TranslationDirection; |
| @@ -18,25 +20,85 @@ import cuchaz.enigma.mapping.Translator; | |||
| 18 | 20 | ||
| 19 | public class TestTranslator { | 21 | public class TestTranslator { |
| 20 | 22 | ||
| 21 | private Deobfuscator m_deobfuscator; | 23 | private static Deobfuscator m_deobfuscator; |
| 22 | private Mappings m_mappings; | 24 | private static Mappings m_mappings; |
| 25 | private static Translator m_deobfTranslator; | ||
| 26 | private static Translator m_obfTranslator; | ||
| 23 | 27 | ||
| 24 | public TestTranslator() | 28 | @BeforeClass |
| 29 | public static void beforeClass() | ||
| 25 | throws Exception { | 30 | throws Exception { |
| 26 | m_deobfuscator = new Deobfuscator(new JarFile("build/testTranslation.obf.jar")); | 31 | m_deobfuscator = new Deobfuscator(new JarFile("build/testTranslation.obf.jar")); |
| 27 | try (InputStream in = getClass().getResourceAsStream("/cuchaz/enigma/resources/translation.mappings")) { | 32 | try (InputStream in = TestTranslator.class.getResourceAsStream("/cuchaz/enigma/resources/translation.mappings")) { |
| 28 | m_mappings = new MappingsReader().read(new InputStreamReader(in)); | 33 | m_mappings = new MappingsReader().read(new InputStreamReader(in)); |
| 29 | m_deobfuscator.setMappings(m_mappings); | 34 | m_deobfuscator.setMappings(m_mappings); |
| 35 | m_deobfTranslator = m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating); | ||
| 36 | m_obfTranslator = m_deobfuscator.getTranslator(TranslationDirection.Obfuscating); | ||
| 30 | } | 37 | } |
| 31 | } | 38 | } |
| 32 | 39 | ||
| 33 | @Test | 40 | @Test |
| 34 | public void deobfuscatingTranslations() | 41 | public void basicClasses() { |
| 35 | throws Exception { | 42 | assertMapping(newClass("none/a"), newClass("deobf/A_Basic")); |
| 36 | Translator translator = m_deobfuscator.getTranslator(TranslationDirection.Deobfuscating); | 43 | assertMapping(newClass("none/b"), newClass("deobf/B_BaseClass")); |
| 37 | assertThat(translator.translateEntry(newClass("none/a")), is(newClass("deobf/A"))); | 44 | assertMapping(newClass("none/c"), newClass("deobf/C_SubClass")); |
| 38 | assertThat(translator.translateEntry(newField("none/a", "a", "I")), is(newField("deobf/A", "one", "I"))); | 45 | } |
| 39 | assertThat(translator.translateEntry(newField("none/a", "a", "F")), is(newField("deobf/A", "two", "F"))); | 46 | |
| 40 | assertThat(translator.translateEntry(newField("none/a", "a", "Ljava/lang/String;")), is(newField("deobf/A", "three", "Ljava/lang/String;"))); | 47 | @Test |
| 48 | public void basicFields() { | ||
| 49 | assertMapping(newField("none/a", "a", "I"), newField("deobf/A_Basic", "f1", "I")); | ||
| 50 | assertMapping(newField("none/a", "a", "F"), newField("deobf/A_Basic", "f2", "F")); | ||
| 51 | assertMapping(newField("none/a", "a", "Ljava/lang/String;"), newField("deobf/A_Basic", "f3", "Ljava/lang/String;")); | ||
| 52 | } | ||
| 53 | |||
| 54 | @Test | ||
| 55 | public void basicMethods() { | ||
| 56 | assertMapping(newMethod("none/a", "a", "()V"), newMethod("deobf/A_Basic", "m1", "()V")); | ||
| 57 | assertMapping(newMethod("none/a", "a", "()I"), newMethod("deobf/A_Basic", "m2", "()I")); | ||
| 58 | assertMapping(newMethod("none/a", "a", "(I)V"), newMethod("deobf/A_Basic", "m3", "(I)V")); | ||
| 59 | assertMapping(newMethod("none/a", "a", "(I)I"), newMethod("deobf/A_Basic", "m4", "(I)I")); | ||
| 60 | } | ||
| 61 | |||
| 62 | // TODO: basic constructors | ||
| 63 | |||
| 64 | @Test | ||
| 65 | public void inheritanceFields() { | ||
| 66 | assertMapping(newField("none/b", "a", "I"), newField("deobf/B_BaseClass", "f1", "I")); | ||
| 67 | assertMapping(newField("none/b", "a", "C"), newField("deobf/B_BaseClass", "f2", "C")); | ||
| 68 | assertMapping(newField("none/c", "b", "I"), newField("deobf/C_SubClass", "f3", "I")); | ||
| 69 | assertMapping(newField("none/c", "c", "I"), newField("deobf/C_SubClass", "f4", "I")); | ||
| 70 | } | ||
| 71 | |||
| 72 | @Test | ||
| 73 | public void inheritanceFieldsShadowing() { | ||
| 74 | assertMapping(newField("none/c", "b", "C"), newField("deobf/C_SubClass", "f2", "C")); | ||
| 75 | } | ||
| 76 | |||
| 77 | @Test | ||
| 78 | public void inheritanceFieldsBySubClass() { | ||
| 79 | assertMapping(newField("none/c", "a", "I"), newField("deobf/C_SubClass", "f1", "I")); | ||
| 80 | // NOTE: can't reference b.C by subclass since it's shadowed | ||
| 81 | } | ||
| 82 | |||
| 83 | @Test | ||
| 84 | public void inheritanceMethods() { | ||
| 85 | assertMapping(newMethod("none/b", "a", "()I"), newMethod("deobf/B_BaseClass", "m1", "()I")); | ||
| 86 | assertMapping(newMethod("none/b", "b", "()I"), newMethod("deobf/B_BaseClass", "m2", "()I")); | ||
| 87 | assertMapping(newMethod("none/c", "c", "()I"), newMethod("deobf/C_SubClass", "m3", "()I")); | ||
| 88 | } | ||
| 89 | |||
| 90 | @Test | ||
| 91 | public void inheritanceMethodsOverrides() { | ||
| 92 | assertMapping(newMethod("none/c", "a", "()I"), newMethod("deobf/C_SubClass", "m1", "()I")); | ||
| 93 | } | ||
| 94 | |||
| 95 | @Test | ||
| 96 | public void inheritanceMethodsBySubClass() { | ||
| 97 | assertMapping(newMethod("none/c", "b", "()I"), newMethod("deobf/C_SubClass", "m2", "()I")); | ||
| 98 | } | ||
| 99 | |||
| 100 | private void assertMapping(Entry obf, Entry deobf) { | ||
| 101 | assertThat(m_deobfTranslator.translateEntry(obf), is(deobf)); | ||
| 102 | assertThat(m_obfTranslator.translateEntry(deobf), is(obf)); | ||
| 41 | } | 103 | } |
| 42 | } | 104 | } |
diff --git a/test/cuchaz/enigma/TestType.java b/test/cuchaz/enigma/TestType.java index 7c3cebe2..93f864b0 100644 --- a/test/cuchaz/enigma/TestType.java +++ b/test/cuchaz/enigma/TestType.java | |||
| @@ -7,7 +7,7 @@ import static org.hamcrest.Matchers.*; | |||
| 7 | 7 | ||
| 8 | import cuchaz.enigma.mapping.Type; | 8 | import cuchaz.enigma.mapping.Type; |
| 9 | 9 | ||
| 10 | import static cuchaz.enigma.EntryFactory.*; | 10 | import static cuchaz.enigma.TestEntryFactory.*; |
| 11 | 11 | ||
| 12 | 12 | ||
| 13 | public class TestType { | 13 | public class TestType { |
diff --git a/test/cuchaz/enigma/inputs/translation/A.java b/test/cuchaz/enigma/inputs/translation/A.java deleted file mode 100644 index b8aaf11e..00000000 --- a/test/cuchaz/enigma/inputs/translation/A.java +++ /dev/null | |||
| @@ -1,8 +0,0 @@ | |||
| 1 | package cuchaz.enigma.inputs.translation; | ||
| 2 | |||
| 3 | public class A { | ||
| 4 | |||
| 5 | public int one; | ||
| 6 | public float two; | ||
| 7 | public String three; | ||
| 8 | } | ||
diff --git a/test/cuchaz/enigma/inputs/translation/A_Basic.java b/test/cuchaz/enigma/inputs/translation/A_Basic.java new file mode 100644 index 00000000..89307630 --- /dev/null +++ b/test/cuchaz/enigma/inputs/translation/A_Basic.java | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | package cuchaz.enigma.inputs.translation; | ||
| 2 | |||
| 3 | public class A_Basic { | ||
| 4 | |||
| 5 | public int one; | ||
| 6 | public float two; | ||
| 7 | public String three; | ||
| 8 | |||
| 9 | public void m1() { | ||
| 10 | } | ||
| 11 | |||
| 12 | public int m2() { | ||
| 13 | return 42; | ||
| 14 | } | ||
| 15 | |||
| 16 | public void m3(int a1) { | ||
| 17 | } | ||
| 18 | |||
| 19 | public int m4(int a1) { | ||
| 20 | return 5; // chosen by fair die roll, guaranteed to be random | ||
| 21 | } | ||
| 22 | } | ||
diff --git a/test/cuchaz/enigma/inputs/translation/B_BaseClass.java b/test/cuchaz/enigma/inputs/translation/B_BaseClass.java new file mode 100644 index 00000000..44fbc8db --- /dev/null +++ b/test/cuchaz/enigma/inputs/translation/B_BaseClass.java | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | package cuchaz.enigma.inputs.translation; | ||
| 2 | |||
| 3 | public class B_BaseClass { | ||
| 4 | |||
| 5 | public int f1; | ||
| 6 | public char f2; | ||
| 7 | |||
| 8 | public int m1() { | ||
| 9 | return 5; | ||
| 10 | } | ||
| 11 | |||
| 12 | public int m2() { | ||
| 13 | return 42; | ||
| 14 | } | ||
| 15 | } | ||
diff --git a/test/cuchaz/enigma/inputs/translation/C_SubClass.java b/test/cuchaz/enigma/inputs/translation/C_SubClass.java new file mode 100644 index 00000000..8fe0b799 --- /dev/null +++ b/test/cuchaz/enigma/inputs/translation/C_SubClass.java | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | package cuchaz.enigma.inputs.translation; | ||
| 2 | |||
| 3 | public class C_SubClass extends B_BaseClass { | ||
| 4 | |||
| 5 | public char f2; // shadows B_BaseClass.f2 | ||
| 6 | public int f3; | ||
| 7 | public int f4; | ||
| 8 | |||
| 9 | @Override | ||
| 10 | public int m1() { | ||
| 11 | return 32; | ||
| 12 | } | ||
| 13 | |||
| 14 | public int m3() { | ||
| 15 | return 7; | ||
| 16 | } | ||
| 17 | } | ||
diff --git a/test/cuchaz/enigma/resources/translation.mappings b/test/cuchaz/enigma/resources/translation.mappings index c71493e9..d87d437c 100644 --- a/test/cuchaz/enigma/resources/translation.mappings +++ b/test/cuchaz/enigma/resources/translation.mappings | |||
| @@ -1,4 +1,19 @@ | |||
| 1 | CLASS none/a deobf/A | 1 | CLASS none/a deobf/A_Basic |
| 2 | FIELD a one I | 2 | FIELD a f1 I |
| 3 | FIELD a two F | 3 | FIELD a f2 F |
| 4 | FIELD a three Ljava/lang/String; \ No newline at end of file | 4 | FIELD a f3 Ljava/lang/String; |
| 5 | METHOD a m1 ()V | ||
| 6 | METHOD a m2 ()I | ||
| 7 | METHOD a m3 (I)V | ||
| 8 | METHOD a m4 (I)I | ||
| 9 | CLASS none/b deobf/B_BaseClass | ||
| 10 | FIELD a f1 I | ||
| 11 | FIELD a f2 C | ||
| 12 | METHOD a m1 ()I | ||
| 13 | METHOD b m2 ()I | ||
| 14 | CLASS none/c deobf/C_SubClass | ||
| 15 | FIELD b f2 C | ||
| 16 | FIELD b f3 I | ||
| 17 | FIELD c f4 I | ||
| 18 | METHOD a m1 ()I | ||
| 19 | METHOD c m3 ()I | ||