summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Cuchaz2015-03-30 23:56:21 -0400
committerGravatar Cuchaz2015-03-30 23:56:21 -0400
commit2fc8ae770442ec3ab91cf0c16cc30917e0d048d3 (patch)
treea49e9ede649fb0f350fee1b8336f319df20f4973
parentadd publifier (diff)
downloadenigma-2fc8ae770442ec3ab91cf0c16cc30917e0d048d3.tar.gz
enigma-2fc8ae770442ec3ab91cf0c16cc30917e0d048d3.tar.xz
enigma-2fc8ae770442ec3ab91cf0c16cc30917e0d048d3.zip
resolve methods using interfaces as well as superclasses
-rw-r--r--src/cuchaz/enigma/analysis/JarIndex.java36
-rw-r--r--src/cuchaz/enigma/analysis/TranslationIndex.java69
2 files changed, 84 insertions, 21 deletions
diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java
index e255468a..6b3cf677 100644
--- a/src/cuchaz/enigma/analysis/JarIndex.java
+++ b/src/cuchaz/enigma/analysis/JarIndex.java
@@ -59,7 +59,6 @@ public class JarIndex {
59 59
60 private Set<ClassEntry> m_obfClassEntries; 60 private Set<ClassEntry> m_obfClassEntries;
61 private TranslationIndex m_translationIndex; 61 private TranslationIndex m_translationIndex;
62 private Multimap<String,String> m_interfaces;
63 private Map<Entry,Access> m_access; 62 private Map<Entry,Access> m_access;
64 private Multimap<ClassEntry,FieldEntry> m_fields; 63 private Multimap<ClassEntry,FieldEntry> m_fields;
65 private Multimap<ClassEntry,BehaviorEntry> m_behaviors; 64 private Multimap<ClassEntry,BehaviorEntry> m_behaviors;
@@ -74,7 +73,6 @@ public class JarIndex {
74 public JarIndex() { 73 public JarIndex() {
75 m_obfClassEntries = Sets.newHashSet(); 74 m_obfClassEntries = Sets.newHashSet();
76 m_translationIndex = new TranslationIndex(); 75 m_translationIndex = new TranslationIndex();
77 m_interfaces = HashMultimap.create();
78 m_access = Maps.newHashMap(); 76 m_access = Maps.newHashMap();
79 m_fields = HashMultimap.create(); 77 m_fields = HashMultimap.create();
80 m_behaviors = HashMultimap.create(); 78 m_behaviors = HashMultimap.create();
@@ -124,7 +122,6 @@ public class JarIndex {
124 if (className.equals(interfaceName)) { 122 if (className.equals(interfaceName)) {
125 throw new IllegalArgumentException("Class cannot be its own interface! " + className); 123 throw new IllegalArgumentException("Class cannot be its own interface! " + className);
126 } 124 }
127 m_interfaces.put(className, interfaceName);
128 } 125 }
129 for (CtBehavior behavior : c.getDeclaredBehaviors()) { 126 for (CtBehavior behavior : c.getDeclaredBehaviors()) {
130 indexBehavior(behavior); 127 indexBehavior(behavior);
@@ -176,7 +173,6 @@ public class JarIndex {
176 } 173 }
177 EntryRenamer.renameClassesInSet(renames, m_obfClassEntries); 174 EntryRenamer.renameClassesInSet(renames, m_obfClassEntries);
178 m_translationIndex.renameClasses(renames); 175 m_translationIndex.renameClasses(renames);
179 EntryRenamer.renameClassesInMultimap(renames, m_interfaces);
180 EntryRenamer.renameClassesInMultimap(renames, m_methodImplementations); 176 EntryRenamer.renameClassesInMultimap(renames, m_methodImplementations);
181 EntryRenamer.renameClassesInMultimap(renames, m_behaviorReferences); 177 EntryRenamer.renameClassesInMultimap(renames, m_behaviorReferences);
182 EntryRenamer.renameClassesInMultimap(renames, m_fieldReferences); 178 EntryRenamer.renameClassesInMultimap(renames, m_fieldReferences);
@@ -637,11 +633,11 @@ public class JarIndex {
637 interfaceMethodEntries.add(obfMethodEntry); 633 interfaceMethodEntries.add(obfMethodEntry);
638 } else { 634 } else {
639 // get the interface class 635 // get the interface class
640 for (String interfaceName : getInterfaces(obfMethodEntry.getClassName())) { 636 for (ClassEntry interfaceEntry : getInterfaces(obfMethodEntry.getClassName())) {
641 637
642 // is this method defined in this interface? 638 // is this method defined in this interface?
643 MethodEntry methodInterface = new MethodEntry( 639 MethodEntry methodInterface = new MethodEntry(
644 new ClassEntry(interfaceName), 640 interfaceEntry,
645 obfMethodEntry.getName(), 641 obfMethodEntry.getName(),
646 obfMethodEntry.getSignature() 642 obfMethodEntry.getSignature()
647 ); 643 );
@@ -745,31 +741,33 @@ public class JarIndex {
745 return m_anonymousClasses.get(obfInnerClassName); 741 return m_anonymousClasses.get(obfInnerClassName);
746 } 742 }
747 743
748 public Set<String> getInterfaces(String className) { 744 public Set<ClassEntry> getInterfaces(String className) {
749 Set<String> interfaceNames = new HashSet<String>(); 745 ClassEntry classEntry = new ClassEntry(className);
750 interfaceNames.addAll(m_interfaces.get(className)); 746 Set<ClassEntry> interfaces = new HashSet<ClassEntry>();
751 for (ClassEntry ancestor : m_translationIndex.getAncestry(new ClassEntry(className))) { 747 interfaces.addAll(m_translationIndex.getInterfaces(classEntry));
752 interfaceNames.addAll(m_interfaces.get(ancestor.getName())); 748 for (ClassEntry ancestor : m_translationIndex.getAncestry(classEntry)) {
749 interfaces.addAll(m_translationIndex.getInterfaces(ancestor));
753 } 750 }
754 return interfaceNames; 751 return interfaces;
755 } 752 }
756 753
757 public Set<String> getImplementingClasses(String targetInterfaceName) { 754 public Set<String> getImplementingClasses(String targetInterfaceName) {
755
758 // linear search is fast enough for now 756 // linear search is fast enough for now
759 Set<String> classNames = Sets.newHashSet(); 757 Set<String> classNames = Sets.newHashSet();
760 for (Map.Entry<String,String> entry : m_interfaces.entries()) { 758 for (Map.Entry<ClassEntry,ClassEntry> entry : m_translationIndex.getClassInterfaces()) {
761 String className = entry.getKey(); 759 ClassEntry classEntry = entry.getKey();
762 String interfaceName = entry.getValue(); 760 ClassEntry interfaceEntry = entry.getValue();
763 if (interfaceName.equals(targetInterfaceName)) { 761 if (interfaceEntry.getName().equals(targetInterfaceName)) {
764 classNames.add(className); 762 classNames.add(classEntry.getClassName());
765 m_translationIndex.getSubclassNamesRecursively(classNames, new ClassEntry(className)); 763 m_translationIndex.getSubclassNamesRecursively(classNames, classEntry);
766 } 764 }
767 } 765 }
768 return classNames; 766 return classNames;
769 } 767 }
770 768
771 public boolean isInterface(String className) { 769 public boolean isInterface(String className) {
772 return m_interfaces.containsValue(className); 770 return m_translationIndex.isInterface(new ClassEntry(className));
773 } 771 }
774 772
775 public boolean containsObfClass(ClassEntry obfClassEntry) { 773 public boolean containsObfClass(ClassEntry obfClassEntry) {
diff --git a/src/cuchaz/enigma/analysis/TranslationIndex.java b/src/cuchaz/enigma/analysis/TranslationIndex.java
index bd77344c..e0e66bf7 100644
--- a/src/cuchaz/enigma/analysis/TranslationIndex.java
+++ b/src/cuchaz/enigma/analysis/TranslationIndex.java
@@ -16,6 +16,7 @@ import java.io.ObjectInputStream;
16import java.io.ObjectOutputStream; 16import java.io.ObjectOutputStream;
17import java.io.OutputStream; 17import java.io.OutputStream;
18import java.io.Serializable; 18import java.io.Serializable;
19import java.util.Collection;
19import java.util.HashMap; 20import java.util.HashMap;
20import java.util.List; 21import java.util.List;
21import java.util.Map; 22import java.util.Map;
@@ -26,6 +27,7 @@ import java.util.zip.GZIPOutputStream;
26import javassist.CtBehavior; 27import javassist.CtBehavior;
27import javassist.CtClass; 28import javassist.CtClass;
28import javassist.CtField; 29import javassist.CtField;
30import javassist.bytecode.Descriptor;
29 31
30import com.google.common.collect.HashMultimap; 32import com.google.common.collect.HashMultimap;
31import com.google.common.collect.Lists; 33import com.google.common.collect.Lists;
@@ -36,8 +38,8 @@ import cuchaz.enigma.mapping.ArgumentEntry;
36import cuchaz.enigma.mapping.BehaviorEntry; 38import cuchaz.enigma.mapping.BehaviorEntry;
37import cuchaz.enigma.mapping.ClassEntry; 39import cuchaz.enigma.mapping.ClassEntry;
38import cuchaz.enigma.mapping.Entry; 40import cuchaz.enigma.mapping.Entry;
39import cuchaz.enigma.mapping.FieldEntry;
40import cuchaz.enigma.mapping.EntryFactory; 41import cuchaz.enigma.mapping.EntryFactory;
42import cuchaz.enigma.mapping.FieldEntry;
41import cuchaz.enigma.mapping.Translator; 43import cuchaz.enigma.mapping.Translator;
42 44
43public class TranslationIndex implements Serializable { 45public class TranslationIndex implements Serializable {
@@ -47,11 +49,13 @@ public class TranslationIndex implements Serializable {
47 private Map<ClassEntry,ClassEntry> m_superclasses; 49 private Map<ClassEntry,ClassEntry> m_superclasses;
48 private Multimap<ClassEntry,FieldEntry> m_fieldEntries; 50 private Multimap<ClassEntry,FieldEntry> m_fieldEntries;
49 private Multimap<ClassEntry,BehaviorEntry> m_behaviorEntries; 51 private Multimap<ClassEntry,BehaviorEntry> m_behaviorEntries;
52 private Multimap<ClassEntry,ClassEntry> m_interfaces;
50 53
51 public TranslationIndex() { 54 public TranslationIndex() {
52 m_superclasses = Maps.newHashMap(); 55 m_superclasses = Maps.newHashMap();
53 m_fieldEntries = HashMultimap.create(); 56 m_fieldEntries = HashMultimap.create();
54 m_behaviorEntries = HashMultimap.create(); 57 m_behaviorEntries = HashMultimap.create();
58 m_interfaces = HashMultimap.create();
55 } 59 }
56 60
57 public TranslationIndex(TranslationIndex other, Translator translator) { 61 public TranslationIndex(TranslationIndex other, Translator translator) {
@@ -65,6 +69,15 @@ public class TranslationIndex implements Serializable {
65 ); 69 );
66 } 70 }
67 71
72 // translate the interfaces
73 m_interfaces = HashMultimap.create();
74 for (Map.Entry<ClassEntry,ClassEntry> mapEntry : other.m_interfaces.entries()) {
75 m_interfaces.put(
76 translator.translateEntry(mapEntry.getKey()),
77 translator.translateEntry(mapEntry.getValue())
78 );
79 }
80
68 // translate the fields 81 // translate the fields
69 m_fieldEntries = HashMultimap.create(); 82 m_fieldEntries = HashMultimap.create();
70 for (Map.Entry<ClassEntry,FieldEntry> mapEntry : other.m_fieldEntries.entries()) { 83 for (Map.Entry<ClassEntry,FieldEntry> mapEntry : other.m_fieldEntries.entries()) {
@@ -90,13 +103,24 @@ public class TranslationIndex implements Serializable {
90 public void indexClass(CtClass c, boolean indexMembers) { 103 public void indexClass(CtClass c, boolean indexMembers) {
91 104
92 ClassEntry classEntry = EntryFactory.getClassEntry(c); 105 ClassEntry classEntry = EntryFactory.getClassEntry(c);
106 if (isJre(classEntry)) {
107 return;
108 }
93 109
94 // add the superclass 110 // add the superclass
95 ClassEntry superclassEntry = EntryFactory.getSuperclassEntry(c); 111 ClassEntry superclassEntry = EntryFactory.getSuperclassEntry(c);
96 if (!isJre(classEntry) && superclassEntry != null && !isJre(superclassEntry)) { 112 if (superclassEntry != null && !isJre(superclassEntry)) {
97 m_superclasses.put(classEntry, superclassEntry); 113 m_superclasses.put(classEntry, superclassEntry);
98 } 114 }
99 115
116 // add the interfaces
117 for (String interfaceClassName : c.getClassFile().getInterfaces()) {
118 ClassEntry interfaceClassEntry = new ClassEntry(Descriptor.toJvmName(interfaceClassName));
119 if (!isJre(interfaceClassEntry)) {
120 m_interfaces.put(classEntry, interfaceClassEntry);
121 }
122 }
123
100 if (indexMembers) { 124 if (indexMembers) {
101 // add fields 125 // add fields
102 for (CtField field : c.getDeclaredFields()) { 126 for (CtField field : c.getDeclaredFields()) {
@@ -134,6 +158,7 @@ public class TranslationIndex implements Serializable {
134 } 158 }
135 159
136 public List<ClassEntry> getSubclass(ClassEntry classEntry) { 160 public List<ClassEntry> getSubclass(ClassEntry classEntry) {
161
137 // linear search is fast enough for now 162 // linear search is fast enough for now
138 List<ClassEntry> subclasses = Lists.newArrayList(); 163 List<ClassEntry> subclasses = Lists.newArrayList();
139 for (Map.Entry<ClassEntry,ClassEntry> entry : m_superclasses.entrySet()) { 164 for (Map.Entry<ClassEntry,ClassEntry> entry : m_superclasses.entrySet()) {
@@ -160,6 +185,18 @@ public class TranslationIndex implements Serializable {
160 } 185 }
161 } 186 }
162 187
188 public Collection<Map.Entry<ClassEntry,ClassEntry>> getClassInterfaces() {
189 return m_interfaces.entries();
190 }
191
192 public Collection<ClassEntry> getInterfaces(ClassEntry classEntry) {
193 return m_interfaces.get(classEntry);
194 }
195
196 public boolean isInterface(ClassEntry classEntry) {
197 return m_interfaces.containsValue(classEntry);
198 }
199
163 public boolean entryExists(Entry entry) { 200 public boolean entryExists(Entry entry) {
164 if (entry instanceof FieldEntry) { 201 if (entry instanceof FieldEntry) {
165 return fieldExists((FieldEntry)entry); 202 return fieldExists((FieldEntry)entry);
@@ -185,6 +222,21 @@ public class TranslationIndex implements Serializable {
185 return (ClassEntry)entry; 222 return (ClassEntry)entry;
186 } 223 }
187 224
225 ClassEntry superclassEntry = resolveSuperclass(entry);
226 if (superclassEntry != null) {
227 return superclassEntry;
228 }
229
230 ClassEntry interfaceEntry = resolveInterface(entry);
231 if (interfaceEntry != null) {
232 return interfaceEntry;
233 }
234
235 return null;
236 }
237
238 public ClassEntry resolveSuperclass(Entry entry) {
239
188 // this entry could refer to a method on a class where the method is not actually implemented 240 // this entry could refer to a method on a class where the method is not actually implemented
189 // travel up the inheritance tree to find the closest implementation 241 // travel up the inheritance tree to find the closest implementation
190 while (!entryExists(entry)) { 242 while (!entryExists(entry)) {
@@ -203,6 +255,19 @@ public class TranslationIndex implements Serializable {
203 return entry.getClassEntry(); 255 return entry.getClassEntry();
204 } 256 }
205 257
258 public ClassEntry resolveInterface(Entry entry) {
259
260 // the interfaces for any class is a forest
261 // so let's look at all the trees
262 for (ClassEntry interfaceEntry : m_interfaces.get(entry.getClassEntry())) {
263 ClassEntry resolvedClassEntry = resolveSuperclass(entry.cloneToNewClass(interfaceEntry));
264 if (resolvedClassEntry != null) {
265 return resolvedClassEntry;
266 }
267 }
268 return null;
269 }
270
206 private boolean isJre(ClassEntry classEntry) { 271 private boolean isJre(ClassEntry classEntry) {
207 String packageName = classEntry.getPackageName(); 272 String packageName = classEntry.getPackageName();
208 return packageName != null && (packageName.startsWith("java") || packageName.startsWith("javax")); 273 return packageName != null && (packageName.startsWith("java") || packageName.startsWith("javax"));