summaryrefslogtreecommitdiff
path: root/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java
diff options
context:
space:
mode:
authorGravatar lclc982016-06-30 00:49:21 +1000
committerGravatar GitHub2016-06-30 00:49:21 +1000
commit4be005617b3b8c3578cca07c5d085d12916f0d1d (patch)
treedb163431f38703e26da417ef05eaea2b27a498b9 /src/main/java/cuchaz/enigma/analysis/TranslationIndex.java
parentSome small changes to fix idea importing (diff)
downloadenigma-fork-4be005617b3b8c3578cca07c5d085d12916f0d1d.tar.gz
enigma-fork-4be005617b3b8c3578cca07c5d085d12916f0d1d.tar.xz
enigma-fork-4be005617b3b8c3578cca07c5d085d12916f0d1d.zip
Json format (#2)
* Added new format * Fixed bug * Updated Version
Diffstat (limited to 'src/main/java/cuchaz/enigma/analysis/TranslationIndex.java')
-rw-r--r--src/main/java/cuchaz/enigma/analysis/TranslationIndex.java282
1 files changed, 282 insertions, 0 deletions
diff --git a/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java b/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java
new file mode 100644
index 0000000..0261a96
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java
@@ -0,0 +1,282 @@
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 ******************************************************************************/
11package cuchaz.enigma.analysis;
12
13import com.google.common.collect.HashMultimap;
14import com.google.common.collect.Lists;
15import com.google.common.collect.Maps;
16import com.google.common.collect.Multimap;
17
18import java.io.*;
19import java.util.*;
20import java.util.zip.GZIPInputStream;
21import java.util.zip.GZIPOutputStream;
22
23import cuchaz.enigma.mapping.*;
24import javassist.CtBehavior;
25import javassist.CtClass;
26import javassist.CtField;
27import javassist.bytecode.Descriptor;
28
29public class TranslationIndex implements Serializable {
30
31 private static final long serialVersionUID = 738687982126844179L;
32
33 private Map<ClassEntry, ClassEntry> m_superclasses;
34 private Multimap<ClassEntry, FieldEntry> m_fieldEntries;
35 private Multimap<ClassEntry, BehaviorEntry> m_behaviorEntries;
36 private Multimap<ClassEntry, ClassEntry> m_interfaces;
37
38 public TranslationIndex() {
39 m_superclasses = Maps.newHashMap();
40 m_fieldEntries = HashMultimap.create();
41 m_behaviorEntries = HashMultimap.create();
42 m_interfaces = HashMultimap.create();
43 }
44
45 public TranslationIndex(TranslationIndex other, Translator translator) {
46
47 // translate the superclasses
48 m_superclasses = Maps.newHashMap();
49 for (Map.Entry<ClassEntry, ClassEntry> mapEntry : other.m_superclasses.entrySet()) {
50 m_superclasses.put(
51 translator.translateEntry(mapEntry.getKey()),
52 translator.translateEntry(mapEntry.getValue())
53 );
54 }
55
56 // translate the interfaces
57 m_interfaces = HashMultimap.create();
58 for (Map.Entry<ClassEntry, ClassEntry> mapEntry : other.m_interfaces.entries()) {
59 m_interfaces.put(
60 translator.translateEntry(mapEntry.getKey()),
61 translator.translateEntry(mapEntry.getValue())
62 );
63 }
64
65 // translate the fields
66 m_fieldEntries = HashMultimap.create();
67 for (Map.Entry<ClassEntry, FieldEntry> mapEntry : other.m_fieldEntries.entries()) {
68 m_fieldEntries.put(
69 translator.translateEntry(mapEntry.getKey()),
70 translator.translateEntry(mapEntry.getValue())
71 );
72 }
73
74 m_behaviorEntries = HashMultimap.create();
75 for (Map.Entry<ClassEntry, BehaviorEntry> mapEntry : other.m_behaviorEntries.entries()) {
76 m_behaviorEntries.put(
77 translator.translateEntry(mapEntry.getKey()),
78 translator.translateEntry(mapEntry.getValue())
79 );
80 }
81 }
82
83 public void indexClass(CtClass c) {
84 indexClass(c, true);
85 }
86
87 public void indexClass(CtClass c, boolean indexMembers) {
88
89 ClassEntry classEntry = EntryFactory.getClassEntry(c);
90 if (isJre(classEntry)) {
91 return;
92 }
93
94 // add the superclass
95 ClassEntry superclassEntry = EntryFactory.getSuperclassEntry(c);
96 if (superclassEntry != null) {
97 m_superclasses.put(classEntry, superclassEntry);
98 }
99
100 // add the interfaces
101 for (String interfaceClassName : c.getClassFile().getInterfaces()) {
102 ClassEntry interfaceClassEntry = new ClassEntry(Descriptor.toJvmName(interfaceClassName));
103 if (!isJre(interfaceClassEntry)) {
104 m_interfaces.put(classEntry, interfaceClassEntry);
105 }
106 }
107
108 if (indexMembers) {
109 // add fields
110 for (CtField field : c.getDeclaredFields()) {
111 FieldEntry fieldEntry = EntryFactory.getFieldEntry(field);
112 m_fieldEntries.put(fieldEntry.getClassEntry(), fieldEntry);
113 }
114
115 // add behaviors
116 for (CtBehavior behavior : c.getDeclaredBehaviors()) {
117 BehaviorEntry behaviorEntry = EntryFactory.getBehaviorEntry(behavior);
118 m_behaviorEntries.put(behaviorEntry.getClassEntry(), behaviorEntry);
119 }
120 }
121 }
122
123 public void renameClasses(Map<String, String> renames) {
124 EntryRenamer.renameClassesInMap(renames, m_superclasses);
125 EntryRenamer.renameClassesInMultimap(renames, m_fieldEntries);
126 EntryRenamer.renameClassesInMultimap(renames, m_behaviorEntries);
127 }
128
129 public ClassEntry getSuperclass(ClassEntry classEntry) {
130 return m_superclasses.get(classEntry);
131 }
132
133 public List<ClassEntry> getAncestry(ClassEntry classEntry) {
134 List<ClassEntry> ancestors = Lists.newArrayList();
135 while (classEntry != null) {
136 classEntry = getSuperclass(classEntry);
137 if (classEntry != null) {
138 ancestors.add(classEntry);
139 }
140 }
141 return ancestors;
142 }
143
144 public List<ClassEntry> getSubclass(ClassEntry classEntry) {
145
146 // linear search is fast enough for now
147 List<ClassEntry> subclasses = Lists.newArrayList();
148 for (Map.Entry<ClassEntry, ClassEntry> entry : m_superclasses.entrySet()) {
149 ClassEntry subclass = entry.getKey();
150 ClassEntry superclass = entry.getValue();
151 if (classEntry.equals(superclass)) {
152 subclasses.add(subclass);
153 }
154 }
155 return subclasses;
156 }
157
158 public void getSubclassesRecursively(Set<ClassEntry> out, ClassEntry classEntry) {
159 for (ClassEntry subclassEntry : getSubclass(classEntry)) {
160 out.add(subclassEntry);
161 getSubclassesRecursively(out, subclassEntry);
162 }
163 }
164
165 public void getSubclassNamesRecursively(Set<String> out, ClassEntry classEntry) {
166 for (ClassEntry subclassEntry : getSubclass(classEntry)) {
167 out.add(subclassEntry.getName());
168 getSubclassNamesRecursively(out, subclassEntry);
169 }
170 }
171
172 public Collection<Map.Entry<ClassEntry, ClassEntry>> getClassInterfaces() {
173 return m_interfaces.entries();
174 }
175
176 public Collection<ClassEntry> getInterfaces(ClassEntry classEntry) {
177 return m_interfaces.get(classEntry);
178 }
179
180 public boolean isInterface(ClassEntry classEntry) {
181 return m_interfaces.containsValue(classEntry);
182 }
183
184 public boolean entryExists(Entry entry) {
185 if (entry instanceof FieldEntry) {
186 return fieldExists((FieldEntry) entry);
187 } else if (entry instanceof BehaviorEntry) {
188 return behaviorExists((BehaviorEntry) entry);
189 } else if (entry instanceof ArgumentEntry) {
190 return behaviorExists(((ArgumentEntry) entry).getBehaviorEntry());
191 }
192 throw new IllegalArgumentException("Cannot check existence for " + entry.getClass());
193 }
194
195 public boolean fieldExists(FieldEntry fieldEntry) {
196 return m_fieldEntries.containsEntry(fieldEntry.getClassEntry(), fieldEntry);
197 }
198
199 public boolean behaviorExists(BehaviorEntry behaviorEntry) {
200 return m_behaviorEntries.containsEntry(behaviorEntry.getClassEntry(), behaviorEntry);
201 }
202
203 public ClassEntry resolveEntryClass(Entry entry) {
204
205 if (entry instanceof ClassEntry) {
206 return (ClassEntry) entry;
207 }
208
209 ClassEntry superclassEntry = resolveSuperclass(entry);
210 if (superclassEntry != null) {
211 return superclassEntry;
212 }
213
214 ClassEntry interfaceEntry = resolveInterface(entry);
215 if (interfaceEntry != null) {
216 return interfaceEntry;
217 }
218
219 return null;
220 }
221
222 public ClassEntry resolveSuperclass(Entry entry) {
223
224 // this entry could refer to a method on a class where the method is not actually implemented
225 // travel up the inheritance tree to find the closest implementation
226 while (!entryExists(entry)) {
227
228 // is there a parent class?
229 ClassEntry superclassEntry = getSuperclass(entry.getClassEntry());
230 if (superclassEntry == null) {
231 // this is probably a method from a class in a library
232 // we can't trace the implementation up any higher unless we index the library
233 return null;
234 }
235
236 // move up to the parent class
237 entry = entry.cloneToNewClass(superclassEntry);
238 }
239 return entry.getClassEntry();
240 }
241
242 public ClassEntry resolveInterface(Entry entry) {
243
244 // the interfaces for any class is a forest
245 // so let's look at all the trees
246 for (ClassEntry interfaceEntry : m_interfaces.get(entry.getClassEntry())) {
247 ClassEntry resolvedClassEntry = resolveSuperclass(entry.cloneToNewClass(interfaceEntry));
248 if (resolvedClassEntry != null) {
249 return resolvedClassEntry;
250 }
251 }
252 return null;
253 }
254
255 private boolean isJre(ClassEntry classEntry) {
256 String packageName = classEntry.getPackageName();
257 return packageName != null && (packageName.startsWith("java") || packageName.startsWith("javax"));
258 }
259
260 public void write(OutputStream out)
261 throws IOException {
262 GZIPOutputStream gzipout = new GZIPOutputStream(out);
263 ObjectOutputStream oout = new ObjectOutputStream(gzipout);
264 oout.writeObject(m_superclasses);
265 oout.writeObject(m_fieldEntries);
266 oout.writeObject(m_behaviorEntries);
267 gzipout.finish();
268 }
269
270 @SuppressWarnings("unchecked")
271 public void read(InputStream in)
272 throws IOException {
273 try {
274 ObjectInputStream oin = new ObjectInputStream(new GZIPInputStream(in));
275 m_superclasses = (HashMap<ClassEntry, ClassEntry>) oin.readObject();
276 m_fieldEntries = (HashMultimap<ClassEntry, FieldEntry>) oin.readObject();
277 m_behaviorEntries = (HashMultimap<ClassEntry, BehaviorEntry>) oin.readObject();
278 } catch (ClassNotFoundException ex) {
279 throw new Error(ex);
280 }
281 }
282}