summaryrefslogtreecommitdiff
path: root/src/cuchaz/enigma/mapping/ClassMapping.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/cuchaz/enigma/mapping/ClassMapping.java')
-rw-r--r--src/cuchaz/enigma/mapping/ClassMapping.java460
1 files changed, 460 insertions, 0 deletions
diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java
new file mode 100644
index 0000000..0b0105e
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/ClassMapping.java
@@ -0,0 +1,460 @@
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.io.Serializable;
14import java.util.ArrayList;
15import java.util.Map;
16
17import com.google.common.collect.Maps;
18
19public class ClassMapping implements Serializable, Comparable<ClassMapping> {
20
21 private static final long serialVersionUID = -5148491146902340107L;
22
23 private String m_obfFullName;
24 private String m_obfSimpleName;
25 private String m_deobfName;
26 private Map<String,ClassMapping> m_innerClassesByObfSimple;
27 private Map<String,ClassMapping> m_innerClassesByDeobf;
28 private Map<String,FieldMapping> m_fieldsByObf;
29 private Map<String,FieldMapping> m_fieldsByDeobf;
30 private Map<String,MethodMapping> m_methodsByObf;
31 private Map<String,MethodMapping> m_methodsByDeobf;
32
33 public ClassMapping(String obfFullName) {
34 this(obfFullName, null);
35 }
36
37 public ClassMapping(String obfFullName, String deobfName) {
38 m_obfFullName = obfFullName;
39 ClassEntry classEntry = new ClassEntry(obfFullName);
40 m_obfSimpleName = classEntry.isInnerClass() ? classEntry.getInnermostClassName() : classEntry.getSimpleName();
41 m_deobfName = NameValidator.validateClassName(deobfName, false);
42 m_innerClassesByObfSimple = Maps.newHashMap();
43 m_innerClassesByDeobf = Maps.newHashMap();
44 m_fieldsByObf = Maps.newHashMap();
45 m_fieldsByDeobf = Maps.newHashMap();
46 m_methodsByObf = Maps.newHashMap();
47 m_methodsByDeobf = Maps.newHashMap();
48 }
49
50 public String getObfFullName() {
51 return m_obfFullName;
52 }
53
54 public String getObfSimpleName() {
55 return m_obfSimpleName;
56 }
57
58 public String getDeobfName() {
59 return m_deobfName;
60 }
61
62 public void setDeobfName(String val) {
63 m_deobfName = NameValidator.validateClassName(val, false);
64 }
65
66 //// INNER CLASSES ////////
67
68 public Iterable<ClassMapping> innerClasses() {
69 assert (m_innerClassesByObfSimple.size() >= m_innerClassesByDeobf.size());
70 return m_innerClassesByObfSimple.values();
71 }
72
73 public void addInnerClassMapping(ClassMapping classMapping) {
74 boolean obfWasAdded = m_innerClassesByObfSimple.put(classMapping.getObfSimpleName(), classMapping) == null;
75 assert (obfWasAdded);
76 if (classMapping.getDeobfName() != null) {
77 assert (isSimpleClassName(classMapping.getDeobfName()));
78 boolean deobfWasAdded = m_innerClassesByDeobf.put(classMapping.getDeobfName(), classMapping) == null;
79 assert (deobfWasAdded);
80 }
81 }
82
83 public void removeInnerClassMapping(ClassMapping classMapping) {
84 boolean obfWasRemoved = m_innerClassesByObfSimple.remove(classMapping.getObfSimpleName()) != null;
85 assert (obfWasRemoved);
86 if (classMapping.getDeobfName() != null) {
87 boolean deobfWasRemoved = m_innerClassesByDeobf.remove(classMapping.getDeobfName()) != null;
88 assert (deobfWasRemoved);
89 }
90 }
91
92 public ClassMapping getOrCreateInnerClass(ClassEntry obfInnerClass) {
93 ClassMapping classMapping = m_innerClassesByObfSimple.get(obfInnerClass.getInnermostClassName());
94 if (classMapping == null) {
95 classMapping = new ClassMapping(obfInnerClass.getName());
96 boolean wasAdded = m_innerClassesByObfSimple.put(classMapping.getObfSimpleName(), classMapping) == null;
97 assert (wasAdded);
98 }
99 return classMapping;
100 }
101
102 public ClassMapping getInnerClassByObfSimple(String obfSimpleName) {
103 assert (isSimpleClassName(obfSimpleName));
104 return m_innerClassesByObfSimple.get(obfSimpleName);
105 }
106
107 public ClassMapping getInnerClassByDeobf(String deobfName) {
108 assert (isSimpleClassName(deobfName));
109 return m_innerClassesByDeobf.get(deobfName);
110 }
111
112 public ClassMapping getInnerClassByDeobfThenObfSimple(String name) {
113 ClassMapping classMapping = getInnerClassByDeobf(name);
114 if (classMapping == null) {
115 classMapping = getInnerClassByObfSimple(name);
116 }
117 return classMapping;
118 }
119
120 public String getDeobfInnerClassName(String obfSimpleName) {
121 assert (isSimpleClassName(obfSimpleName));
122 ClassMapping classMapping = m_innerClassesByObfSimple.get(obfSimpleName);
123 if (classMapping != null) {
124 return classMapping.getDeobfName();
125 }
126 return null;
127 }
128
129 public void setInnerClassName(ClassEntry obfInnerClass, String deobfName) {
130 ClassMapping classMapping = getOrCreateInnerClass(obfInnerClass);
131 if (classMapping.getDeobfName() != null) {
132 boolean wasRemoved = m_innerClassesByDeobf.remove(classMapping.getDeobfName()) != null;
133 assert (wasRemoved);
134 }
135 classMapping.setDeobfName(deobfName);
136 if (deobfName != null) {
137 assert (isSimpleClassName(deobfName));
138 boolean wasAdded = m_innerClassesByDeobf.put(deobfName, classMapping) == null;
139 assert (wasAdded);
140 }
141 }
142
143 public boolean hasInnerClassByObfSimple(String obfSimpleName) {
144 return m_innerClassesByObfSimple.containsKey(obfSimpleName);
145 }
146
147 public boolean hasInnerClassByDeobf(String deobfName) {
148 return m_innerClassesByDeobf.containsKey(deobfName);
149 }
150
151
152 //// FIELDS ////////
153
154 public Iterable<FieldMapping> fields() {
155 assert (m_fieldsByObf.size() == m_fieldsByDeobf.size());
156 return m_fieldsByObf.values();
157 }
158
159 public boolean containsObfField(String obfName, Type obfType) {
160 return m_fieldsByObf.containsKey(getFieldKey(obfName, obfType));
161 }
162
163 public boolean containsDeobfField(String deobfName, Type deobfType) {
164 return m_fieldsByDeobf.containsKey(getFieldKey(deobfName, deobfType));
165 }
166
167 public void addFieldMapping(FieldMapping fieldMapping) {
168 String obfKey = getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType());
169 if (m_fieldsByObf.containsKey(obfKey)) {
170 throw new Error("Already have mapping for " + m_obfFullName + "." + obfKey);
171 }
172 String deobfKey = getFieldKey(fieldMapping.getDeobfName(), fieldMapping.getObfType());
173 if (m_fieldsByDeobf.containsKey(deobfKey)) {
174 throw new Error("Already have mapping for " + m_deobfName + "." + deobfKey);
175 }
176 boolean obfWasAdded = m_fieldsByObf.put(obfKey, fieldMapping) == null;
177 assert (obfWasAdded);
178 boolean deobfWasAdded = m_fieldsByDeobf.put(deobfKey, fieldMapping) == null;
179 assert (deobfWasAdded);
180 assert (m_fieldsByObf.size() == m_fieldsByDeobf.size());
181 }
182
183 public void removeFieldMapping(FieldMapping fieldMapping) {
184 boolean obfWasRemoved = m_fieldsByObf.remove(getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType())) != null;
185 assert (obfWasRemoved);
186 if (fieldMapping.getDeobfName() != null) {
187 boolean deobfWasRemoved = m_fieldsByDeobf.remove(getFieldKey(fieldMapping.getDeobfName(), fieldMapping.getObfType())) != null;
188 assert (deobfWasRemoved);
189 }
190 }
191
192 public FieldMapping getFieldByObf(String obfName, Type obfType) {
193 return m_fieldsByObf.get(getFieldKey(obfName, obfType));
194 }
195
196 public FieldMapping getFieldByDeobf(String deobfName, Type obfType) {
197 return m_fieldsByDeobf.get(getFieldKey(deobfName, obfType));
198 }
199
200 public String getObfFieldName(String deobfName, Type obfType) {
201 FieldMapping fieldMapping = m_fieldsByDeobf.get(getFieldKey(deobfName, obfType));
202 if (fieldMapping != null) {
203 return fieldMapping.getObfName();
204 }
205 return null;
206 }
207
208 public String getDeobfFieldName(String obfName, Type obfType) {
209 FieldMapping fieldMapping = m_fieldsByObf.get(getFieldKey(obfName, obfType));
210 if (fieldMapping != null) {
211 return fieldMapping.getDeobfName();
212 }
213 return null;
214 }
215
216 private String getFieldKey(String name, Type type) {
217 if (name == null) {
218 throw new IllegalArgumentException("name cannot be null!");
219 }
220 if (type == null) {
221 throw new IllegalArgumentException("type cannot be null!");
222 }
223 return name + ":" + type;
224 }
225
226
227 public void setFieldName(String obfName, Type obfType, String deobfName) {
228 assert(deobfName != null);
229 FieldMapping fieldMapping = m_fieldsByObf.get(getFieldKey(obfName, obfType));
230 if (fieldMapping == null) {
231 fieldMapping = new FieldMapping(obfName, obfType, deobfName);
232 boolean obfWasAdded = m_fieldsByObf.put(getFieldKey(obfName, obfType), fieldMapping) == null;
233 assert (obfWasAdded);
234 } else {
235 boolean wasRemoved = m_fieldsByDeobf.remove(getFieldKey(fieldMapping.getDeobfName(), obfType)) != null;
236 assert (wasRemoved);
237 }
238 fieldMapping.setDeobfName(deobfName);
239 if (deobfName != null) {
240 boolean wasAdded = m_fieldsByDeobf.put(getFieldKey(deobfName, obfType), fieldMapping) == null;
241 assert (wasAdded);
242 }
243 }
244
245 public void setFieldObfNameAndType(String oldObfName, Type obfType, String newObfName, Type newObfType) {
246 assert(newObfName != null);
247 FieldMapping fieldMapping = m_fieldsByObf.remove(getFieldKey(oldObfName, obfType));
248 assert(fieldMapping != null);
249 fieldMapping.setObfName(newObfName);
250 fieldMapping.setObfType(newObfType);
251 boolean obfWasAdded = m_fieldsByObf.put(getFieldKey(newObfName, newObfType), fieldMapping) == null;
252 assert(obfWasAdded);
253 }
254
255
256 //// METHODS ////////
257
258 public Iterable<MethodMapping> methods() {
259 assert (m_methodsByObf.size() >= m_methodsByDeobf.size());
260 return m_methodsByObf.values();
261 }
262
263 public boolean containsObfMethod(String obfName, Signature obfSignature) {
264 return m_methodsByObf.containsKey(getMethodKey(obfName, obfSignature));
265 }
266
267 public boolean containsDeobfMethod(String deobfName, Signature obfSignature) {
268 return m_methodsByDeobf.containsKey(getMethodKey(deobfName, obfSignature));
269 }
270
271 public void addMethodMapping(MethodMapping methodMapping) {
272 String obfKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature());
273 if (m_methodsByObf.containsKey(obfKey)) {
274 throw new Error("Already have mapping for " + m_obfFullName + "." + obfKey);
275 }
276 boolean wasAdded = m_methodsByObf.put(obfKey, methodMapping) == null;
277 assert (wasAdded);
278 if (methodMapping.getDeobfName() != null) {
279 String deobfKey = getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature());
280 if (m_methodsByDeobf.containsKey(deobfKey)) {
281 throw new Error("Already have mapping for " + m_deobfName + "." + deobfKey);
282 }
283 boolean deobfWasAdded = m_methodsByDeobf.put(deobfKey, methodMapping) == null;
284 assert (deobfWasAdded);
285 }
286 assert (m_methodsByObf.size() >= m_methodsByDeobf.size());
287 }
288
289 public void removeMethodMapping(MethodMapping methodMapping) {
290 boolean obfWasRemoved = m_methodsByObf.remove(getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature())) != null;
291 assert (obfWasRemoved);
292 if (methodMapping.getDeobfName() != null) {
293 boolean deobfWasRemoved = m_methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature())) != null;
294 assert (deobfWasRemoved);
295 }
296 }
297
298 public MethodMapping getMethodByObf(String obfName, Signature obfSignature) {
299 return m_methodsByObf.get(getMethodKey(obfName, obfSignature));
300 }
301
302 public MethodMapping getMethodByDeobf(String deobfName, Signature obfSignature) {
303 return m_methodsByDeobf.get(getMethodKey(deobfName, obfSignature));
304 }
305
306 private String getMethodKey(String name, Signature signature) {
307 if (name == null) {
308 throw new IllegalArgumentException("name cannot be null!");
309 }
310 if (signature == null) {
311 throw new IllegalArgumentException("signature cannot be null!");
312 }
313 return name + signature;
314 }
315
316 public void setMethodName(String obfName, Signature obfSignature, String deobfName) {
317 MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfName, obfSignature));
318 if (methodMapping == null) {
319 methodMapping = createMethodMapping(obfName, obfSignature);
320 } else if (methodMapping.getDeobfName() != null) {
321 boolean wasRemoved = m_methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature())) != null;
322 assert (wasRemoved);
323 }
324 methodMapping.setDeobfName(deobfName);
325 if (deobfName != null) {
326 boolean wasAdded = m_methodsByDeobf.put(getMethodKey(deobfName, obfSignature), methodMapping) == null;
327 assert (wasAdded);
328 }
329 }
330
331 public void setMethodObfNameAndSignature(String oldObfName, Signature obfSignature, String newObfName, Signature newObfSignature) {
332 assert(newObfName != null);
333 MethodMapping methodMapping = m_methodsByObf.remove(getMethodKey(oldObfName, obfSignature));
334 assert(methodMapping != null);
335 methodMapping.setObfName(newObfName);
336 methodMapping.setObfSignature(newObfSignature);
337 boolean obfWasAdded = m_methodsByObf.put(getMethodKey(newObfName, newObfSignature), methodMapping) == null;
338 assert(obfWasAdded);
339 }
340
341 //// ARGUMENTS ////////
342
343 public void setArgumentName(String obfMethodName, Signature obfMethodSignature, int argumentIndex, String argumentName) {
344 assert(argumentName != null);
345 MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfMethodName, obfMethodSignature));
346 if (methodMapping == null) {
347 methodMapping = createMethodMapping(obfMethodName, obfMethodSignature);
348 }
349 methodMapping.setArgumentName(argumentIndex, argumentName);
350 }
351
352 public void removeArgumentName(String obfMethodName, Signature obfMethodSignature, int argumentIndex) {
353 m_methodsByObf.get(getMethodKey(obfMethodName, obfMethodSignature)).removeArgumentName(argumentIndex);
354 }
355
356 private MethodMapping createMethodMapping(String obfName, Signature obfSignature) {
357 MethodMapping methodMapping = new MethodMapping(obfName, obfSignature);
358 boolean wasAdded = m_methodsByObf.put(getMethodKey(obfName, obfSignature), methodMapping) == null;
359 assert (wasAdded);
360 return methodMapping;
361 }
362
363 @Override
364 public String toString() {
365 StringBuilder buf = new StringBuilder();
366 buf.append(m_obfFullName);
367 buf.append(" <-> ");
368 buf.append(m_deobfName);
369 buf.append("\n");
370 buf.append("Fields:\n");
371 for (FieldMapping fieldMapping : fields()) {
372 buf.append("\t");
373 buf.append(fieldMapping.getObfName());
374 buf.append(" <-> ");
375 buf.append(fieldMapping.getDeobfName());
376 buf.append("\n");
377 }
378 buf.append("Methods:\n");
379 for (MethodMapping methodMapping : m_methodsByObf.values()) {
380 buf.append(methodMapping.toString());
381 buf.append("\n");
382 }
383 buf.append("Inner Classes:\n");
384 for (ClassMapping classMapping : m_innerClassesByObfSimple.values()) {
385 buf.append("\t");
386 buf.append(classMapping.getObfSimpleName());
387 buf.append(" <-> ");
388 buf.append(classMapping.getDeobfName());
389 buf.append("\n");
390 }
391 return buf.toString();
392 }
393
394 @Override
395 public int compareTo(ClassMapping other) {
396 // sort by a, b, c, ... aa, ab, etc
397 if (m_obfFullName.length() != other.m_obfFullName.length()) {
398 return m_obfFullName.length() - other.m_obfFullName.length();
399 }
400 return m_obfFullName.compareTo(other.m_obfFullName);
401 }
402
403 public boolean renameObfClass(String oldObfClassName, String newObfClassName) {
404
405 // rename inner classes
406 for (ClassMapping innerClassMapping : new ArrayList<ClassMapping>(m_innerClassesByObfSimple.values())) {
407 if (innerClassMapping.renameObfClass(oldObfClassName, newObfClassName)) {
408 boolean wasRemoved = m_innerClassesByObfSimple.remove(oldObfClassName) != null;
409 assert (wasRemoved);
410 boolean wasAdded = m_innerClassesByObfSimple.put(newObfClassName, innerClassMapping) == null;
411 assert (wasAdded);
412 }
413 }
414
415 // rename field types
416 for (FieldMapping fieldMapping : new ArrayList<FieldMapping>(m_fieldsByObf.values())) {
417 String oldFieldKey = getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType());
418 if (fieldMapping.renameObfClass(oldObfClassName, newObfClassName)) {
419 boolean wasRemoved = m_fieldsByObf.remove(oldFieldKey) != null;
420 assert (wasRemoved);
421 boolean wasAdded = m_fieldsByObf.put(getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfType()), fieldMapping) == null;
422 assert (wasAdded);
423 }
424 }
425
426 // rename method signatures
427 for (MethodMapping methodMapping : new ArrayList<MethodMapping>(m_methodsByObf.values())) {
428 String oldMethodKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature());
429 if (methodMapping.renameObfClass(oldObfClassName, newObfClassName)) {
430 boolean wasRemoved = m_methodsByObf.remove(oldMethodKey) != null;
431 assert (wasRemoved);
432 boolean wasAdded = m_methodsByObf.put(getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature()), methodMapping) == null;
433 assert (wasAdded);
434 }
435 }
436
437 if (m_obfFullName.equals(oldObfClassName)) {
438 // rename this class
439 m_obfFullName = newObfClassName;
440 return true;
441 }
442 return false;
443 }
444
445 public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) {
446 MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfBehaviorEntry.getName(), obfBehaviorEntry.getSignature()));
447 if (methodMapping != null) {
448 return methodMapping.containsArgument(name);
449 }
450 return false;
451 }
452
453 public static boolean isSimpleClassName(String name) {
454 return name.indexOf('/') < 0 && name.indexOf('$') < 0;
455 }
456
457 public ClassEntry getObfEntry() {
458 return new ClassEntry(m_obfFullName);
459 }
460}