summaryrefslogtreecommitdiff
path: root/src/main/java/cuchaz/enigma/mapping/Mappings.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/cuchaz/enigma/mapping/Mappings.java')
-rw-r--r--src/main/java/cuchaz/enigma/mapping/Mappings.java201
1 files changed, 201 insertions, 0 deletions
diff --git a/src/main/java/cuchaz/enigma/mapping/Mappings.java b/src/main/java/cuchaz/enigma/mapping/Mappings.java
new file mode 100644
index 0000000..a48ec3f
--- /dev/null
+++ b/src/main/java/cuchaz/enigma/mapping/Mappings.java
@@ -0,0 +1,201 @@
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.mapping;
12
13import com.google.common.collect.Lists;
14import com.google.common.collect.Maps;
15import com.google.common.collect.Sets;
16
17import java.io.Serializable;
18import java.util.*;
19
20import cuchaz.enigma.analysis.TranslationIndex;
21
22public class Mappings implements Serializable {
23
24 private static final long serialVersionUID = 4649790259460259026L;
25
26 protected Map<String, ClassMapping> m_classesByObf;
27 protected Map<String, ClassMapping> m_classesByDeobf;
28
29 public Mappings() {
30 m_classesByObf = Maps.newHashMap();
31 m_classesByDeobf = Maps.newHashMap();
32 }
33
34 public Mappings(Iterable<ClassMapping> classes) {
35 this();
36
37 for (ClassMapping classMapping : classes) {
38 m_classesByObf.put(classMapping.getObfFullName(), classMapping);
39 if (classMapping.getDeobfName() != null) {
40 m_classesByDeobf.put(classMapping.getDeobfName(), classMapping);
41 }
42 }
43 }
44
45 public Collection<ClassMapping> classes() {
46 assert (m_classesByObf.size() >= m_classesByDeobf.size());
47 return m_classesByObf.values();
48 }
49
50 public void addClassMapping(ClassMapping classMapping) {
51 if (m_classesByObf.containsKey(classMapping.getObfFullName())) {
52 throw new Error("Already have mapping for " + classMapping.getObfFullName());
53 }
54 boolean obfWasAdded = m_classesByObf.put(classMapping.getObfFullName(), classMapping) == null;
55 assert (obfWasAdded);
56 if (classMapping.getDeobfName() != null) {
57 if (m_classesByDeobf.containsKey(classMapping.getDeobfName())) {
58 throw new Error("Already have mapping for " + classMapping.getDeobfName());
59 }
60 boolean deobfWasAdded = m_classesByDeobf.put(classMapping.getDeobfName(), classMapping) == null;
61 assert (deobfWasAdded);
62 }
63 }
64
65 public void removeClassMapping(ClassMapping classMapping) {
66 boolean obfWasRemoved = m_classesByObf.remove(classMapping.getObfFullName()) != null;
67 assert (obfWasRemoved);
68 if (classMapping.getDeobfName() != null) {
69 boolean deobfWasRemoved = m_classesByDeobf.remove(classMapping.getDeobfName()) != null;
70 assert (deobfWasRemoved);
71 }
72 }
73
74 public ClassMapping getClassByObf(ClassEntry entry) {
75 return getClassByObf(entry.getName());
76 }
77
78 public ClassMapping getClassByObf(String obfName) {
79 return m_classesByObf.get(obfName);
80 }
81
82 public ClassMapping getClassByDeobf(ClassEntry entry) {
83 return getClassByDeobf(entry.getName());
84 }
85
86 public ClassMapping getClassByDeobf(String deobfName) {
87 return m_classesByDeobf.get(deobfName);
88 }
89
90 public void setClassDeobfName(ClassMapping classMapping, String deobfName) {
91 if (classMapping.getDeobfName() != null) {
92 boolean wasRemoved = m_classesByDeobf.remove(classMapping.getDeobfName()) != null;
93 assert (wasRemoved);
94 }
95 classMapping.setDeobfName(deobfName);
96 if (deobfName != null) {
97 boolean wasAdded = m_classesByDeobf.put(deobfName, classMapping) == null;
98 assert (wasAdded);
99 }
100 }
101
102 public Translator getTranslator(TranslationDirection direction, TranslationIndex index) {
103 switch (direction) {
104 case Deobfuscating:
105
106 return new Translator(direction, m_classesByObf, index);
107
108 case Obfuscating:
109
110 // fill in the missing deobf class entries with obf entries
111 Map<String, ClassMapping> classes = Maps.newHashMap();
112 for (ClassMapping classMapping : classes()) {
113 if (classMapping.getDeobfName() != null) {
114 classes.put(classMapping.getDeobfName(), classMapping);
115 } else {
116 classes.put(classMapping.getObfFullName(), classMapping);
117 }
118 }
119
120 // translate the translation index
121 // NOTE: this isn't actually recursive
122 TranslationIndex deobfIndex = new TranslationIndex(index, getTranslator(TranslationDirection.Deobfuscating, index));
123
124 return new Translator(direction, classes, deobfIndex);
125
126 default:
127 throw new Error("Invalid translation direction!");
128 }
129 }
130
131 @Override
132 public String toString() {
133 StringBuilder buf = new StringBuilder();
134 for (ClassMapping classMapping : m_classesByObf.values()) {
135 buf.append(classMapping.toString());
136 buf.append("\n");
137 }
138 return buf.toString();
139 }
140
141 public void renameObfClass(String oldObfName, String newObfName) {
142 new ArrayList<>(classes()).stream().filter(classMapping -> classMapping.renameObfClass(oldObfName, newObfName)).forEach(classMapping -> {
143 boolean wasRemoved = m_classesByObf.remove(oldObfName) != null;
144 assert (wasRemoved);
145 boolean wasAdded = m_classesByObf.put(newObfName, classMapping) == null;
146 assert (wasAdded);
147 });
148 }
149
150 public Set<String> getAllObfClassNames() {
151 final Set<String> classNames = Sets.newHashSet();
152 for (ClassMapping classMapping : classes()) {
153
154 // add the class name
155 classNames.add(classMapping.getObfFullName());
156
157 // add classes from method signatures
158 for (MethodMapping methodMapping : classMapping.methods()) {
159 for (Type type : methodMapping.getObfSignature().types()) {
160 if (type.hasClass()) {
161 classNames.add(type.getClassEntry().getClassName());
162 }
163 }
164 }
165 }
166 return classNames;
167 }
168
169 public boolean containsDeobfClass(String deobfName) {
170 return m_classesByDeobf.containsKey(deobfName);
171 }
172
173 public boolean containsDeobfField(ClassEntry obfClassEntry, String deobfName, Type obfType) {
174 ClassMapping classMapping = m_classesByObf.get(obfClassEntry.getName());
175 return classMapping != null && classMapping.containsDeobfField(deobfName, obfType);
176 }
177
178 public boolean containsDeobfMethod(ClassEntry obfClassEntry, String deobfName, Signature deobfSignature) {
179 ClassMapping classMapping = m_classesByObf.get(obfClassEntry.getName());
180 return classMapping != null && classMapping.containsDeobfMethod(deobfName, deobfSignature);
181 }
182
183 public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) {
184 ClassMapping classMapping = m_classesByObf.get(obfBehaviorEntry.getClassName());
185 return classMapping != null && classMapping.containsArgument(obfBehaviorEntry, name);
186 }
187
188 public List<ClassMapping> getClassMappingChain(ClassEntry obfClass) {
189 List<ClassMapping> mappingChain = Lists.newArrayList();
190 ClassMapping classMapping = null;
191 for (ClassEntry obfClassEntry : obfClass.getClassChain()) {
192 if (mappingChain.isEmpty()) {
193 classMapping = m_classesByObf.get(obfClassEntry.getName());
194 } else if (classMapping != null) {
195 classMapping = classMapping.getInnerClassByObfSimple(obfClassEntry.getInnermostClassName());
196 }
197 mappingChain.add(classMapping);
198 }
199 return mappingChain;
200 }
201}