diff options
Diffstat (limited to 'src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java')
| -rw-r--r-- | src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java | 365 |
1 files changed, 0 insertions, 365 deletions
diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java b/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java deleted file mode 100644 index 8ef4f12..0000000 --- a/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java +++ /dev/null | |||
| @@ -1,365 +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.Lists; | ||
| 15 | import cuchaz.enigma.analysis.JarIndex; | ||
| 16 | import cuchaz.enigma.mapping.entry.*; | ||
| 17 | import cuchaz.enigma.throwables.IllegalNameException; | ||
| 18 | import cuchaz.enigma.throwables.MappingConflict; | ||
| 19 | |||
| 20 | import java.io.IOException; | ||
| 21 | import java.io.ObjectOutputStream; | ||
| 22 | import java.io.OutputStream; | ||
| 23 | import java.util.List; | ||
| 24 | import java.util.Set; | ||
| 25 | import java.util.zip.GZIPOutputStream; | ||
| 26 | |||
| 27 | public class MappingsRenamer { | ||
| 28 | |||
| 29 | private final JarIndex index; | ||
| 30 | private final ReferencedEntryPool entryPool; | ||
| 31 | private Mappings mappings; | ||
| 32 | |||
| 33 | public MappingsRenamer(JarIndex index, Mappings mappings, ReferencedEntryPool entryPool) { | ||
| 34 | this.index = index; | ||
| 35 | this.mappings = mappings; | ||
| 36 | this.entryPool = entryPool; | ||
| 37 | } | ||
| 38 | |||
| 39 | public void setMappings(Mappings mappings) { | ||
| 40 | this.mappings = mappings; | ||
| 41 | } | ||
| 42 | |||
| 43 | public void setClassName(ClassEntry obf, String deobfName) { | ||
| 44 | |||
| 45 | deobfName = NameValidator.validateClassName(deobfName, !obf.isInnerClass()); | ||
| 46 | |||
| 47 | List<ClassMapping> mappingChain = getOrCreateClassMappingChain(obf); | ||
| 48 | if (mappingChain.size() == 1) { | ||
| 49 | |||
| 50 | if (deobfName != null) { | ||
| 51 | // make sure we don't rename to an existing obf or deobf class | ||
| 52 | if (mappings.containsDeobfClass(deobfName) || index.containsObfClass(entryPool.getClass(deobfName))) { | ||
| 53 | throw new IllegalNameException(deobfName, "There is already a class with that name"); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | ClassMapping classMapping = mappingChain.get(0); | ||
| 58 | mappings.setClassDeobfName(classMapping, deobfName); | ||
| 59 | |||
| 60 | } else { | ||
| 61 | |||
| 62 | ClassMapping outerClassMapping = mappingChain.get(mappingChain.size() - 2); | ||
| 63 | |||
| 64 | if (deobfName != null) { | ||
| 65 | // make sure we don't rename to an existing obf or deobf inner class | ||
| 66 | if (outerClassMapping.hasInnerClassByDeobf(deobfName) || outerClassMapping.hasInnerClassByObfSimple(deobfName)) { | ||
| 67 | throw new IllegalNameException(deobfName, "There is already a class with that name"); | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | outerClassMapping.setInnerClassName(obf, deobfName); | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | public void removeClassMapping(ClassEntry obf) { | ||
| 76 | setClassName(obf, null); | ||
| 77 | } | ||
| 78 | |||
| 79 | public void markClassAsDeobfuscated(ClassEntry obf) { | ||
| 80 | String deobfName = obf.isInnerClass() ? obf.getInnermostClassName() : obf.getName(); | ||
| 81 | List<ClassMapping> mappingChain = getOrCreateClassMappingChain(obf); | ||
| 82 | if (mappingChain.size() == 1) { | ||
| 83 | ClassMapping classMapping = mappingChain.get(0); | ||
| 84 | mappings.setClassDeobfName(classMapping, deobfName); | ||
| 85 | } else { | ||
| 86 | ClassMapping outerClassMapping = mappingChain.get(mappingChain.size() - 2); | ||
| 87 | outerClassMapping.setInnerClassName(obf, deobfName); | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | public void setFieldName(FieldEntry obf, String deobfName) { | ||
| 92 | deobfName = NameValidator.validateFieldName(deobfName); | ||
| 93 | FieldEntry targetEntry = entryPool.getField(obf.getOwnerClassEntry(), deobfName, obf.getDesc()); | ||
| 94 | ClassEntry definedClass = null; | ||
| 95 | if (mappings.containsDeobfField(obf.getOwnerClassEntry(), deobfName) || index.containsEntryWithSameName(targetEntry)) { | ||
| 96 | definedClass = obf.getOwnerClassEntry(); | ||
| 97 | } else { | ||
| 98 | for (ClassEntry ancestorEntry : this.index.getTranslationIndex().getAncestry(obf.getOwnerClassEntry())) { | ||
| 99 | if (mappings.containsDeobfField(ancestorEntry, deobfName) || index.containsEntryWithSameName(targetEntry.updateOwnership(ancestorEntry))) { | ||
| 100 | definedClass = ancestorEntry; | ||
| 101 | break; | ||
| 102 | } | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | if (definedClass != null) { | ||
| 107 | Translator translator = mappings.getTranslator(TranslationDirection.DEOBFUSCATING, index.getTranslationIndex()); | ||
| 108 | String className = translator.getTranslatedClass(entryPool.getClass(definedClass.getClassName())).getName(); | ||
| 109 | if (className == null) | ||
| 110 | className = definedClass.getClassName(); | ||
| 111 | throw new IllegalNameException(deobfName, "There is already a field with that name in " + className); | ||
| 112 | } | ||
| 113 | |||
| 114 | ClassMapping classMapping = getOrCreateClassMapping(obf.getOwnerClassEntry()); | ||
| 115 | classMapping.setFieldName(obf.getName(), obf.getDesc(), deobfName); | ||
| 116 | } | ||
| 117 | |||
| 118 | public void removeFieldMapping(FieldEntry obf) { | ||
| 119 | ClassMapping classMapping = getOrCreateClassMapping(obf.getOwnerClassEntry()); | ||
| 120 | classMapping.removeFieldMapping(classMapping.getFieldByObf(obf.getName(), obf.getDesc())); | ||
| 121 | } | ||
| 122 | |||
| 123 | public void markFieldAsDeobfuscated(FieldEntry obf) { | ||
| 124 | ClassMapping classMapping = getOrCreateClassMapping(obf.getOwnerClassEntry()); | ||
| 125 | classMapping.setFieldName(obf.getName(), obf.getDesc(), obf.getName()); | ||
| 126 | } | ||
| 127 | |||
| 128 | private void validateMethodTreeName(MethodEntry entry, String deobfName) { | ||
| 129 | MethodEntry targetEntry = entryPool.getMethod(entry.getOwnerClassEntry(), deobfName, entry.getDesc()); | ||
| 130 | |||
| 131 | // TODO: Verify if I don't break things | ||
| 132 | ClassMapping classMapping = mappings.getClassByObf(entry.getOwnerClassEntry()); | ||
| 133 | if ((classMapping != null && classMapping.containsDeobfMethod(deobfName, entry.getDesc()) && classMapping.getMethodByObf(entry.getName(), entry.getDesc()) != classMapping.getMethodByDeobf(deobfName, entry.getDesc())) | ||
| 134 | || index.containsObfMethod(targetEntry)) { | ||
| 135 | Translator translator = mappings.getTranslator(TranslationDirection.DEOBFUSCATING, index.getTranslationIndex()); | ||
| 136 | String deobfClassName = translator.getTranslatedClass(entryPool.getClass(entry.getClassName())).getClassName(); | ||
| 137 | if (deobfClassName == null) { | ||
| 138 | deobfClassName = entry.getClassName(); | ||
| 139 | } | ||
| 140 | throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName); | ||
| 141 | } | ||
| 142 | |||
| 143 | for (ClassEntry child : index.getTranslationIndex().getSubclass(entry.getOwnerClassEntry())) { | ||
| 144 | validateMethodTreeName(entry.updateOwnership(child), deobfName); | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | public void setMethodTreeName(MethodEntry obf, String deobfName) { | ||
| 149 | Set<MethodEntry> implementations = index.getRelatedMethodImplementations(obf); | ||
| 150 | |||
| 151 | deobfName = NameValidator.validateMethodName(deobfName); | ||
| 152 | for (MethodEntry entry : implementations) { | ||
| 153 | validateMethodTreeName(entry, deobfName); | ||
| 154 | } | ||
| 155 | |||
| 156 | for (MethodEntry entry : implementations) { | ||
| 157 | setMethodName(entry, deobfName); | ||
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | public void setMethodName(MethodEntry obf, String deobfName) { | ||
| 162 | deobfName = NameValidator.validateMethodName(deobfName); | ||
| 163 | MethodEntry targetEntry = entryPool.getMethod(obf.getOwnerClassEntry(), deobfName, obf.getDesc()); | ||
| 164 | ClassMapping classMapping = getOrCreateClassMapping(obf.getOwnerClassEntry()); | ||
| 165 | |||
| 166 | // TODO: Verify if I don't break things | ||
| 167 | if ((mappings.containsDeobfMethod(obf.getOwnerClassEntry(), deobfName, obf.getDesc()) && classMapping.getMethodByObf(obf.getName(), obf.getDesc()) != classMapping.getMethodByDeobf(deobfName, obf.getDesc())) | ||
| 168 | || index.containsObfMethod(targetEntry)) { | ||
| 169 | Translator translator = mappings.getTranslator(TranslationDirection.DEOBFUSCATING, index.getTranslationIndex()); | ||
| 170 | String deobfClassName = translator.getTranslatedClass(entryPool.getClass(obf.getClassName())).getClassName(); | ||
| 171 | if (deobfClassName == null) { | ||
| 172 | deobfClassName = obf.getClassName(); | ||
| 173 | } | ||
| 174 | throw new IllegalNameException(deobfName, "There is already a method with that name and signature in class " + deobfClassName); | ||
| 175 | } | ||
| 176 | |||
| 177 | classMapping.setMethodName(obf.getName(), obf.getDesc(), deobfName); | ||
| 178 | } | ||
| 179 | |||
| 180 | public void removeMethodTreeMapping(MethodEntry obf) { | ||
| 181 | index.getRelatedMethodImplementations(obf).forEach(this::removeMethodMapping); | ||
| 182 | } | ||
| 183 | |||
| 184 | public void removeMethodMapping(MethodEntry obf) { | ||
| 185 | ClassMapping classMapping = getOrCreateClassMapping(obf.getOwnerClassEntry()); | ||
| 186 | classMapping.setMethodName(obf.getName(), obf.getDesc(), null); | ||
| 187 | } | ||
| 188 | |||
| 189 | public void markMethodTreeAsDeobfuscated(MethodEntry obf) { | ||
| 190 | index.getRelatedMethodImplementations(obf).forEach(this::markMethodAsDeobfuscated); | ||
| 191 | } | ||
| 192 | |||
| 193 | public void markMethodAsDeobfuscated(MethodEntry obf) { | ||
| 194 | ClassMapping classMapping = getOrCreateClassMapping(obf.getOwnerClassEntry()); | ||
| 195 | classMapping.setMethodName(obf.getName(), obf.getDesc(), obf.getName()); | ||
| 196 | } | ||
| 197 | |||
| 198 | public void setLocalVariableTreeName(LocalVariableEntry obf, String deobfName) { | ||
| 199 | MethodEntry obfMethod = obf.getOwnerEntry(); | ||
| 200 | if (!obf.isParameter()) { | ||
| 201 | setLocalVariableName(obf, deobfName); | ||
| 202 | return; | ||
| 203 | } | ||
| 204 | |||
| 205 | Set<MethodEntry> implementations = index.getRelatedMethodImplementations(obfMethod); | ||
| 206 | for (MethodEntry entry : implementations) { | ||
| 207 | ClassMapping classMapping = mappings.getClassByObf(entry.getOwnerClassEntry()); | ||
| 208 | if (classMapping != null) { | ||
| 209 | MethodMapping mapping = classMapping.getMethodByObf(entry.getName(), entry.getDesc()); | ||
| 210 | // NOTE: don't need to check arguments for name collisions with names determined by Procyon | ||
| 211 | // TODO: Verify if I don't break things | ||
| 212 | if (mapping != null) { | ||
| 213 | for (LocalVariableMapping localVariableMapping : Lists.newArrayList(mapping.arguments())) { | ||
| 214 | if (localVariableMapping.getIndex() != obf.getIndex()) { | ||
| 215 | if (mapping.getDeobfLocalVariableName(localVariableMapping.getIndex()).equals(deobfName) | ||
| 216 | || localVariableMapping.getName().equals(deobfName)) { | ||
| 217 | throw new IllegalNameException(deobfName, "There is already an argument with that name"); | ||
| 218 | } | ||
| 219 | } | ||
| 220 | } | ||
| 221 | } | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | for (MethodEntry entry : implementations) { | ||
| 226 | setLocalVariableName(new LocalVariableEntry(entry, obf.getIndex(), obf.getName(), obf.isParameter()), deobfName); | ||
| 227 | } | ||
| 228 | } | ||
| 229 | |||
| 230 | public void setLocalVariableName(LocalVariableEntry obf, String deobfName) { | ||
| 231 | deobfName = NameValidator.validateArgumentName(deobfName); | ||
| 232 | ClassMapping classMapping = getOrCreateClassMapping(obf.getOwnerClassEntry()); | ||
| 233 | MethodMapping mapping = classMapping.getMethodByObf(obf.getMethodName(), obf.getMethodDesc()); | ||
| 234 | // NOTE: don't need to check arguments for name collisions with names determined by Procyon | ||
| 235 | // TODO: Verify if I don't break things | ||
| 236 | if (mapping != null) { | ||
| 237 | for (LocalVariableMapping localVariableMapping : Lists.newArrayList(mapping.arguments())) { | ||
| 238 | if (localVariableMapping.getIndex() != obf.getIndex()) { | ||
| 239 | if (mapping.getDeobfLocalVariableName(localVariableMapping.getIndex()).equals(deobfName) | ||
| 240 | || localVariableMapping.getName().equals(deobfName)) { | ||
| 241 | throw new IllegalNameException(deobfName, "There is already an argument with that name"); | ||
| 242 | } | ||
| 243 | } | ||
| 244 | } | ||
| 245 | } | ||
| 246 | |||
| 247 | classMapping.setArgumentName(obf.getMethodName(), obf.getMethodDesc(), obf.getIndex(), deobfName); | ||
| 248 | } | ||
| 249 | |||
| 250 | public void removeLocalVariableMapping(LocalVariableEntry obf) { | ||
| 251 | ClassMapping classMapping = getOrCreateClassMapping(obf.getOwnerClassEntry()); | ||
| 252 | classMapping.removeArgumentName(obf.getMethodName(), obf.getMethodDesc(), obf.getIndex()); | ||
| 253 | } | ||
| 254 | |||
| 255 | public void markArgumentAsDeobfuscated(LocalVariableEntry obf) { | ||
| 256 | ClassMapping classMapping = getOrCreateClassMapping(obf.getOwnerClassEntry()); | ||
| 257 | classMapping.setArgumentName(obf.getMethodName(), obf.getMethodDesc(), obf.getIndex(), obf.getName()); | ||
| 258 | } | ||
| 259 | |||
| 260 | public boolean moveFieldToObfClass(ClassMapping classMapping, FieldMapping fieldMapping, ClassEntry obfClass) { | ||
| 261 | classMapping.removeFieldMapping(fieldMapping); | ||
| 262 | ClassMapping targetClassMapping = getOrCreateClassMapping(obfClass); | ||
| 263 | if (!targetClassMapping.containsObfField(fieldMapping.getObfName(), fieldMapping.getObfDesc())) { | ||
| 264 | if (!targetClassMapping.containsDeobfField(fieldMapping.getDeobfName(), fieldMapping.getObfDesc())) { | ||
| 265 | targetClassMapping.addFieldMapping(fieldMapping); | ||
| 266 | return true; | ||
| 267 | } else { | ||
| 268 | System.err.println("WARNING: deobf field was already there: " + obfClass + "." + fieldMapping.getDeobfName()); | ||
| 269 | } | ||
| 270 | } | ||
| 271 | return false; | ||
| 272 | } | ||
| 273 | |||
| 274 | public boolean moveMethodToObfClass(ClassMapping classMapping, MethodMapping methodMapping, ClassEntry obfClass) { | ||
| 275 | classMapping.removeMethodMapping(methodMapping); | ||
| 276 | ClassMapping targetClassMapping = getOrCreateClassMapping(obfClass); | ||
| 277 | if (!targetClassMapping.containsObfMethod(methodMapping.getObfName(), methodMapping.getObfDesc())) { | ||
| 278 | if (!targetClassMapping.containsDeobfMethod(methodMapping.getDeobfName(), methodMapping.getObfDesc())) { | ||
| 279 | targetClassMapping.addMethodMapping(methodMapping); | ||
| 280 | return true; | ||
| 281 | } else { | ||
| 282 | System.err.println("WARNING: deobf method was already there: " + obfClass + "." + methodMapping.getDeobfName() + methodMapping.getObfDesc()); | ||
| 283 | } | ||
| 284 | } | ||
| 285 | return false; | ||
| 286 | } | ||
| 287 | |||
| 288 | public void write(OutputStream out) throws IOException { | ||
| 289 | // TEMP: just use the object output for now. We can find a more efficient storage format later | ||
| 290 | GZIPOutputStream gzipout = new GZIPOutputStream(out); | ||
| 291 | ObjectOutputStream oout = new ObjectOutputStream(gzipout); | ||
| 292 | oout.writeObject(this); | ||
| 293 | gzipout.finish(); | ||
| 294 | } | ||
| 295 | |||
| 296 | private ClassMapping getOrCreateClassMapping(ClassEntry obfClassEntry) { | ||
| 297 | List<ClassMapping> mappingChain = getOrCreateClassMappingChain(obfClassEntry); | ||
| 298 | return mappingChain.get(mappingChain.size() - 1); | ||
| 299 | } | ||
| 300 | |||
| 301 | private List<ClassMapping> getOrCreateClassMappingChain(ClassEntry obfClassEntry) { | ||
| 302 | List<ClassEntry> classChain = obfClassEntry.getClassChain(); | ||
| 303 | List<ClassMapping> mappingChain = mappings.getClassMappingChain(obfClassEntry); | ||
| 304 | for (int i = 0; i < classChain.size(); i++) { | ||
| 305 | ClassEntry classEntry = classChain.get(i); | ||
| 306 | ClassMapping classMapping = mappingChain.get(i); | ||
| 307 | if (classMapping == null) { | ||
| 308 | |||
| 309 | // create it | ||
| 310 | classMapping = new ClassMapping(classEntry.getName()); | ||
| 311 | mappingChain.set(i, classMapping); | ||
| 312 | |||
| 313 | // add it to the right parent | ||
| 314 | try { | ||
| 315 | if (i == 0) { | ||
| 316 | mappings.addClassMapping(classMapping); | ||
| 317 | } else { | ||
| 318 | mappingChain.get(i - 1).addInnerClassMapping(classMapping); | ||
| 319 | } | ||
| 320 | } catch (MappingConflict mappingConflict) { | ||
| 321 | mappingConflict.printStackTrace(); | ||
| 322 | } | ||
| 323 | } | ||
| 324 | } | ||
| 325 | return mappingChain; | ||
| 326 | } | ||
| 327 | |||
| 328 | public void setClassModifier(ClassEntry obEntry, Mappings.EntryModifier modifier) { | ||
| 329 | ClassMapping classMapping = getOrCreateClassMapping(obEntry); | ||
| 330 | classMapping.setModifier(modifier); | ||
| 331 | } | ||
| 332 | |||
| 333 | public void setFieldModifier(FieldEntry obEntry, Mappings.EntryModifier modifier) { | ||
| 334 | ClassMapping classMapping = getOrCreateClassMapping(obEntry.getOwnerClassEntry()); | ||
| 335 | classMapping.setFieldModifier(obEntry.getName(), obEntry.getDesc(), modifier); | ||
| 336 | } | ||
| 337 | |||
| 338 | public void setMethodModifier(MethodEntry obEntry, Mappings.EntryModifier modifier) { | ||
| 339 | ClassMapping classMapping = getOrCreateClassMapping(obEntry.getOwnerClassEntry()); | ||
| 340 | classMapping.setMethodModifier(obEntry.getName(), obEntry.getDesc(), modifier); | ||
| 341 | } | ||
| 342 | |||
| 343 | public Mappings.EntryModifier getClassModifier(ClassEntry obfEntry) { | ||
| 344 | ClassMapping classMapping = getOrCreateClassMapping(obfEntry); | ||
| 345 | return classMapping.getModifier(); | ||
| 346 | } | ||
| 347 | |||
| 348 | public Mappings.EntryModifier getFieldModifier(FieldEntry obfEntry) { | ||
| 349 | ClassMapping classMapping = getOrCreateClassMapping(obfEntry.getOwnerClassEntry()); | ||
| 350 | FieldMapping fieldMapping = classMapping.getFieldByObf(obfEntry); | ||
| 351 | if (fieldMapping == null) { | ||
| 352 | return Mappings.EntryModifier.UNCHANGED; | ||
| 353 | } | ||
| 354 | return fieldMapping.getModifier(); | ||
| 355 | } | ||
| 356 | |||
| 357 | public Mappings.EntryModifier getMethodModfifier(MethodEntry obfEntry) { | ||
| 358 | ClassMapping classMapping = getOrCreateClassMapping(obfEntry.getOwnerClassEntry()); | ||
| 359 | MethodMapping methodMapping = classMapping.getMethodByObf(obfEntry); | ||
| 360 | if (methodMapping == null) { | ||
| 361 | return Mappings.EntryModifier.UNCHANGED; | ||
| 362 | } | ||
| 363 | return methodMapping.getModifier(); | ||
| 364 | } | ||
| 365 | } | ||