diff options
Diffstat (limited to 'src/main/java/cuchaz/enigma/analysis/TranslationIndex.java')
| -rw-r--r-- | src/main/java/cuchaz/enigma/analysis/TranslationIndex.java | 275 |
1 files changed, 0 insertions, 275 deletions
diff --git a/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java b/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java deleted file mode 100644 index 984d84b..0000000 --- a/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java +++ /dev/null | |||
| @@ -1,275 +0,0 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2015 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Lesser General Public | ||
| 5 | * License v3.0 which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/lgpl.html | ||
| 7 | * <p> | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | |||
| 12 | package cuchaz.enigma.analysis; | ||
| 13 | |||
| 14 | import com.google.common.cache.Cache; | ||
| 15 | import com.google.common.cache.CacheBuilder; | ||
| 16 | import com.google.common.collect.HashMultimap; | ||
| 17 | import com.google.common.collect.Lists; | ||
| 18 | import com.google.common.collect.Maps; | ||
| 19 | import com.google.common.collect.Multimap; | ||
| 20 | import cuchaz.enigma.bytecode.AccessFlags; | ||
| 21 | import cuchaz.enigma.mapping.*; | ||
| 22 | import cuchaz.enigma.mapping.entry.*; | ||
| 23 | |||
| 24 | import java.util.*; | ||
| 25 | |||
| 26 | public class TranslationIndex { | ||
| 27 | |||
| 28 | private final ReferencedEntryPool entryPool; | ||
| 29 | private Map<ClassEntry, ClassEntry> superclasses; | ||
| 30 | private Map<Entry, DefEntry> defEntries = new HashMap<>(); | ||
| 31 | private Multimap<ClassEntry, FieldDefEntry> fieldEntries; | ||
| 32 | private Multimap<ClassEntry, MethodDefEntry> methodEntries; | ||
| 33 | private Multimap<ClassEntry, ClassEntry> interfaces; | ||
| 34 | |||
| 35 | public TranslationIndex(ReferencedEntryPool entryPool) { | ||
| 36 | this.entryPool = entryPool; | ||
| 37 | this.superclasses = Maps.newHashMap(); | ||
| 38 | this.fieldEntries = HashMultimap.create(); | ||
| 39 | this.methodEntries = HashMultimap.create(); | ||
| 40 | this.interfaces = HashMultimap.create(); | ||
| 41 | |||
| 42 | for (FieldDefEntry entry : fieldEntries.values()) { | ||
| 43 | defEntries.put(entry, entry); | ||
| 44 | } | ||
| 45 | |||
| 46 | for (MethodDefEntry entry : methodEntries.values()) { | ||
| 47 | defEntries.put(entry, entry); | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | public TranslationIndex(TranslationIndex other, Translator translator) { | ||
| 52 | this.entryPool = other.entryPool; | ||
| 53 | |||
| 54 | // translate the superclasses | ||
| 55 | this.superclasses = Maps.newHashMap(); | ||
| 56 | for (Map.Entry<ClassEntry, ClassEntry> mapEntry : other.superclasses.entrySet()) { | ||
| 57 | this.superclasses.put(translator.getTranslatedClass(mapEntry.getKey()), translator.getTranslatedClass(mapEntry.getValue())); | ||
| 58 | } | ||
| 59 | |||
| 60 | // translate the interfaces | ||
| 61 | this.interfaces = HashMultimap.create(); | ||
| 62 | for (Map.Entry<ClassEntry, ClassEntry> mapEntry : other.interfaces.entries()) { | ||
| 63 | this.interfaces.put( | ||
| 64 | translator.getTranslatedClass(mapEntry.getKey()), | ||
| 65 | translator.getTranslatedClass(mapEntry.getValue()) | ||
| 66 | ); | ||
| 67 | } | ||
| 68 | |||
| 69 | // translate the fields | ||
| 70 | this.fieldEntries = HashMultimap.create(); | ||
| 71 | for (Map.Entry<ClassEntry, FieldDefEntry> mapEntry : other.fieldEntries.entries()) { | ||
| 72 | this.fieldEntries.put( | ||
| 73 | translator.getTranslatedClass(mapEntry.getKey()), | ||
| 74 | translator.getTranslatedFieldDef(mapEntry.getValue()) | ||
| 75 | ); | ||
| 76 | } | ||
| 77 | |||
| 78 | this.methodEntries = HashMultimap.create(); | ||
| 79 | for (Map.Entry<ClassEntry, MethodDefEntry> mapEntry : other.methodEntries.entries()) { | ||
| 80 | this.methodEntries.put( | ||
| 81 | translator.getTranslatedClass(mapEntry.getKey()), | ||
| 82 | translator.getTranslatedMethodDef(mapEntry.getValue()) | ||
| 83 | ); | ||
| 84 | } | ||
| 85 | |||
| 86 | for (FieldDefEntry entry : fieldEntries.values()) { | ||
| 87 | defEntries.put(entry, entry); | ||
| 88 | } | ||
| 89 | |||
| 90 | for (MethodDefEntry entry : methodEntries.values()) { | ||
| 91 | defEntries.put(entry, entry); | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | protected ClassDefEntry indexClass(int access, String name, String signature, String superName, String[] interfaces) { | ||
| 96 | ClassDefEntry classEntry = new ClassDefEntry(name, Signature.createSignature(signature), new AccessFlags(access)); | ||
| 97 | if (isJre(classEntry)) { | ||
| 98 | return null; | ||
| 99 | } | ||
| 100 | |||
| 101 | // add the superclass | ||
| 102 | ClassEntry superclassEntry = entryPool.getClass(superName); | ||
| 103 | if (superclassEntry != null) { | ||
| 104 | this.superclasses.put(classEntry, superclassEntry); | ||
| 105 | } | ||
| 106 | |||
| 107 | // add the interfaces | ||
| 108 | for (String interfaceClassName : interfaces) { | ||
| 109 | ClassEntry interfaceClassEntry = entryPool.getClass(interfaceClassName); | ||
| 110 | if (!isJre(interfaceClassEntry)) { | ||
| 111 | this.interfaces.put(classEntry, interfaceClassEntry); | ||
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 115 | return classEntry; | ||
| 116 | } | ||
| 117 | |||
| 118 | protected void indexField(FieldDefEntry fieldEntry) { | ||
| 119 | this.fieldEntries.put(fieldEntry.getOwnerClassEntry(), fieldEntry); | ||
| 120 | this.defEntries.put(fieldEntry, fieldEntry); | ||
| 121 | } | ||
| 122 | |||
| 123 | protected void indexMethod(MethodDefEntry methodEntry) { | ||
| 124 | this.methodEntries.put(methodEntry.getOwnerClassEntry(), methodEntry); | ||
| 125 | this.defEntries.put(methodEntry, methodEntry); | ||
| 126 | } | ||
| 127 | |||
| 128 | public void renameClasses(Map<String, String> renames) { | ||
| 129 | EntryRenamer.renameClassesInMap(renames, this.superclasses); | ||
| 130 | EntryRenamer.renameClassesInMultimap(renames, this.fieldEntries); | ||
| 131 | EntryRenamer.renameClassesInMultimap(renames, this.methodEntries); | ||
| 132 | |||
| 133 | this.defEntries.clear(); | ||
| 134 | for (FieldDefEntry entry : fieldEntries.values()) { | ||
| 135 | defEntries.put(entry, entry); | ||
| 136 | } | ||
| 137 | |||
| 138 | for (MethodDefEntry entry : methodEntries.values()) { | ||
| 139 | defEntries.put(entry, entry); | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | public ClassEntry getSuperclass(ClassEntry classEntry) { | ||
| 144 | return this.superclasses.get(classEntry); | ||
| 145 | } | ||
| 146 | |||
| 147 | public List<ClassEntry> getAncestry(ClassEntry classEntry) { | ||
| 148 | List<ClassEntry> ancestors = Lists.newArrayList(); | ||
| 149 | while (classEntry != null) { | ||
| 150 | classEntry = getSuperclass(classEntry); | ||
| 151 | if (classEntry != null) { | ||
| 152 | ancestors.add(classEntry); | ||
| 153 | } | ||
| 154 | } | ||
| 155 | return ancestors; | ||
| 156 | } | ||
| 157 | |||
| 158 | public List<ClassEntry> getImplementers(ClassEntry classEntry) { | ||
| 159 | // linear search is fast enough for now | ||
| 160 | List<ClassEntry> implementers = Lists.newArrayList(); | ||
| 161 | for (ClassEntry itf : this.interfaces.keySet()) { | ||
| 162 | if (this.interfaces.containsEntry(itf, classEntry)) { | ||
| 163 | implementers.add(itf); | ||
| 164 | } | ||
| 165 | } | ||
| 166 | return implementers; | ||
| 167 | } | ||
| 168 | |||
| 169 | public List<ClassEntry> getSubclass(ClassEntry classEntry) { | ||
| 170 | // linear search is fast enough for now | ||
| 171 | List<ClassEntry> subclasses = Lists.newArrayList(); | ||
| 172 | for (Map.Entry<ClassEntry, ClassEntry> entry : this.superclasses.entrySet()) { | ||
| 173 | ClassEntry subclass = entry.getKey(); | ||
| 174 | ClassEntry superclass = entry.getValue(); | ||
| 175 | if (classEntry.equals(superclass)) { | ||
| 176 | subclasses.add(subclass); | ||
| 177 | } | ||
| 178 | } | ||
| 179 | return subclasses; | ||
| 180 | } | ||
| 181 | |||
| 182 | public void getSubclassesRecursively(Set<ClassEntry> out, ClassEntry classEntry) { | ||
| 183 | for (ClassEntry subclassEntry : getSubclass(classEntry)) { | ||
| 184 | out.add(subclassEntry); | ||
| 185 | getSubclassesRecursively(out, subclassEntry); | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 189 | public void getSubclassNamesRecursively(Set<String> out, ClassEntry classEntry) { | ||
| 190 | for (ClassEntry subclassEntry : getSubclass(classEntry)) { | ||
| 191 | out.add(subclassEntry.getName()); | ||
| 192 | getSubclassNamesRecursively(out, subclassEntry); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | public Collection<Map.Entry<ClassEntry, ClassEntry>> getClassInterfaces() { | ||
| 197 | return this.interfaces.entries(); | ||
| 198 | } | ||
| 199 | |||
| 200 | public Collection<ClassEntry> getInterfaces(ClassEntry classEntry) { | ||
| 201 | return this.interfaces.get(classEntry); | ||
| 202 | } | ||
| 203 | |||
| 204 | public boolean isInterface(ClassEntry classEntry) { | ||
| 205 | return this.interfaces.containsValue(classEntry); | ||
| 206 | } | ||
| 207 | |||
| 208 | public boolean entryExists(Entry entry) { | ||
| 209 | if (entry == null) { | ||
| 210 | return false; | ||
| 211 | } | ||
| 212 | |||
| 213 | if (entry instanceof FieldEntry) { | ||
| 214 | return fieldExists((FieldEntry) entry); | ||
| 215 | } else if (entry instanceof MethodEntry) { | ||
| 216 | return methodExists((MethodEntry) entry); | ||
| 217 | } else if (entry instanceof LocalVariableEntry) { | ||
| 218 | return methodExists(((LocalVariableEntry) entry).getOwnerEntry()); | ||
| 219 | } | ||
| 220 | throw new IllegalArgumentException("Cannot check existence for " + entry.getClass()); | ||
| 221 | } | ||
| 222 | |||
| 223 | public boolean fieldExists(FieldEntry fieldEntry) { | ||
| 224 | return this.fieldEntries.containsEntry(fieldEntry.getOwnerClassEntry(), fieldEntry); | ||
| 225 | } | ||
| 226 | |||
| 227 | public boolean methodExists(MethodEntry methodEntry) { | ||
| 228 | return this.methodEntries.containsEntry(methodEntry.getOwnerClassEntry(), methodEntry); | ||
| 229 | } | ||
| 230 | |||
| 231 | public ClassEntry resolveEntryOwner(Entry entry) { | ||
| 232 | if (entry instanceof ClassEntry) { | ||
| 233 | return (ClassEntry) entry; | ||
| 234 | } | ||
| 235 | |||
| 236 | if (entryExists(entry)) { | ||
| 237 | return entry.getOwnerClassEntry(); | ||
| 238 | } | ||
| 239 | |||
| 240 | DefEntry def = defEntries.get(entry); | ||
| 241 | if (def != null && (def.getAccess().isPrivate())) { | ||
| 242 | return null; | ||
| 243 | } | ||
| 244 | |||
| 245 | // if we're protected/public/non-static, chances are we're somewhere down | ||
| 246 | LinkedList<ClassEntry> classEntries = new LinkedList<>(); | ||
| 247 | classEntries.add(entry.getOwnerClassEntry()); | ||
| 248 | while (!classEntries.isEmpty()) { | ||
| 249 | ClassEntry c = classEntries.remove(); | ||
| 250 | Entry cEntry = entry.updateOwnership(c); | ||
| 251 | |||
| 252 | if (entryExists(cEntry)) { | ||
| 253 | def = defEntries.get(cEntry); | ||
| 254 | if (def == null || (!def.getAccess().isPrivate())) { | ||
| 255 | return cEntry.getOwnerClassEntry(); | ||
| 256 | } | ||
| 257 | } | ||
| 258 | |||
| 259 | ClassEntry superC = getSuperclass(c); | ||
| 260 | if (superC != null) { | ||
| 261 | classEntries.add(superC); | ||
| 262 | } | ||
| 263 | if (entry instanceof MethodEntry) { | ||
| 264 | classEntries.addAll(getInterfaces(c)); | ||
| 265 | } | ||
| 266 | } | ||
| 267 | |||
| 268 | return null; | ||
| 269 | } | ||
| 270 | |||
| 271 | private boolean isJre(ClassEntry classEntry) { | ||
| 272 | String packageName = classEntry.getPackageName(); | ||
| 273 | return packageName != null && (packageName.startsWith("java") || packageName.startsWith("javax")); | ||
| 274 | } | ||
| 275 | } | ||