diff options
Diffstat (limited to 'src/main/java/cuchaz/enigma/mapping/ClassMapping.java')
| -rw-r--r-- | src/main/java/cuchaz/enigma/mapping/ClassMapping.java | 627 |
1 files changed, 0 insertions, 627 deletions
diff --git a/src/main/java/cuchaz/enigma/mapping/ClassMapping.java b/src/main/java/cuchaz/enigma/mapping/ClassMapping.java deleted file mode 100644 index 9c193ef..0000000 --- a/src/main/java/cuchaz/enigma/mapping/ClassMapping.java +++ /dev/null | |||
| @@ -1,627 +0,0 @@ | |||
| 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 | ******************************************************************************/ | ||
| 11 | |||
| 12 | package cuchaz.enigma.mapping; | ||
| 13 | |||
| 14 | import com.google.common.collect.Maps; | ||
| 15 | import cuchaz.enigma.mapping.entry.ClassEntry; | ||
| 16 | import cuchaz.enigma.mapping.entry.FieldEntry; | ||
| 17 | import cuchaz.enigma.mapping.entry.MethodEntry; | ||
| 18 | import cuchaz.enigma.throwables.MappingConflict; | ||
| 19 | |||
| 20 | import java.util.ArrayList; | ||
| 21 | import java.util.Map; | ||
| 22 | |||
| 23 | // FIXME: Enigma doesn't support inner classes of inner class????! | ||
| 24 | public class ClassMapping implements Comparable<ClassMapping> { | ||
| 25 | |||
| 26 | private String obfFullName; | ||
| 27 | private String obfSimpleName; | ||
| 28 | private String deobfName; | ||
| 29 | private String deobfFullName; | ||
| 30 | private String previousDeobfName; | ||
| 31 | private Map<String, ClassMapping> innerClassesByObfSimple; | ||
| 32 | private Map<String, ClassMapping> innerClassesByObfFull; | ||
| 33 | private Map<String, ClassMapping> innerClassesByDeobf; | ||
| 34 | private Map<String, FieldMapping> fieldsByObf; | ||
| 35 | private Map<String, FieldMapping> fieldsByDeobf; | ||
| 36 | private Map<String, MethodMapping> methodsByObf; | ||
| 37 | private Map<String, MethodMapping> methodsByDeobf; | ||
| 38 | private boolean isDirty; | ||
| 39 | private Mappings.EntryModifier modifier; | ||
| 40 | |||
| 41 | public ClassMapping(String obfFullName) { | ||
| 42 | this(obfFullName, null, Mappings.EntryModifier.UNCHANGED); | ||
| 43 | } | ||
| 44 | |||
| 45 | public ClassMapping(String obfFullName, String deobfName) { | ||
| 46 | this(obfFullName, deobfName, Mappings.EntryModifier.UNCHANGED); | ||
| 47 | } | ||
| 48 | |||
| 49 | public ClassMapping(String obfFullName, String deobfName, Mappings.EntryModifier modifier) { | ||
| 50 | this.obfFullName = obfFullName; | ||
| 51 | ClassEntry classEntry = new ClassEntry(obfFullName); | ||
| 52 | obfSimpleName = classEntry.isInnerClass() ? classEntry.getInnermostClassName() : classEntry.getSimpleName(); | ||
| 53 | previousDeobfName = null; | ||
| 54 | this.deobfName = NameValidator.validateClassName(deobfName, false); | ||
| 55 | innerClassesByObfSimple = Maps.newHashMap(); | ||
| 56 | innerClassesByObfFull = Maps.newHashMap(); | ||
| 57 | innerClassesByDeobf = Maps.newHashMap(); | ||
| 58 | fieldsByObf = Maps.newHashMap(); | ||
| 59 | fieldsByDeobf = Maps.newHashMap(); | ||
| 60 | methodsByObf = Maps.newHashMap(); | ||
| 61 | methodsByDeobf = Maps.newHashMap(); | ||
| 62 | isDirty = true; | ||
| 63 | this.modifier = modifier; | ||
| 64 | } | ||
| 65 | |||
| 66 | public static boolean isSimpleClassName(String name) { | ||
| 67 | return name.indexOf('/') < 0 && name.indexOf('$') < 0; | ||
| 68 | } | ||
| 69 | |||
| 70 | public String getObfFullName() { | ||
| 71 | return obfFullName; | ||
| 72 | } | ||
| 73 | |||
| 74 | public String getObfSimpleName() { | ||
| 75 | return obfSimpleName; | ||
| 76 | } | ||
| 77 | |||
| 78 | public String getPreviousDeobfName() { | ||
| 79 | return previousDeobfName; | ||
| 80 | } | ||
| 81 | |||
| 82 | public String getDeobfName() { | ||
| 83 | return deobfName; | ||
| 84 | } | ||
| 85 | |||
| 86 | public String getTranslatedName(TranslationDirection direction) { | ||
| 87 | return direction.choose(deobfName, obfFullName); | ||
| 88 | } | ||
| 89 | |||
| 90 | //// INNER CLASSES //////// | ||
| 91 | |||
| 92 | public void setDeobfName(String val) { | ||
| 93 | previousDeobfName = deobfName; | ||
| 94 | deobfName = NameValidator.validateClassName(val, false); | ||
| 95 | this.isDirty = true; | ||
| 96 | } | ||
| 97 | |||
| 98 | public Iterable<ClassMapping> innerClasses() { | ||
| 99 | assert (innerClassesByObfSimple.size() >= innerClassesByDeobf.size()); | ||
| 100 | return innerClassesByObfSimple.values(); | ||
| 101 | } | ||
| 102 | |||
| 103 | public void addInnerClassMapping(ClassMapping classMapping) throws MappingConflict { | ||
| 104 | // FIXME: dirty hack, that can get into issues, but it's a temp fix! | ||
| 105 | if (this.innerClassesByObfFull.containsKey(classMapping.getObfSimpleName())) { | ||
| 106 | throw new MappingConflict("classes", classMapping.getObfSimpleName(), this.innerClassesByObfSimple.get(classMapping.getObfSimpleName()).getObfSimpleName()); | ||
| 107 | } | ||
| 108 | innerClassesByObfFull.put(classMapping.getObfFullName(), classMapping); | ||
| 109 | innerClassesByObfSimple.put(classMapping.getObfSimpleName(), classMapping); | ||
| 110 | |||
| 111 | if (classMapping.getDeobfName() != null) { | ||
| 112 | if (this.innerClassesByDeobf.containsKey(classMapping.getDeobfName())) { | ||
| 113 | throw new MappingConflict("classes", classMapping.getDeobfName(), this.innerClassesByDeobf.get(classMapping.getDeobfName()).getDeobfName()); | ||
| 114 | } | ||
| 115 | innerClassesByDeobf.put(classMapping.getDeobfName(), classMapping); | ||
| 116 | } | ||
| 117 | this.isDirty = true; | ||
| 118 | } | ||
| 119 | |||
| 120 | public void removeInnerClassMapping(ClassMapping classMapping) { | ||
| 121 | innerClassesByObfFull.remove(classMapping.getObfFullName()); | ||
| 122 | boolean obfWasRemoved = innerClassesByObfSimple.remove(classMapping.getObfSimpleName()) != null; | ||
| 123 | assert (obfWasRemoved); | ||
| 124 | if (classMapping.getDeobfName() != null) { | ||
| 125 | boolean deobfWasRemoved = innerClassesByDeobf.remove(classMapping.getDeobfName()) != null; | ||
| 126 | assert (deobfWasRemoved); | ||
| 127 | } | ||
| 128 | this.isDirty = true; | ||
| 129 | } | ||
| 130 | |||
| 131 | public ClassMapping getOrCreateInnerClass(ClassEntry obfInnerClass) { | ||
| 132 | ClassMapping classMapping = innerClassesByObfSimple.get(obfInnerClass.getInnermostClassName()); | ||
| 133 | if (classMapping == null) { | ||
| 134 | classMapping = new ClassMapping(obfInnerClass.getName()); | ||
| 135 | innerClassesByObfFull.put(classMapping.getObfFullName(), classMapping); | ||
| 136 | boolean wasAdded = innerClassesByObfSimple.put(classMapping.getObfSimpleName(), classMapping) == null; | ||
| 137 | assert (wasAdded); | ||
| 138 | this.isDirty = true; | ||
| 139 | } | ||
| 140 | return classMapping; | ||
| 141 | } | ||
| 142 | |||
| 143 | public ClassMapping getInnerClassByObfSimple(String obfSimpleName) { | ||
| 144 | assert (isSimpleClassName(obfSimpleName)); | ||
| 145 | return innerClassesByObfSimple.get(obfSimpleName); | ||
| 146 | } | ||
| 147 | |||
| 148 | public ClassMapping getInnerClassByDeobf(String deobfName) { | ||
| 149 | assert (isSimpleClassName(deobfName)); | ||
| 150 | return innerClassesByDeobf.get(deobfName); | ||
| 151 | } | ||
| 152 | |||
| 153 | public ClassMapping getInnerClassByDeobfThenObfSimple(String name) { | ||
| 154 | ClassMapping classMapping = getInnerClassByDeobf(name); | ||
| 155 | if (classMapping == null) { | ||
| 156 | classMapping = getInnerClassByObfSimple(name); | ||
| 157 | } | ||
| 158 | return classMapping; | ||
| 159 | } | ||
| 160 | |||
| 161 | public String getDeobfInnerClassName(String obfSimpleName) { | ||
| 162 | assert (isSimpleClassName(obfSimpleName)); | ||
| 163 | ClassMapping classMapping = innerClassesByObfSimple.get(obfSimpleName); | ||
| 164 | if (classMapping != null) { | ||
| 165 | return classMapping.getDeobfName(); | ||
| 166 | } | ||
| 167 | return null; | ||
| 168 | } | ||
| 169 | |||
| 170 | public void setInnerClassName(ClassEntry obfInnerClass, String deobfName) { | ||
| 171 | ClassMapping classMapping = getOrCreateInnerClass(obfInnerClass); | ||
| 172 | if (classMapping.getDeobfName() != null) { | ||
| 173 | boolean wasRemoved = innerClassesByDeobf.remove(classMapping.getDeobfName()) != null; | ||
| 174 | assert (wasRemoved); | ||
| 175 | } | ||
| 176 | classMapping.setDeobfName(deobfName); | ||
| 177 | if (deobfName != null) { | ||
| 178 | assert (isSimpleClassName(deobfName)); | ||
| 179 | boolean wasAdded = innerClassesByDeobf.put(deobfName, classMapping) == null; | ||
| 180 | assert (wasAdded); | ||
| 181 | } | ||
| 182 | this.isDirty = true; | ||
| 183 | } | ||
| 184 | |||
| 185 | public boolean hasInnerClassByObfSimple(String obfSimpleName) { | ||
| 186 | return innerClassesByObfSimple.containsKey(obfSimpleName); | ||
| 187 | } | ||
| 188 | |||
| 189 | //// FIELDS //////// | ||
| 190 | |||
| 191 | public boolean hasInnerClassByDeobf(String deobfName) { | ||
| 192 | return innerClassesByDeobf.containsKey(deobfName); | ||
| 193 | } | ||
| 194 | |||
| 195 | public Iterable<FieldMapping> fields() { | ||
| 196 | assert (fieldsByObf.size() == fieldsByDeobf.size()); | ||
| 197 | return fieldsByObf.values(); | ||
| 198 | } | ||
| 199 | |||
| 200 | public boolean containsObfField(String obfName, TypeDescriptor obfDesc) { | ||
| 201 | return fieldsByObf.containsKey(getFieldKey(obfName, obfDesc)); | ||
| 202 | } | ||
| 203 | |||
| 204 | public boolean containsDeobfField(String deobfName, TypeDescriptor deobfDesc) { | ||
| 205 | return fieldsByDeobf.containsKey(getFieldKey(deobfName, deobfDesc)); | ||
| 206 | } | ||
| 207 | |||
| 208 | public void addFieldMapping(FieldMapping fieldMapping) { | ||
| 209 | String obfKey = getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfDesc()); | ||
| 210 | if (fieldsByObf.containsKey(obfKey)) { | ||
| 211 | throw new Error("Already have mapping for " + obfFullName + "." + obfKey); | ||
| 212 | } | ||
| 213 | if (fieldMapping.getDeobfName() != null) { | ||
| 214 | String deobfKey = getFieldKey(fieldMapping.getDeobfName(), fieldMapping.getObfDesc()); | ||
| 215 | if (fieldsByDeobf.containsKey(deobfKey)) { | ||
| 216 | throw new Error("Already have mapping for " + deobfName + "." + deobfKey); | ||
| 217 | } | ||
| 218 | boolean deobfWasAdded = fieldsByDeobf.put(deobfKey, fieldMapping) == null; | ||
| 219 | assert (deobfWasAdded); | ||
| 220 | } | ||
| 221 | boolean obfWasAdded = fieldsByObf.put(obfKey, fieldMapping) == null; | ||
| 222 | assert (obfWasAdded); | ||
| 223 | this.isDirty = true; | ||
| 224 | } | ||
| 225 | |||
| 226 | public void removeFieldMapping(FieldMapping fieldMapping) { | ||
| 227 | boolean obfWasRemoved = fieldsByObf.remove(getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfDesc())) != null; | ||
| 228 | assert (obfWasRemoved); | ||
| 229 | if (fieldMapping.getDeobfName() != null) { | ||
| 230 | boolean deobfWasRemoved = fieldsByDeobf.remove(getFieldKey(fieldMapping.getDeobfName(), fieldMapping.getObfDesc())) != null; | ||
| 231 | assert (deobfWasRemoved); | ||
| 232 | } | ||
| 233 | this.isDirty = true; | ||
| 234 | } | ||
| 235 | |||
| 236 | public FieldMapping getFieldByObf(String obfName, TypeDescriptor obfDesc) { | ||
| 237 | return fieldsByObf.get(getFieldKey(obfName, obfDesc)); | ||
| 238 | } | ||
| 239 | |||
| 240 | public FieldMapping getFieldByObf(FieldEntry field) { | ||
| 241 | return getFieldByObf(field.getName(), field.getDesc()); | ||
| 242 | } | ||
| 243 | |||
| 244 | public FieldMapping getFieldByDeobf(String deobfName, TypeDescriptor obfDesc) { | ||
| 245 | return fieldsByDeobf.get(getFieldKey(deobfName, obfDesc)); | ||
| 246 | } | ||
| 247 | |||
| 248 | public String getObfFieldName(String deobfName, TypeDescriptor obfDesc) { | ||
| 249 | FieldMapping fieldMapping = fieldsByDeobf.get(getFieldKey(deobfName, obfDesc)); | ||
| 250 | if (fieldMapping != null) { | ||
| 251 | return fieldMapping.getObfName(); | ||
| 252 | } | ||
| 253 | return null; | ||
| 254 | } | ||
| 255 | |||
| 256 | public String getDeobfFieldName(String obfName, TypeDescriptor obfDesc) { | ||
| 257 | FieldMapping fieldMapping = fieldsByObf.get(getFieldKey(obfName, obfDesc)); | ||
| 258 | if (fieldMapping != null) { | ||
| 259 | return fieldMapping.getDeobfName(); | ||
| 260 | } | ||
| 261 | return null; | ||
| 262 | } | ||
| 263 | |||
| 264 | private String getFieldKey(String name, TypeDescriptor desc) { | ||
| 265 | if (name == null) { | ||
| 266 | throw new IllegalArgumentException("name cannot be null!"); | ||
| 267 | } | ||
| 268 | if (desc == null) { | ||
| 269 | throw new IllegalArgumentException("desc cannot be null!"); | ||
| 270 | } | ||
| 271 | return name + ":" + desc; | ||
| 272 | } | ||
| 273 | |||
| 274 | public void setFieldName(String obfName, TypeDescriptor obfDesc, String deobfName) { | ||
| 275 | assert (deobfName != null); | ||
| 276 | FieldMapping fieldMapping = fieldsByObf.get(getFieldKey(obfName, obfDesc)); | ||
| 277 | if (fieldMapping == null) { | ||
| 278 | fieldMapping = new FieldMapping(obfName, obfDesc, deobfName, Mappings.EntryModifier.UNCHANGED); | ||
| 279 | boolean obfWasAdded = fieldsByObf.put(getFieldKey(obfName, obfDesc), fieldMapping) == null; | ||
| 280 | assert (obfWasAdded); | ||
| 281 | } else { | ||
| 282 | boolean wasRemoved = fieldsByDeobf.remove(getFieldKey(fieldMapping.getDeobfName(), obfDesc)) != null; | ||
| 283 | assert (wasRemoved); | ||
| 284 | } | ||
| 285 | fieldMapping.setDeobfName(deobfName); | ||
| 286 | if (deobfName != null) { | ||
| 287 | boolean wasAdded = fieldsByDeobf.put(getFieldKey(deobfName, obfDesc), fieldMapping) == null; | ||
| 288 | assert (wasAdded); | ||
| 289 | } | ||
| 290 | this.isDirty = true; | ||
| 291 | } | ||
| 292 | |||
| 293 | //// METHODS //////// | ||
| 294 | |||
| 295 | public void setFieldObfNameAndType(String oldObfName, TypeDescriptor obfDesc, String newObfName, TypeDescriptor newObfDesc) { | ||
| 296 | assert (newObfName != null); | ||
| 297 | FieldMapping fieldMapping = fieldsByObf.remove(getFieldKey(oldObfName, obfDesc)); | ||
| 298 | assert (fieldMapping != null); | ||
| 299 | fieldMapping.setObfName(newObfName); | ||
| 300 | fieldMapping.setObfDesc(newObfDesc); | ||
| 301 | boolean obfWasAdded = fieldsByObf.put(getFieldKey(newObfName, newObfDesc), fieldMapping) == null; | ||
| 302 | assert (obfWasAdded); | ||
| 303 | this.isDirty = true; | ||
| 304 | } | ||
| 305 | |||
| 306 | public Iterable<MethodMapping> methods() { | ||
| 307 | assert (methodsByObf.size() >= methodsByDeobf.size()); | ||
| 308 | return methodsByObf.values(); | ||
| 309 | } | ||
| 310 | |||
| 311 | public boolean containsObfMethod(String obfName, MethodDescriptor obfDescriptor) { | ||
| 312 | return methodsByObf.containsKey(getMethodKey(obfName, obfDescriptor)); | ||
| 313 | } | ||
| 314 | |||
| 315 | public boolean containsDeobfMethod(String deobfName, MethodDescriptor obfDescriptor) { | ||
| 316 | return methodsByDeobf.containsKey(getMethodKey(deobfName, obfDescriptor)); | ||
| 317 | } | ||
| 318 | |||
| 319 | public void addMethodMapping(MethodMapping methodMapping) { | ||
| 320 | String obfKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfDesc()); | ||
| 321 | if (methodsByObf.containsKey(obfKey)) { | ||
| 322 | throw new Error("Already have mapping for " + obfFullName + "." + obfKey); | ||
| 323 | } | ||
| 324 | boolean wasAdded = methodsByObf.put(obfKey, methodMapping) == null; | ||
| 325 | assert (wasAdded); | ||
| 326 | if (!methodMapping.isObfuscated()) { | ||
| 327 | String deobfKey = getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfDesc()); | ||
| 328 | if (methodsByDeobf.containsKey(deobfKey)) { | ||
| 329 | throw new Error("Already have mapping for " + deobfName + "." + deobfKey); | ||
| 330 | } | ||
| 331 | boolean deobfWasAdded = methodsByDeobf.put(deobfKey, methodMapping) == null; | ||
| 332 | assert (deobfWasAdded); | ||
| 333 | } | ||
| 334 | this.isDirty = true; | ||
| 335 | assert (methodsByObf.size() >= methodsByDeobf.size()); | ||
| 336 | } | ||
| 337 | |||
| 338 | public void removeMethodMapping(MethodMapping methodMapping) { | ||
| 339 | boolean obfWasRemoved = methodsByObf.remove(getMethodKey(methodMapping.getObfName(), methodMapping.getObfDesc())) != null; | ||
| 340 | assert (obfWasRemoved); | ||
| 341 | if (!methodMapping.isObfuscated()) { | ||
| 342 | boolean deobfWasRemoved = methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfDesc())) != null; | ||
| 343 | assert (deobfWasRemoved); | ||
| 344 | } | ||
| 345 | this.isDirty = true; | ||
| 346 | } | ||
| 347 | |||
| 348 | public MethodMapping getMethodByObf(String obfName, MethodDescriptor obfDescriptor) { | ||
| 349 | return methodsByObf.get(getMethodKey(obfName, obfDescriptor)); | ||
| 350 | } | ||
| 351 | |||
| 352 | public MethodMapping getMethodByObf(MethodEntry method) { | ||
| 353 | return getMethodByObf(method.getName(), method.getDesc()); | ||
| 354 | } | ||
| 355 | |||
| 356 | public MethodMapping getMethodByDeobf(String deobfName, MethodDescriptor obfDescriptor) { | ||
| 357 | return methodsByDeobf.get(getMethodKey(deobfName, obfDescriptor)); | ||
| 358 | } | ||
| 359 | |||
| 360 | private String getMethodKey(String name, MethodDescriptor descriptor) { | ||
| 361 | if (name == null) { | ||
| 362 | throw new IllegalArgumentException("name cannot be null!"); | ||
| 363 | } | ||
| 364 | if (descriptor == null) { | ||
| 365 | throw new IllegalArgumentException("descriptor cannot be null!"); | ||
| 366 | } | ||
| 367 | return name + descriptor; | ||
| 368 | } | ||
| 369 | |||
| 370 | public void setMethodName(String obfName, MethodDescriptor obfDescriptor, String deobfName) { | ||
| 371 | MethodMapping methodMapping = methodsByObf.get(getMethodKey(obfName, obfDescriptor)); | ||
| 372 | if (methodMapping == null) { | ||
| 373 | methodMapping = createMethodMapping(obfName, obfDescriptor); | ||
| 374 | } else if (!methodMapping.isObfuscated()) { | ||
| 375 | boolean wasRemoved = methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfDesc())) != null; | ||
| 376 | assert (wasRemoved); | ||
| 377 | } | ||
| 378 | methodMapping.setDeobfName(deobfName); | ||
| 379 | if (deobfName != null) { | ||
| 380 | boolean wasAdded = methodsByDeobf.put(getMethodKey(deobfName, obfDescriptor), methodMapping) == null; | ||
| 381 | assert (wasAdded); | ||
| 382 | } | ||
| 383 | this.isDirty = true; | ||
| 384 | } | ||
| 385 | |||
| 386 | //// ARGUMENTS //////// | ||
| 387 | |||
| 388 | public void setMethodObfNameAndSignature(String oldObfName, MethodDescriptor obfDescriptor, String newObfName, MethodDescriptor newObfDescriptor) { | ||
| 389 | assert (newObfName != null); | ||
| 390 | MethodMapping methodMapping = methodsByObf.remove(getMethodKey(oldObfName, obfDescriptor)); | ||
| 391 | assert (methodMapping != null); | ||
| 392 | methodMapping.setObfName(newObfName); | ||
| 393 | methodMapping.setObfDescriptor(newObfDescriptor); | ||
| 394 | boolean obfWasAdded = methodsByObf.put(getMethodKey(newObfName, newObfDescriptor), methodMapping) == null; | ||
| 395 | assert (obfWasAdded); | ||
| 396 | this.isDirty = true; | ||
| 397 | } | ||
| 398 | |||
| 399 | public void setArgumentName(String obfMethodName, MethodDescriptor obfMethodDescriptor, int argumentIndex, String argumentName) { | ||
| 400 | assert (argumentName != null); | ||
| 401 | MethodMapping methodMapping = methodsByObf.get(getMethodKey(obfMethodName, obfMethodDescriptor)); | ||
| 402 | if (methodMapping == null) { | ||
| 403 | methodMapping = createMethodMapping(obfMethodName, obfMethodDescriptor); | ||
| 404 | } | ||
| 405 | methodMapping.setLocalVariableName(argumentIndex, argumentName); | ||
| 406 | this.isDirty = true; | ||
| 407 | } | ||
| 408 | |||
| 409 | public void removeArgumentName(String obfMethodName, MethodDescriptor obfMethodDescriptor, int argumentIndex) { | ||
| 410 | methodsByObf.get(getMethodKey(obfMethodName, obfMethodDescriptor)).removeLocalVariableName(argumentIndex); | ||
| 411 | this.isDirty = true; | ||
| 412 | } | ||
| 413 | |||
| 414 | private MethodMapping createMethodMapping(String obfName, MethodDescriptor obfDescriptor) { | ||
| 415 | MethodMapping methodMapping = new MethodMapping(obfName, obfDescriptor); | ||
| 416 | boolean wasAdded = methodsByObf.put(getMethodKey(obfName, obfDescriptor), methodMapping) == null; | ||
| 417 | assert (wasAdded); | ||
| 418 | this.isDirty = true; | ||
| 419 | return methodMapping; | ||
| 420 | } | ||
| 421 | |||
| 422 | @Override | ||
| 423 | public String toString() { | ||
| 424 | StringBuilder buf = new StringBuilder(); | ||
| 425 | buf.append(obfFullName); | ||
| 426 | buf.append(" <-> "); | ||
| 427 | buf.append(deobfName); | ||
| 428 | buf.append("\n"); | ||
| 429 | buf.append("Fields:\n"); | ||
| 430 | for (FieldMapping fieldMapping : fields()) { | ||
| 431 | buf.append("\t"); | ||
| 432 | buf.append(fieldMapping.getObfName()); | ||
| 433 | buf.append(" <-> "); | ||
| 434 | buf.append(fieldMapping.getDeobfName()); | ||
| 435 | buf.append("\n"); | ||
| 436 | } | ||
| 437 | buf.append("Methods:\n"); | ||
| 438 | for (MethodMapping methodMapping : methodsByObf.values()) { | ||
| 439 | buf.append(methodMapping); | ||
| 440 | buf.append("\n"); | ||
| 441 | } | ||
| 442 | buf.append("Inner Classes:\n"); | ||
| 443 | for (ClassMapping classMapping : innerClassesByObfSimple.values()) { | ||
| 444 | buf.append("\t"); | ||
| 445 | buf.append(classMapping.getObfSimpleName()); | ||
| 446 | buf.append(" <-> "); | ||
| 447 | buf.append(classMapping.getDeobfName()); | ||
| 448 | buf.append("\n"); | ||
| 449 | } | ||
| 450 | return buf.toString(); | ||
| 451 | } | ||
| 452 | |||
| 453 | @Override | ||
| 454 | public int compareTo(ClassMapping other) { | ||
| 455 | // sort by a, b, c, ... aa, ab, etc | ||
| 456 | if (obfFullName.length() != other.obfFullName.length()) { | ||
| 457 | return obfFullName.length() - other.obfFullName.length(); | ||
| 458 | } | ||
| 459 | return obfFullName.compareTo(other.obfFullName); | ||
| 460 | } | ||
| 461 | |||
| 462 | public boolean renameObfClass(String oldObfClassName, String newObfClassName) { | ||
| 463 | |||
| 464 | // rename inner classes | ||
| 465 | for (ClassMapping innerClassMapping : new ArrayList<>(innerClassesByObfSimple.values())) { | ||
| 466 | if (innerClassMapping.renameObfClass(oldObfClassName, newObfClassName)) { | ||
| 467 | boolean wasRemoved = innerClassesByObfSimple.remove(oldObfClassName) != null; | ||
| 468 | assert (wasRemoved); | ||
| 469 | boolean wasAdded = innerClassesByObfSimple.put(newObfClassName, innerClassMapping) == null; | ||
| 470 | assert (wasAdded); | ||
| 471 | } | ||
| 472 | } | ||
| 473 | |||
| 474 | // rename field types | ||
| 475 | for (FieldMapping fieldMapping : new ArrayList<>(fieldsByObf.values())) { | ||
| 476 | String oldFieldKey = getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfDesc()); | ||
| 477 | if (fieldMapping.renameObfClass(oldObfClassName, newObfClassName)) { | ||
| 478 | boolean wasRemoved = fieldsByObf.remove(oldFieldKey) != null; | ||
| 479 | assert (wasRemoved); | ||
| 480 | boolean wasAdded = fieldsByObf | ||
| 481 | .put(getFieldKey(fieldMapping.getObfName(), fieldMapping.getObfDesc()), fieldMapping) == null; | ||
| 482 | assert (wasAdded); | ||
| 483 | } | ||
| 484 | } | ||
| 485 | |||
| 486 | // rename method signatures | ||
| 487 | for (MethodMapping methodMapping : new ArrayList<>(methodsByObf.values())) { | ||
| 488 | String oldMethodKey = getMethodKey(methodMapping.getObfName(), methodMapping.getObfDesc()); | ||
| 489 | if (methodMapping.renameObfClass(oldObfClassName, newObfClassName)) { | ||
| 490 | boolean wasRemoved = methodsByObf.remove(oldMethodKey) != null; | ||
| 491 | assert (wasRemoved); | ||
| 492 | boolean wasAdded = methodsByObf | ||
| 493 | .put(getMethodKey(methodMapping.getObfName(), methodMapping.getObfDesc()), methodMapping) == null; | ||
| 494 | assert (wasAdded); | ||
| 495 | } | ||
| 496 | } | ||
| 497 | |||
| 498 | if (obfFullName.equals(oldObfClassName)) { | ||
| 499 | // rename this class | ||
| 500 | obfFullName = newObfClassName; | ||
| 501 | return true; | ||
| 502 | } | ||
| 503 | this.isDirty = true; | ||
| 504 | return false; | ||
| 505 | } | ||
| 506 | |||
| 507 | public boolean containsArgument(MethodEntry obfMethodEntry, String name) { | ||
| 508 | MethodMapping methodMapping = methodsByObf.get(getMethodKey(obfMethodEntry.getName(), obfMethodEntry.getDesc())); | ||
| 509 | return methodMapping != null && methodMapping.containsLocalVariable(name); | ||
| 510 | } | ||
| 511 | |||
| 512 | public ClassEntry getObfEntry() { | ||
| 513 | return new ClassEntry(obfFullName); | ||
| 514 | } | ||
| 515 | |||
| 516 | public ClassEntry getDeObfEntry() { | ||
| 517 | return deobfFullName != null ? new ClassEntry(deobfFullName) : null; | ||
| 518 | } | ||
| 519 | |||
| 520 | public boolean isObfuscated() { | ||
| 521 | return this.deobfName == null || this.deobfName.equals(this.obfFullName); | ||
| 522 | } | ||
| 523 | |||
| 524 | public String getSaveName() { | ||
| 525 | return this.isObfuscated() ? this.obfFullName : this.deobfName; | ||
| 526 | } | ||
| 527 | |||
| 528 | public boolean isDirty() { | ||
| 529 | return isDirty || areInnersDirty(); | ||
| 530 | } | ||
| 531 | |||
| 532 | private boolean areInnersDirty(){ | ||
| 533 | for (ClassMapping c : this.innerClasses()){ | ||
| 534 | if (c.isDirty()){ | ||
| 535 | return true; | ||
| 536 | } | ||
| 537 | } | ||
| 538 | return false; | ||
| 539 | } | ||
| 540 | |||
| 541 | public void resetDirty() { | ||
| 542 | this.isDirty = false; | ||
| 543 | } | ||
| 544 | |||
| 545 | public void markDirty() { | ||
| 546 | this.isDirty = true; | ||
| 547 | } | ||
| 548 | |||
| 549 | public Mappings.EntryModifier getModifier() { | ||
| 550 | return modifier; | ||
| 551 | } | ||
| 552 | |||
| 553 | public void setModifier(Mappings.EntryModifier modifier) { | ||
| 554 | if (this.modifier != modifier) | ||
| 555 | this.isDirty = true; | ||
| 556 | this.modifier = modifier; | ||
| 557 | } | ||
| 558 | |||
| 559 | public void setFieldModifier(String obfName, TypeDescriptor obfDesc, Mappings.EntryModifier modifier) { | ||
| 560 | FieldMapping fieldMapping = fieldsByObf.computeIfAbsent(getFieldKey(obfName, obfDesc), | ||
| 561 | k -> new FieldMapping(obfName, obfDesc, null, Mappings.EntryModifier.UNCHANGED)); | ||
| 562 | |||
| 563 | if (fieldMapping.getModifier() != modifier) { | ||
| 564 | fieldMapping.setModifier(modifier); | ||
| 565 | this.isDirty = true; | ||
| 566 | } | ||
| 567 | } | ||
| 568 | |||
| 569 | public void setMethodModifier(String obfName, MethodDescriptor sig, Mappings.EntryModifier modifier) { | ||
| 570 | MethodMapping methodMapping = methodsByObf.computeIfAbsent(getMethodKey(obfName, sig), | ||
| 571 | k -> new MethodMapping(obfName, sig, null, Mappings.EntryModifier.UNCHANGED)); | ||
| 572 | |||
| 573 | if (methodMapping.getModifier() != modifier) { | ||
| 574 | methodMapping.setModifier(modifier); | ||
| 575 | this.isDirty = true; | ||
| 576 | } | ||
| 577 | } | ||
| 578 | |||
| 579 | // Used for tiny parsing to keep track of deobfuscate inner classes | ||
| 580 | public ClassMapping setDeobfInner(String deobName) { | ||
| 581 | this.deobfFullName = deobName; | ||
| 582 | return this; | ||
| 583 | } | ||
| 584 | |||
| 585 | public ClassMapping copy() { | ||
| 586 | ClassMapping copied = new ClassMapping(this.obfFullName); | ||
| 587 | copied.obfSimpleName= this.obfSimpleName; | ||
| 588 | copied.modifier = this.modifier; | ||
| 589 | copied.deobfFullName = this.deobfFullName; | ||
| 590 | copied.deobfName = this.deobfName; | ||
| 591 | copied.innerClassesByDeobf = this.innerClassesByDeobf; | ||
| 592 | copied.innerClassesByObfFull = this.innerClassesByObfFull; | ||
| 593 | copied.innerClassesByObfSimple = this.innerClassesByObfSimple; | ||
| 594 | copied.fieldsByObf = this.fieldsByObf; | ||
| 595 | copied.fieldsByDeobf = this.fieldsByDeobf; | ||
| 596 | copied.methodsByObf = this.methodsByObf; | ||
| 597 | copied.methodsByDeobf = this.methodsByDeobf; | ||
| 598 | return copied; | ||
| 599 | } | ||
| 600 | |||
| 601 | @Override | ||
| 602 | public int hashCode() { | ||
| 603 | return this.obfFullName.hashCode(); | ||
| 604 | } | ||
| 605 | |||
| 606 | @Override | ||
| 607 | public boolean equals(Object obj) { | ||
| 608 | return obj instanceof ClassMapping && ((ClassMapping) obj).obfFullName.equals(this.obfFullName); | ||
| 609 | } | ||
| 610 | |||
| 611 | public boolean isEmpty() { | ||
| 612 | if (fieldsByDeobf.isEmpty() && methodsByDeobf.isEmpty() && deobfFullName == null && deobfName == null | ||
| 613 | && innerClassesByObfSimple.values().stream().allMatch(ClassMapping::isEmpty)) { | ||
| 614 | |||
| 615 | // check args | ||
| 616 | for (MethodMapping mapping : methodsByObf.values()) { | ||
| 617 | if (mapping.arguments().iterator().hasNext()) { | ||
| 618 | return false; | ||
| 619 | } | ||
| 620 | } | ||
| 621 | |||
| 622 | return true; | ||
| 623 | } | ||
| 624 | |||
| 625 | return false; | ||
| 626 | } | ||
| 627 | } | ||