diff options
| author | 2015-02-08 21:29:25 -0500 | |
|---|---|---|
| committer | 2015-02-08 21:29:25 -0500 | |
| commit | ed9b5cdfc648e86fd463bfa8d86b94c41671e14c (patch) | |
| tree | 2619bbc7e04dfa3b82f8dfd3b1d31f529766cd4b /src/cuchaz/enigma/mapping/ClassMapping.java | |
| download | enigma-fork-ed9b5cdfc648e86fd463bfa8d86b94c41671e14c.tar.gz enigma-fork-ed9b5cdfc648e86fd463bfa8d86b94c41671e14c.tar.xz enigma-fork-ed9b5cdfc648e86fd463bfa8d86b94c41671e14c.zip | |
switch all classes to new signature/type system
Diffstat (limited to 'src/cuchaz/enigma/mapping/ClassMapping.java')
| -rw-r--r-- | src/cuchaz/enigma/mapping/ClassMapping.java | 405 |
1 files changed, 405 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..e2c3d56 --- /dev/null +++ b/src/cuchaz/enigma/mapping/ClassMapping.java | |||
| @@ -0,0 +1,405 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2014 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Public License v3.0 | ||
| 5 | * which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/gpl.html | ||
| 7 | * | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.mapping; | ||
| 12 | |||
| 13 | import java.io.Serializable; | ||
| 14 | import java.util.ArrayList; | ||
| 15 | import java.util.Map; | ||
| 16 | |||
| 17 | import com.google.common.collect.Maps; | ||
| 18 | |||
| 19 | public class ClassMapping implements Serializable, Comparable<ClassMapping> { | ||
| 20 | |||
| 21 | private static final long serialVersionUID = -5148491146902340107L; | ||
| 22 | |||
| 23 | private String m_obfName; | ||
| 24 | private String m_deobfName; | ||
| 25 | private Map<String,ClassMapping> m_innerClassesByObf; | ||
| 26 | private Map<String,ClassMapping> m_innerClassesByDeobf; | ||
| 27 | private Map<String,FieldMapping> m_fieldsByObf; | ||
| 28 | private Map<String,FieldMapping> m_fieldsByDeobf; | ||
| 29 | private Map<String,MethodMapping> m_methodsByObf; | ||
| 30 | private Map<String,MethodMapping> m_methodsByDeobf; | ||
| 31 | |||
| 32 | public ClassMapping(String obfName) { | ||
| 33 | this(obfName, null); | ||
| 34 | } | ||
| 35 | |||
| 36 | public ClassMapping(String obfName, String deobfName) { | ||
| 37 | m_obfName = obfName; | ||
| 38 | m_deobfName = NameValidator.validateClassName(deobfName, false); | ||
| 39 | m_innerClassesByObf = Maps.newHashMap(); | ||
| 40 | m_innerClassesByDeobf = Maps.newHashMap(); | ||
| 41 | m_fieldsByObf = Maps.newHashMap(); | ||
| 42 | m_fieldsByDeobf = Maps.newHashMap(); | ||
| 43 | m_methodsByObf = Maps.newHashMap(); | ||
| 44 | m_methodsByDeobf = Maps.newHashMap(); | ||
| 45 | } | ||
| 46 | |||
| 47 | public String getObfName() { | ||
| 48 | return m_obfName; | ||
| 49 | } | ||
| 50 | |||
| 51 | public String getDeobfName() { | ||
| 52 | return m_deobfName; | ||
| 53 | } | ||
| 54 | |||
| 55 | public void setDeobfName(String val) { | ||
| 56 | m_deobfName = NameValidator.validateClassName(val, false); | ||
| 57 | } | ||
| 58 | |||
| 59 | //// INNER CLASSES //////// | ||
| 60 | |||
| 61 | public Iterable<ClassMapping> innerClasses() { | ||
| 62 | assert (m_innerClassesByObf.size() >= m_innerClassesByDeobf.size()); | ||
| 63 | return m_innerClassesByObf.values(); | ||
| 64 | } | ||
| 65 | |||
| 66 | public void addInnerClassMapping(ClassMapping classMapping) { | ||
| 67 | assert (isSimpleClassName(classMapping.getObfName())); | ||
| 68 | boolean obfWasAdded = m_innerClassesByObf.put(classMapping.getObfName(), classMapping) == null; | ||
| 69 | assert (obfWasAdded); | ||
| 70 | if (classMapping.getDeobfName() != null) { | ||
| 71 | assert (isSimpleClassName(classMapping.getDeobfName())); | ||
| 72 | boolean deobfWasAdded = m_innerClassesByDeobf.put(classMapping.getDeobfName(), classMapping) == null; | ||
| 73 | assert (deobfWasAdded); | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | public void removeInnerClassMapping(ClassMapping classMapping) { | ||
| 78 | boolean obfWasRemoved = m_innerClassesByObf.remove(classMapping.getObfName()) != null; | ||
| 79 | assert (obfWasRemoved); | ||
| 80 | if (classMapping.getDeobfName() != null) { | ||
| 81 | boolean deobfWasRemoved = m_innerClassesByDeobf.remove(classMapping.getDeobfName()) != null; | ||
| 82 | assert (deobfWasRemoved); | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | public ClassMapping getOrCreateInnerClass(String obfName) { | ||
| 87 | assert (isSimpleClassName(obfName)); | ||
| 88 | ClassMapping classMapping = m_innerClassesByObf.get(obfName); | ||
| 89 | if (classMapping == null) { | ||
| 90 | classMapping = new ClassMapping(obfName); | ||
| 91 | boolean wasAdded = m_innerClassesByObf.put(obfName, classMapping) == null; | ||
| 92 | assert (wasAdded); | ||
| 93 | } | ||
| 94 | return classMapping; | ||
| 95 | } | ||
| 96 | |||
| 97 | public ClassMapping getInnerClassByObf(String obfName) { | ||
| 98 | assert (isSimpleClassName(obfName)); | ||
| 99 | return m_innerClassesByObf.get(obfName); | ||
| 100 | } | ||
| 101 | |||
| 102 | public ClassMapping getInnerClassByDeobf(String deobfName) { | ||
| 103 | assert (isSimpleClassName(deobfName)); | ||
| 104 | return m_innerClassesByDeobf.get(deobfName); | ||
| 105 | } | ||
| 106 | |||
| 107 | public ClassMapping getInnerClassByDeobfThenObf(String name) { | ||
| 108 | ClassMapping classMapping = getInnerClassByDeobf(name); | ||
| 109 | if (classMapping == null) { | ||
| 110 | classMapping = getInnerClassByObf(name); | ||
| 111 | } | ||
| 112 | return classMapping; | ||
| 113 | } | ||
| 114 | |||
| 115 | public String getObfInnerClassName(String deobfName) { | ||
| 116 | assert (isSimpleClassName(deobfName)); | ||
| 117 | ClassMapping classMapping = m_innerClassesByDeobf.get(deobfName); | ||
| 118 | if (classMapping != null) { | ||
| 119 | return classMapping.getObfName(); | ||
| 120 | } | ||
| 121 | return null; | ||
| 122 | } | ||
| 123 | |||
| 124 | public String getDeobfInnerClassName(String obfName) { | ||
| 125 | assert (isSimpleClassName(obfName)); | ||
| 126 | ClassMapping classMapping = m_innerClassesByObf.get(obfName); | ||
| 127 | if (classMapping != null) { | ||
| 128 | return classMapping.getDeobfName(); | ||
| 129 | } | ||
| 130 | return null; | ||
| 131 | } | ||
| 132 | |||
| 133 | public void setInnerClassName(String obfName, String deobfName) { | ||
| 134 | assert (isSimpleClassName(obfName)); | ||
| 135 | ClassMapping classMapping = getOrCreateInnerClass(obfName); | ||
| 136 | if (classMapping.getDeobfName() != null) { | ||
| 137 | boolean wasRemoved = m_innerClassesByDeobf.remove(classMapping.getDeobfName()) != null; | ||
| 138 | assert (wasRemoved); | ||
| 139 | } | ||
| 140 | classMapping.setDeobfName(deobfName); | ||
| 141 | if (deobfName != null) { | ||
| 142 | assert (isSimpleClassName(deobfName)); | ||
| 143 | boolean wasAdded = m_innerClassesByDeobf.put(deobfName, classMapping) == null; | ||
| 144 | assert (wasAdded); | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | //// FIELDS //////// | ||
| 149 | |||
| 150 | public Iterable<FieldMapping> fields() { | ||
| 151 | assert (m_fieldsByObf.size() == m_fieldsByDeobf.size()); | ||
| 152 | return m_fieldsByObf.values(); | ||
| 153 | } | ||
| 154 | |||
| 155 | public boolean containsObfField(String obfName) { | ||
| 156 | return m_fieldsByObf.containsKey(obfName); | ||
| 157 | } | ||
| 158 | |||
| 159 | public boolean containsDeobfField(String deobfName) { | ||
| 160 | return m_fieldsByDeobf.containsKey(deobfName); | ||
| 161 | } | ||
| 162 | |||
| 163 | public void addFieldMapping(FieldMapping fieldMapping) { | ||
| 164 | if (m_fieldsByObf.containsKey(fieldMapping.getObfName())) { | ||
| 165 | throw new Error("Already have mapping for " + m_obfName + "." + fieldMapping.getObfName()); | ||
| 166 | } | ||
| 167 | if (m_fieldsByDeobf.containsKey(fieldMapping.getDeobfName())) { | ||
| 168 | throw new Error("Already have mapping for " + m_deobfName + "." + fieldMapping.getDeobfName()); | ||
| 169 | } | ||
| 170 | boolean obfWasAdded = m_fieldsByObf.put(fieldMapping.getObfName(), fieldMapping) == null; | ||
| 171 | assert (obfWasAdded); | ||
| 172 | boolean deobfWasAdded = m_fieldsByDeobf.put(fieldMapping.getDeobfName(), fieldMapping) == null; | ||
| 173 | assert (deobfWasAdded); | ||
| 174 | assert (m_fieldsByObf.size() == m_fieldsByDeobf.size()); | ||
| 175 | } | ||
| 176 | |||
| 177 | public void removeFieldMapping(FieldMapping fieldMapping) { | ||
| 178 | boolean obfWasRemoved = m_fieldsByObf.remove(fieldMapping.getObfName()) != null; | ||
| 179 | assert (obfWasRemoved); | ||
| 180 | if (fieldMapping.getDeobfName() != null) { | ||
| 181 | boolean deobfWasRemoved = m_fieldsByDeobf.remove(fieldMapping.getDeobfName()) != null; | ||
| 182 | assert (deobfWasRemoved); | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | public FieldMapping getFieldByObf(String obfName) { | ||
| 187 | return m_fieldsByObf.get(obfName); | ||
| 188 | } | ||
| 189 | |||
| 190 | public FieldMapping getFieldByDeobf(String deobfName) { | ||
| 191 | return m_fieldsByDeobf.get(deobfName); | ||
| 192 | } | ||
| 193 | |||
| 194 | public String getObfFieldName(String deobfName) { | ||
| 195 | FieldMapping fieldMapping = m_fieldsByDeobf.get(deobfName); | ||
| 196 | if (fieldMapping != null) { | ||
| 197 | return fieldMapping.getObfName(); | ||
| 198 | } | ||
| 199 | return null; | ||
| 200 | } | ||
| 201 | |||
| 202 | public String getDeobfFieldName(String obfName) { | ||
| 203 | FieldMapping fieldMapping = m_fieldsByObf.get(obfName); | ||
| 204 | if (fieldMapping != null) { | ||
| 205 | return fieldMapping.getDeobfName(); | ||
| 206 | } | ||
| 207 | return null; | ||
| 208 | } | ||
| 209 | |||
| 210 | public void setFieldName(String obfName, String deobfName) { | ||
| 211 | FieldMapping fieldMapping = m_fieldsByObf.get(obfName); | ||
| 212 | if (fieldMapping == null) { | ||
| 213 | fieldMapping = new FieldMapping(obfName, deobfName); | ||
| 214 | boolean obfWasAdded = m_fieldsByObf.put(obfName, fieldMapping) == null; | ||
| 215 | assert (obfWasAdded); | ||
| 216 | } else { | ||
| 217 | boolean wasRemoved = m_fieldsByDeobf.remove(fieldMapping.getDeobfName()) != null; | ||
| 218 | assert (wasRemoved); | ||
| 219 | } | ||
| 220 | fieldMapping.setDeobfName(deobfName); | ||
| 221 | if (deobfName != null) { | ||
| 222 | boolean wasAdded = m_fieldsByDeobf.put(deobfName, fieldMapping) == null; | ||
| 223 | assert (wasAdded); | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | //// METHODS //////// | ||
| 228 | |||
| 229 | public Iterable<MethodMapping> methods() { | ||
| 230 | assert (m_methodsByObf.size() >= m_methodsByDeobf.size()); | ||
| 231 | return m_methodsByObf.values(); | ||
| 232 | } | ||
| 233 | |||
| 234 | public boolean containsObfMethod(String obfName, Signature obfSignature) { | ||
| 235 | return m_methodsByObf.containsKey(getMethodKey(obfName, obfSignature)); | ||
| 236 | } | ||
| 237 | |||
| 238 | public boolean containsDeobfMethod(String deobfName, Signature deobfSignature) { | ||
| 239 | return m_methodsByDeobf.containsKey(getMethodKey(deobfName, deobfSignature)); | ||
| 240 | } | ||
| 241 | |||
| 242 | public void addMethodMapping(MethodMapping methodMapping) { | ||
| 243 | String obfKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature()); | ||
| 244 | if (m_methodsByObf.containsKey(obfKey)) { | ||
| 245 | throw new Error("Already have mapping for " + m_obfName + "." + obfKey); | ||
| 246 | } | ||
| 247 | boolean wasAdded = m_methodsByObf.put(obfKey, methodMapping) == null; | ||
| 248 | assert (wasAdded); | ||
| 249 | if (methodMapping.getDeobfName() != null) { | ||
| 250 | String deobfKey = getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature()); | ||
| 251 | if (m_methodsByDeobf.containsKey(deobfKey)) { | ||
| 252 | throw new Error("Already have mapping for " + m_deobfName + "." + deobfKey); | ||
| 253 | } | ||
| 254 | boolean deobfWasAdded = m_methodsByDeobf.put(deobfKey, methodMapping) == null; | ||
| 255 | assert (deobfWasAdded); | ||
| 256 | } | ||
| 257 | assert (m_methodsByObf.size() >= m_methodsByDeobf.size()); | ||
| 258 | } | ||
| 259 | |||
| 260 | public void removeMethodMapping(MethodMapping methodMapping) { | ||
| 261 | boolean obfWasRemoved = m_methodsByObf.remove(getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature())) != null; | ||
| 262 | assert (obfWasRemoved); | ||
| 263 | if (methodMapping.getDeobfName() != null) { | ||
| 264 | boolean deobfWasRemoved = m_methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature())) != null; | ||
| 265 | assert (deobfWasRemoved); | ||
| 266 | } | ||
| 267 | } | ||
| 268 | |||
| 269 | public MethodMapping getMethodByObf(String obfName, Signature signature) { | ||
| 270 | return m_methodsByObf.get(getMethodKey(obfName, signature)); | ||
| 271 | } | ||
| 272 | |||
| 273 | public MethodMapping getMethodByDeobf(String deobfName, Signature signature) { | ||
| 274 | return m_methodsByDeobf.get(getMethodKey(deobfName, signature)); | ||
| 275 | } | ||
| 276 | |||
| 277 | private String getMethodKey(String name, Signature signature) { | ||
| 278 | if (name == null) { | ||
| 279 | throw new IllegalArgumentException("name cannot be null!"); | ||
| 280 | } | ||
| 281 | if (signature == null) { | ||
| 282 | throw new IllegalArgumentException("signature cannot be null!"); | ||
| 283 | } | ||
| 284 | return name + signature; | ||
| 285 | } | ||
| 286 | |||
| 287 | public void setMethodName(String obfName, Signature obfSignature, String deobfName) { | ||
| 288 | MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfName, obfSignature)); | ||
| 289 | if (methodMapping == null) { | ||
| 290 | methodMapping = createMethodMapping(obfName, obfSignature); | ||
| 291 | } else if (methodMapping.getDeobfName() != null) { | ||
| 292 | boolean wasRemoved = m_methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature())) != null; | ||
| 293 | assert (wasRemoved); | ||
| 294 | } | ||
| 295 | methodMapping.setDeobfName(deobfName); | ||
| 296 | if (deobfName != null) { | ||
| 297 | boolean wasAdded = m_methodsByDeobf.put(getMethodKey(deobfName, obfSignature), methodMapping) == null; | ||
| 298 | assert (wasAdded); | ||
| 299 | } | ||
| 300 | } | ||
| 301 | |||
| 302 | //// ARGUMENTS //////// | ||
| 303 | |||
| 304 | public void setArgumentName(String obfMethodName, Signature obfMethodSignature, int argumentIndex, String argumentName) { | ||
| 305 | MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfMethodName, obfMethodSignature)); | ||
| 306 | if (methodMapping == null) { | ||
| 307 | methodMapping = createMethodMapping(obfMethodName, obfMethodSignature); | ||
| 308 | } | ||
| 309 | methodMapping.setArgumentName(argumentIndex, argumentName); | ||
| 310 | } | ||
| 311 | |||
| 312 | public void removeArgumentName(String obfMethodName, Signature obfMethodSignature, int argumentIndex) { | ||
| 313 | m_methodsByObf.get(getMethodKey(obfMethodName, obfMethodSignature)).removeArgumentName(argumentIndex); | ||
| 314 | } | ||
| 315 | |||
| 316 | private MethodMapping createMethodMapping(String obfName, Signature obfSignature) { | ||
| 317 | MethodMapping methodMapping = new MethodMapping(obfName, obfSignature); | ||
| 318 | boolean wasAdded = m_methodsByObf.put(getMethodKey(obfName, obfSignature), methodMapping) == null; | ||
| 319 | assert (wasAdded); | ||
| 320 | return methodMapping; | ||
| 321 | } | ||
| 322 | |||
| 323 | @Override | ||
| 324 | public String toString() { | ||
| 325 | StringBuilder buf = new StringBuilder(); | ||
| 326 | buf.append(m_obfName); | ||
| 327 | buf.append(" <-> "); | ||
| 328 | buf.append(m_deobfName); | ||
| 329 | buf.append("\n"); | ||
| 330 | buf.append("Fields:\n"); | ||
| 331 | for (FieldMapping fieldMapping : fields()) { | ||
| 332 | buf.append("\t"); | ||
| 333 | buf.append(fieldMapping.getObfName()); | ||
| 334 | buf.append(" <-> "); | ||
| 335 | buf.append(fieldMapping.getDeobfName()); | ||
| 336 | buf.append("\n"); | ||
| 337 | } | ||
| 338 | buf.append("Methods:\n"); | ||
| 339 | for (MethodMapping methodMapping : m_methodsByObf.values()) { | ||
| 340 | buf.append(methodMapping.toString()); | ||
| 341 | buf.append("\n"); | ||
| 342 | } | ||
| 343 | buf.append("Inner Classes:\n"); | ||
| 344 | for (ClassMapping classMapping : m_innerClassesByObf.values()) { | ||
| 345 | buf.append("\t"); | ||
| 346 | buf.append(classMapping.getObfName()); | ||
| 347 | buf.append(" <-> "); | ||
| 348 | buf.append(classMapping.getDeobfName()); | ||
| 349 | buf.append("\n"); | ||
| 350 | } | ||
| 351 | return buf.toString(); | ||
| 352 | } | ||
| 353 | |||
| 354 | @Override | ||
| 355 | public int compareTo(ClassMapping other) { | ||
| 356 | // sort by a, b, c, ... aa, ab, etc | ||
| 357 | if (m_obfName.length() != other.m_obfName.length()) { | ||
| 358 | return m_obfName.length() - other.m_obfName.length(); | ||
| 359 | } | ||
| 360 | return m_obfName.compareTo(other.m_obfName); | ||
| 361 | } | ||
| 362 | |||
| 363 | public boolean renameObfClass(String oldObfClassName, String newObfClassName) { | ||
| 364 | |||
| 365 | // rename inner classes | ||
| 366 | for (ClassMapping innerClassMapping : new ArrayList<ClassMapping>(m_innerClassesByObf.values())) { | ||
| 367 | if (innerClassMapping.renameObfClass(oldObfClassName, newObfClassName)) { | ||
| 368 | boolean wasRemoved = m_innerClassesByObf.remove(oldObfClassName) != null; | ||
| 369 | assert (wasRemoved); | ||
| 370 | boolean wasAdded = m_innerClassesByObf.put(newObfClassName, innerClassMapping) == null; | ||
| 371 | assert (wasAdded); | ||
| 372 | } | ||
| 373 | } | ||
| 374 | |||
| 375 | // rename method signatures | ||
| 376 | for (MethodMapping methodMapping : new ArrayList<MethodMapping>(m_methodsByObf.values())) { | ||
| 377 | String oldMethodKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature()); | ||
| 378 | if (methodMapping.renameObfClass(oldObfClassName, newObfClassName)) { | ||
| 379 | boolean wasRemoved = m_methodsByObf.remove(oldMethodKey) != null; | ||
| 380 | assert (wasRemoved); | ||
| 381 | boolean wasAdded = m_methodsByObf.put(getMethodKey(methodMapping.getObfName(), methodMapping.getObfSignature()), methodMapping) == null; | ||
| 382 | assert (wasAdded); | ||
| 383 | } | ||
| 384 | } | ||
| 385 | |||
| 386 | if (m_obfName.equals(oldObfClassName)) { | ||
| 387 | // rename this class | ||
| 388 | m_obfName = newObfClassName; | ||
| 389 | return true; | ||
| 390 | } | ||
| 391 | return false; | ||
| 392 | } | ||
| 393 | |||
| 394 | public boolean containsArgument(BehaviorEntry obfBehaviorEntry, String name) { | ||
| 395 | MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfBehaviorEntry.getName(), obfBehaviorEntry.getSignature())); | ||
| 396 | if (methodMapping != null) { | ||
| 397 | return methodMapping.containsArgument(name); | ||
| 398 | } | ||
| 399 | return false; | ||
| 400 | } | ||
| 401 | |||
| 402 | public static boolean isSimpleClassName(String name) { | ||
| 403 | return name.indexOf('/') < 0 && name.indexOf('$') < 0; | ||
| 404 | } | ||
| 405 | } | ||