summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/mapping/Translator.java
diff options
context:
space:
mode:
authorGravatar Michael Smith2015-05-21 23:30:00 +0100
committerGravatar Michael Smith2015-05-21 23:30:00 +0100
commite3f452250e51b7271f3989c7dfd12e4422934942 (patch)
tree5aa482f9a6e21eb318a3e23e7d8274d77c73faf6 /src/cuchaz/enigma/mapping/Translator.java
downloadenigma-fork-e3f452250e51b7271f3989c7dfd12e4422934942.tar.gz
enigma-fork-e3f452250e51b7271f3989c7dfd12e4422934942.tar.xz
enigma-fork-e3f452250e51b7271f3989c7dfd12e4422934942.zip
Support Gradle alongside SSJB
This makes builds faster, simpler and better automated but still keeps Cuchaz happy. :)
Diffstat (limited to 'src/cuchaz/enigma/mapping/Translator.java')
-rw-r--r--src/cuchaz/enigma/mapping/Translator.java289
1 files changed, 289 insertions, 0 deletions
diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java
new file mode 100644
index 0000000..41c7d7c
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/Translator.java
@@ -0,0 +1,289 @@
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 *
8 * Contributors:
9 * Jeff Martin - initial API and implementation
10 ******************************************************************************/
11package cuchaz.enigma.mapping;
12
13import java.util.List;
14import java.util.Map;
15
16import com.google.common.collect.Lists;
17import com.google.common.collect.Maps;
18
19import cuchaz.enigma.analysis.TranslationIndex;
20
21public class Translator {
22
23 private TranslationDirection m_direction;
24 private Map<String,ClassMapping> m_classes;
25 private TranslationIndex m_index;
26
27 private ClassNameReplacer m_classNameReplacer = new ClassNameReplacer() {
28 @Override
29 public String replace(String className) {
30 return translateEntry(new ClassEntry(className)).getName();
31 }
32 };
33
34 public Translator() {
35 m_direction = null;
36 m_classes = Maps.newHashMap();
37 m_index = new TranslationIndex();
38 }
39
40 public Translator(TranslationDirection direction, Map<String,ClassMapping> classes, TranslationIndex index) {
41 m_direction = direction;
42 m_classes = classes;
43 m_index = index;
44 }
45
46 public TranslationDirection getDirection() {
47 return m_direction;
48 }
49
50 public TranslationIndex getTranslationIndex() {
51 return m_index;
52 }
53
54 @SuppressWarnings("unchecked")
55 public <T extends Entry> T translateEntry(T entry) {
56 if (entry instanceof ClassEntry) {
57 return (T)translateEntry((ClassEntry)entry);
58 } else if (entry instanceof FieldEntry) {
59 return (T)translateEntry((FieldEntry)entry);
60 } else if (entry instanceof MethodEntry) {
61 return (T)translateEntry((MethodEntry)entry);
62 } else if (entry instanceof ConstructorEntry) {
63 return (T)translateEntry((ConstructorEntry)entry);
64 } else if (entry instanceof ArgumentEntry) {
65 return (T)translateEntry((ArgumentEntry)entry);
66 } else {
67 throw new Error("Unknown entry type: " + entry.getClass().getName());
68 }
69 }
70
71 public <T extends Entry> String translate(T entry) {
72 if (entry instanceof ClassEntry) {
73 return translate((ClassEntry)entry);
74 } else if (entry instanceof FieldEntry) {
75 return translate((FieldEntry)entry);
76 } else if (entry instanceof MethodEntry) {
77 return translate((MethodEntry)entry);
78 } else if (entry instanceof ConstructorEntry) {
79 return translate((ConstructorEntry)entry);
80 } else if (entry instanceof ArgumentEntry) {
81 return translate((ArgumentEntry)entry);
82 } else {
83 throw new Error("Unknown entry type: " + entry.getClass().getName());
84 }
85 }
86
87 public String translate(ClassEntry in) {
88 ClassEntry translated = translateEntry(in);
89 if (translated.equals(in)) {
90 return null;
91 }
92 return translated.getName();
93 }
94
95 public String translateClass(String className) {
96 return translate(new ClassEntry(className));
97 }
98
99 public ClassEntry translateEntry(ClassEntry in) {
100
101 if (in.isInnerClass()) {
102
103 // translate as much of the class chain as we can
104 List<ClassMapping> mappingsChain = getClassMappingChain(in);
105 String[] obfClassNames = in.getName().split("\\$");
106 StringBuilder buf = new StringBuilder();
107 for (int i=0; i<obfClassNames.length; i++) {
108 boolean isFirstClass = buf.length() == 0;
109 String className = null;
110 ClassMapping classMapping = mappingsChain.get(i);
111 if (classMapping != null) {
112 className = m_direction.choose(
113 classMapping.getDeobfName(),
114 isFirstClass ? classMapping.getObfFullName() : classMapping.getObfSimpleName()
115 );
116 }
117 if (className == null) {
118 className = obfClassNames[i];
119 }
120 if (!isFirstClass) {
121 buf.append("$");
122 }
123 buf.append(className);
124 }
125 return new ClassEntry(buf.toString());
126
127 } else {
128
129 // normal classes are easy
130 ClassMapping classMapping = m_classes.get(in.getName());
131 if (classMapping == null) {
132 return in;
133 }
134 return m_direction.choose(
135 classMapping.getDeobfName() != null ? new ClassEntry(classMapping.getDeobfName()) : in,
136 new ClassEntry(classMapping.getObfFullName())
137 );
138 }
139 }
140
141 public String translate(FieldEntry in) {
142
143 // resolve the class entry
144 ClassEntry resolvedClassEntry = m_index.resolveEntryClass(in);
145 if (resolvedClassEntry != null) {
146
147 // look for the class
148 ClassMapping classMapping = findClassMapping(resolvedClassEntry);
149 if (classMapping != null) {
150
151 // look for the field
152 String translatedName = m_direction.choose(
153 classMapping.getDeobfFieldName(in.getName(), in.getType()),
154 classMapping.getObfFieldName(in.getName(), translateType(in.getType()))
155 );
156 if (translatedName != null) {
157 return translatedName;
158 }
159 }
160 }
161 return null;
162 }
163
164 public FieldEntry translateEntry(FieldEntry in) {
165 String name = translate(in);
166 if (name == null) {
167 name = in.getName();
168 }
169 return new FieldEntry(translateEntry(in.getClassEntry()), name, translateType(in.getType()));
170 }
171
172 public String translate(MethodEntry in) {
173
174 // resolve the class entry
175 ClassEntry resolvedClassEntry = m_index.resolveEntryClass(in);
176 if (resolvedClassEntry != null) {
177
178 // look for class
179 ClassMapping classMapping = findClassMapping(resolvedClassEntry);
180 if (classMapping != null) {
181
182 // look for the method
183 MethodMapping methodMapping = m_direction.choose(
184 classMapping.getMethodByObf(in.getName(), in.getSignature()),
185 classMapping.getMethodByDeobf(in.getName(), translateSignature(in.getSignature()))
186 );
187 if (methodMapping != null) {
188 return m_direction.choose(methodMapping.getDeobfName(), methodMapping.getObfName());
189 }
190 }
191 }
192 return null;
193 }
194
195 public MethodEntry translateEntry(MethodEntry in) {
196 String name = translate(in);
197 if (name == null) {
198 name = in.getName();
199 }
200 return new MethodEntry(translateEntry(in.getClassEntry()), name, translateSignature(in.getSignature()));
201 }
202
203 public ConstructorEntry translateEntry(ConstructorEntry in) {
204 if (in.isStatic()) {
205 return new ConstructorEntry(translateEntry(in.getClassEntry()));
206 } else {
207 return new ConstructorEntry(translateEntry(in.getClassEntry()), translateSignature(in.getSignature()));
208 }
209 }
210
211 public BehaviorEntry translateEntry(BehaviorEntry in) {
212 if (in instanceof MethodEntry) {
213 return translateEntry((MethodEntry)in);
214 } else if (in instanceof ConstructorEntry) {
215 return translateEntry((ConstructorEntry)in);
216 }
217 throw new Error("Wrong entry type!");
218 }
219
220 public String translate(ArgumentEntry in) {
221
222 // look for the class
223 ClassMapping classMapping = findClassMapping(in.getClassEntry());
224 if (classMapping != null) {
225
226 // look for the method
227 MethodMapping methodMapping = m_direction.choose(
228 classMapping.getMethodByObf(in.getMethodName(), in.getMethodSignature()),
229 classMapping.getMethodByDeobf(in.getMethodName(), translateSignature(in.getMethodSignature()))
230 );
231 if (methodMapping != null) {
232 return m_direction.choose(
233 methodMapping.getDeobfArgumentName(in.getIndex()),
234 methodMapping.getObfArgumentName(in.getIndex())
235 );
236 }
237 }
238 return null;
239 }
240
241 public ArgumentEntry translateEntry(ArgumentEntry in) {
242 String name = translate(in);
243 if (name == null) {
244 name = in.getName();
245 }
246 return new ArgumentEntry(translateEntry(in.getBehaviorEntry()), in.getIndex(), name);
247 }
248
249 public Type translateType(Type type) {
250 return new Type(type, m_classNameReplacer);
251 }
252
253 public Signature translateSignature(Signature signature) {
254 return new Signature(signature, m_classNameReplacer);
255 }
256
257 private ClassMapping findClassMapping(ClassEntry in) {
258 List<ClassMapping> mappingChain = getClassMappingChain(in);
259 return mappingChain.get(mappingChain.size() - 1);
260 }
261
262 private List<ClassMapping> getClassMappingChain(ClassEntry in) {
263
264 // get a list of all the classes in the hierarchy
265 String[] parts = in.getName().split("\\$");
266 List<ClassMapping> mappingsChain = Lists.newArrayList();
267
268 // get mappings for the outer class
269 ClassMapping outerClassMapping = m_classes.get(parts[0]);
270 mappingsChain.add(outerClassMapping);
271
272 for (int i=1; i<parts.length; i++) {
273
274 // get mappings for the inner class
275 ClassMapping innerClassMapping = null;
276 if (outerClassMapping != null) {
277 innerClassMapping = m_direction.choose(
278 outerClassMapping.getInnerClassByObfSimple(parts[i]),
279 outerClassMapping.getInnerClassByDeobfThenObfSimple(parts[i])
280 );
281 }
282 mappingsChain.add(innerClassMapping);
283 outerClassMapping = innerClassMapping;
284 }
285
286 assert(mappingsChain.size() == parts.length);
287 return mappingsChain;
288 }
289}