diff options
Diffstat (limited to 'src/main/java')
32 files changed, 831 insertions, 132 deletions
diff --git a/src/main/java/cuchaz/enigma/Constants.java b/src/main/java/cuchaz/enigma/Constants.java index 5bdb3af7..04730480 100644 --- a/src/main/java/cuchaz/enigma/Constants.java +++ b/src/main/java/cuchaz/enigma/Constants.java | |||
| @@ -16,5 +16,4 @@ public class Constants { | |||
| 16 | public static final String URL = "http://www.cuchazinteractive.com/enigma"; | 16 | public static final String URL = "http://www.cuchazinteractive.com/enigma"; |
| 17 | public static final int MiB = 1024 * 1024; // 1 mebibyte | 17 | public static final int MiB = 1024 * 1024; // 1 mebibyte |
| 18 | public static final int KiB = 1024; // 1 kebibyte | 18 | public static final int KiB = 1024; // 1 kebibyte |
| 19 | public static final String NONE_PACKAGE = "none"; | ||
| 20 | } | 19 | } |
diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java index 20bb8b98..2766380b 100644 --- a/src/main/java/cuchaz/enigma/Deobfuscator.java +++ b/src/main/java/cuchaz/enigma/Deobfuscator.java | |||
| @@ -146,7 +146,7 @@ public class Deobfuscator { | |||
| 146 | if (!deobfClassEntry.equals(obfClassEntry)) { | 146 | if (!deobfClassEntry.equals(obfClassEntry)) { |
| 147 | // if the class has a mapping, clearly it's deobfuscated | 147 | // if the class has a mapping, clearly it's deobfuscated |
| 148 | deobfClasses.add(deobfClassEntry); | 148 | deobfClasses.add(deobfClassEntry); |
| 149 | } else if (!obfClassEntry.getPackageName().equals(Constants.NONE_PACKAGE)) { | 149 | } else if (obfClassEntry.getPackageName() != null) { |
| 150 | // also call it deobufscated if it's not in the none package | 150 | // also call it deobufscated if it's not in the none package |
| 151 | deobfClasses.add(obfClassEntry); | 151 | deobfClasses.add(obfClassEntry); |
| 152 | } else { | 152 | } else { |
| @@ -532,12 +532,20 @@ public class Deobfuscator { | |||
| 532 | return false; | 532 | return false; |
| 533 | } else if (obfEntry instanceof ArgumentEntry) { | 533 | } else if (obfEntry instanceof ArgumentEntry) { |
| 534 | return translator.translate((ArgumentEntry) obfEntry) != null; | 534 | return translator.translate((ArgumentEntry) obfEntry) != null; |
| 535 | } else if (obfEntry instanceof LocalVariableEntry) { | ||
| 536 | // TODO: Implement it | ||
| 537 | //return translator.translate((LocalVariableEntry)obfEntry) != null; | ||
| 538 | return false; | ||
| 535 | } else { | 539 | } else { |
| 536 | throw new Error("Unknown entry type: " + obfEntry.getClass().getName()); | 540 | throw new Error("Unknown entry type: " + obfEntry.getClass().getName()); |
| 537 | } | 541 | } |
| 538 | } | 542 | } |
| 539 | 543 | ||
| 540 | public void rename(Entry obfEntry, String newName) { | 544 | public void rename(Entry obfEntry, String newName) { |
| 545 | rename(obfEntry, newName, true); | ||
| 546 | } | ||
| 547 | |||
| 548 | public void rename(Entry obfEntry, String newName, boolean clearCache) { | ||
| 541 | if (obfEntry instanceof ClassEntry) { | 549 | if (obfEntry instanceof ClassEntry) { |
| 542 | this.renamer.setClassName((ClassEntry) obfEntry, Descriptor.toJvmName(newName)); | 550 | this.renamer.setClassName((ClassEntry) obfEntry, Descriptor.toJvmName(newName)); |
| 543 | } else if (obfEntry instanceof FieldEntry) { | 551 | } else if (obfEntry instanceof FieldEntry) { |
| @@ -548,12 +556,15 @@ public class Deobfuscator { | |||
| 548 | throw new IllegalArgumentException("Cannot rename constructors"); | 556 | throw new IllegalArgumentException("Cannot rename constructors"); |
| 549 | } else if (obfEntry instanceof ArgumentEntry) { | 557 | } else if (obfEntry instanceof ArgumentEntry) { |
| 550 | this.renamer.setArgumentTreeName((ArgumentEntry) obfEntry, newName); | 558 | this.renamer.setArgumentTreeName((ArgumentEntry) obfEntry, newName); |
| 559 | } else if (obfEntry instanceof LocalVariableEntry) { | ||
| 560 | // TODO: Implement it | ||
| 551 | } else { | 561 | } else { |
| 552 | throw new Error("Unknown entry type: " + obfEntry.getClass().getName()); | 562 | throw new Error("Unknown entry type: " + obfEntry.getClass().getName()); |
| 553 | } | 563 | } |
| 554 | 564 | ||
| 555 | // clear caches | 565 | // clear caches |
| 556 | this.translatorCache.clear(); | 566 | if (clearCache) |
| 567 | this.translatorCache.clear(); | ||
| 557 | } | 568 | } |
| 558 | 569 | ||
| 559 | public void removeMapping(Entry obfEntry) { | 570 | public void removeMapping(Entry obfEntry) { |
| @@ -586,6 +597,8 @@ public class Deobfuscator { | |||
| 586 | throw new IllegalArgumentException("Cannot rename constructors"); | 597 | throw new IllegalArgumentException("Cannot rename constructors"); |
| 587 | } else if (obfEntry instanceof ArgumentEntry) { | 598 | } else if (obfEntry instanceof ArgumentEntry) { |
| 588 | this.renamer.markArgumentAsDeobfuscated((ArgumentEntry) obfEntry); | 599 | this.renamer.markArgumentAsDeobfuscated((ArgumentEntry) obfEntry); |
| 600 | } else if (obfEntry instanceof LocalVariableEntry) { | ||
| 601 | // TODO: Implement it | ||
| 589 | } else { | 602 | } else { |
| 590 | throw new Error("Unknown entry type: " + obfEntry); | 603 | throw new Error("Unknown entry type: " + obfEntry); |
| 591 | } | 604 | } |
| @@ -593,4 +606,25 @@ public class Deobfuscator { | |||
| 593 | // clear caches | 606 | // clear caches |
| 594 | this.translatorCache.clear(); | 607 | this.translatorCache.clear(); |
| 595 | } | 608 | } |
| 609 | |||
| 610 | public void changeModifier(Entry entry, Mappings.EntryModifier modifierEntry) | ||
| 611 | { | ||
| 612 | Entry obfEntry = obfuscateEntry(entry); | ||
| 613 | if (obfEntry instanceof ClassEntry) | ||
| 614 | this.renamer.setClassModifier((ClassEntry) obfEntry, modifierEntry); | ||
| 615 | else if (obfEntry instanceof FieldEntry) | ||
| 616 | this.renamer.setFieldModifier((FieldEntry) obfEntry, modifierEntry); | ||
| 617 | else if (obfEntry instanceof BehaviorEntry) | ||
| 618 | this.renamer.setMethodModifier((BehaviorEntry) obfEntry, modifierEntry); | ||
| 619 | else | ||
| 620 | throw new Error("Unknown entry type: " + obfEntry); | ||
| 621 | } | ||
| 622 | |||
| 623 | public Mappings.EntryModifier getModifier(Entry obEntry) | ||
| 624 | { | ||
| 625 | Entry entry = obfuscateEntry(obEntry); | ||
| 626 | if (entry != null) | ||
| 627 | obEntry = entry; | ||
| 628 | return getTranslator(TranslationDirection.Deobfuscating).getModifier(obEntry); | ||
| 629 | } | ||
| 596 | } | 630 | } |
diff --git a/src/main/java/cuchaz/enigma/TranslatingTypeLoader.java b/src/main/java/cuchaz/enigma/TranslatingTypeLoader.java index 13efbd51..73405662 100644 --- a/src/main/java/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/main/java/cuchaz/enigma/TranslatingTypeLoader.java | |||
| @@ -187,10 +187,6 @@ public class TranslatingTypeLoader implements ITypeLoader { | |||
| 187 | public List<String> getClassNamesToTry(ClassEntry obfClassEntry) { | 187 | public List<String> getClassNamesToTry(ClassEntry obfClassEntry) { |
| 188 | List<String> classNamesToTry = Lists.newArrayList(); | 188 | List<String> classNamesToTry = Lists.newArrayList(); |
| 189 | classNamesToTry.add(obfClassEntry.getName()); | 189 | classNamesToTry.add(obfClassEntry.getName()); |
| 190 | if (obfClassEntry.getPackageName().equals(Constants.NONE_PACKAGE)) { | ||
| 191 | // taking off the none package, if any | ||
| 192 | classNamesToTry.add(obfClassEntry.getSimpleName()); | ||
| 193 | } | ||
| 194 | if (obfClassEntry.isInnerClass()) { | 190 | if (obfClassEntry.isInnerClass()) { |
| 195 | // try just the inner class name | 191 | // try just the inner class name |
| 196 | classNamesToTry.add(obfClassEntry.getInnermostClassName()); | 192 | classNamesToTry.add(obfClassEntry.getInnermostClassName()); |
| @@ -201,12 +197,8 @@ public class TranslatingTypeLoader implements ITypeLoader { | |||
| 201 | public CtClass transformClass(CtClass c) | 197 | public CtClass transformClass(CtClass c) |
| 202 | throws IOException, NotFoundException, CannotCompileException { | 198 | throws IOException, NotFoundException, CannotCompileException { |
| 203 | 199 | ||
| 204 | // we moved a lot of classes out of the default package into the none package | ||
| 205 | // make sure all the class references are consistent | ||
| 206 | ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NONE_PACKAGE); | ||
| 207 | |||
| 208 | // reconstruct inner classes | 200 | // reconstruct inner classes |
| 209 | new InnerClassWriter(this.jarIndex).write(c); | 201 | new InnerClassWriter(this.jarIndex, this.deobfuscatingTranslator).write(c); |
| 210 | 202 | ||
| 211 | // re-get the javassist handle since we changed class names | 203 | // re-get the javassist handle since we changed class names |
| 212 | ClassEntry obfClassEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); | 204 | ClassEntry obfClassEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); |
diff --git a/src/main/java/cuchaz/enigma/analysis/JarIndex.java b/src/main/java/cuchaz/enigma/analysis/JarIndex.java index e501540d..ee1dd544 100644 --- a/src/main/java/cuchaz/enigma/analysis/JarIndex.java +++ b/src/main/java/cuchaz/enigma/analysis/JarIndex.java | |||
| @@ -59,17 +59,10 @@ public class JarIndex { | |||
| 59 | public void indexJar(JarFile jar, boolean buildInnerClasses) { | 59 | public void indexJar(JarFile jar, boolean buildInnerClasses) { |
| 60 | 60 | ||
| 61 | // step 1: read the class names | 61 | // step 1: read the class names |
| 62 | for (ClassEntry classEntry : JarClassIterator.getClassEntries(jar)) { | 62 | this.obfClassEntries.addAll(JarClassIterator.getClassEntries(jar)); |
| 63 | if (classEntry.isInDefaultPackage()) { | ||
| 64 | // move out of default package | ||
| 65 | classEntry = new ClassEntry(Constants.NONE_PACKAGE + "/" + classEntry.getName()); | ||
| 66 | } | ||
| 67 | this.obfClassEntries.add(classEntry); | ||
| 68 | } | ||
| 69 | 63 | ||
| 70 | // step 2: index field/method/constructor access | 64 | // step 2: index field/method/constructor access |
| 71 | for (CtClass c : JarClassIterator.classes(jar)) { | 65 | for (CtClass c : JarClassIterator.classes(jar)) { |
| 72 | ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NONE_PACKAGE); | ||
| 73 | for (CtField field : c.getDeclaredFields()) { | 66 | for (CtField field : c.getDeclaredFields()) { |
| 74 | FieldEntry fieldEntry = EntryFactory.getFieldEntry(field); | 67 | FieldEntry fieldEntry = EntryFactory.getFieldEntry(field); |
| 75 | this.access.put(fieldEntry, Access.get(field)); | 68 | this.access.put(fieldEntry, Access.get(field)); |
| @@ -84,7 +77,6 @@ public class JarIndex { | |||
| 84 | 77 | ||
| 85 | // step 3: index extends, implements, fields, and methods | 78 | // step 3: index extends, implements, fields, and methods |
| 86 | for (CtClass c : JarClassIterator.classes(jar)) { | 79 | for (CtClass c : JarClassIterator.classes(jar)) { |
| 87 | ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NONE_PACKAGE); | ||
| 88 | this.translationIndex.indexClass(c); | 80 | this.translationIndex.indexClass(c); |
| 89 | String className = Descriptor.toJvmName(c.getName()); | 81 | String className = Descriptor.toJvmName(c.getName()); |
| 90 | for (String interfaceName : c.getClassFile().getInterfaces()) { | 82 | for (String interfaceName : c.getClassFile().getInterfaces()) { |
| @@ -101,7 +93,6 @@ public class JarIndex { | |||
| 101 | 93 | ||
| 102 | // step 4: index field, method, constructor references | 94 | // step 4: index field, method, constructor references |
| 103 | for (CtClass c : JarClassIterator.classes(jar)) { | 95 | for (CtClass c : JarClassIterator.classes(jar)) { |
| 104 | ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NONE_PACKAGE); | ||
| 105 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { | 96 | for (CtBehavior behavior : c.getDeclaredBehaviors()) { |
| 106 | indexBehaviorReferences(behavior); | 97 | indexBehaviorReferences(behavior); |
| 107 | } | 98 | } |
| @@ -111,7 +102,6 @@ public class JarIndex { | |||
| 111 | 102 | ||
| 112 | // step 5: index inner classes and anonymous classes | 103 | // step 5: index inner classes and anonymous classes |
| 113 | for (CtClass c : JarClassIterator.classes(jar)) { | 104 | for (CtClass c : JarClassIterator.classes(jar)) { |
| 114 | ClassRenamer.moveAllClassesOutOfDefaultPackage(c, Constants.NONE_PACKAGE); | ||
| 115 | ClassEntry innerClassEntry = EntryFactory.getClassEntry(c); | 105 | ClassEntry innerClassEntry = EntryFactory.getClassEntry(c); |
| 116 | ClassEntry outerClassEntry = findOuterClass(c); | 106 | ClassEntry outerClassEntry = findOuterClass(c); |
| 117 | if (outerClassEntry != null) { | 107 | if (outerClassEntry != null) { |
| @@ -781,6 +771,14 @@ public class JarIndex { | |||
| 781 | return this.access.containsKey(obfBehaviorEntry); | 771 | return this.access.containsKey(obfBehaviorEntry); |
| 782 | } | 772 | } |
| 783 | 773 | ||
| 774 | public boolean containsEntryWithSameName(Entry entry) | ||
| 775 | { | ||
| 776 | for (Entry target : this.access.keySet()) | ||
| 777 | if (target.getName().equals(entry.getName()) && entry.getClass().isInstance(target.getClass())) | ||
| 778 | return true; | ||
| 779 | return false; | ||
| 780 | } | ||
| 781 | |||
| 784 | public boolean containsObfArgument(ArgumentEntry obfArgumentEntry) { | 782 | public boolean containsObfArgument(ArgumentEntry obfArgumentEntry) { |
| 785 | // check the behavior | 783 | // check the behavior |
| 786 | if (!containsObfBehavior(obfArgumentEntry.getBehaviorEntry())) { | 784 | if (!containsObfBehavior(obfArgumentEntry.getBehaviorEntry())) { |
| @@ -801,6 +799,9 @@ public class JarIndex { | |||
| 801 | return containsObfBehavior((BehaviorEntry) obfEntry); | 799 | return containsObfBehavior((BehaviorEntry) obfEntry); |
| 802 | } else if (obfEntry instanceof ArgumentEntry) { | 800 | } else if (obfEntry instanceof ArgumentEntry) { |
| 803 | return containsObfArgument((ArgumentEntry) obfEntry); | 801 | return containsObfArgument((ArgumentEntry) obfEntry); |
| 802 | } else if (obfEntry instanceof LocalVariableEntry) { | ||
| 803 | // TODO: Implement it | ||
| 804 | return false; | ||
| 804 | } else { | 805 | } else { |
| 805 | throw new Error("Entry type not supported: " + obfEntry.getClass().getName()); | 806 | throw new Error("Entry type not supported: " + obfEntry.getClass().getName()); |
| 806 | } | 807 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java b/src/main/java/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java index c328f5f1..e690abdf 100644 --- a/src/main/java/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java +++ b/src/main/java/cuchaz/enigma/analysis/SourceIndexBehaviorVisitor.java | |||
| @@ -10,6 +10,9 @@ | |||
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | package cuchaz.enigma.analysis; | 11 | package cuchaz.enigma.analysis; |
| 12 | 12 | ||
| 13 | import com.google.common.collect.HashMultimap; | ||
| 14 | import com.google.common.collect.Multimap; | ||
| 15 | import com.google.common.collect.Multimaps; | ||
| 13 | import com.strobel.assembler.metadata.MemberReference; | 16 | import com.strobel.assembler.metadata.MemberReference; |
| 14 | import com.strobel.assembler.metadata.MethodReference; | 17 | import com.strobel.assembler.metadata.MethodReference; |
| 15 | import com.strobel.assembler.metadata.ParameterDefinition; | 18 | import com.strobel.assembler.metadata.ParameterDefinition; |
| @@ -17,6 +20,7 @@ import com.strobel.assembler.metadata.TypeReference; | |||
| 17 | import com.strobel.decompiler.languages.TextLocation; | 20 | import com.strobel.decompiler.languages.TextLocation; |
| 18 | import com.strobel.decompiler.languages.java.ast.*; | 21 | import com.strobel.decompiler.languages.java.ast.*; |
| 19 | import cuchaz.enigma.mapping.*; | 22 | import cuchaz.enigma.mapping.*; |
| 23 | import javassist.bytecode.Descriptor; | ||
| 20 | 24 | ||
| 21 | import java.util.HashMap; | 25 | import java.util.HashMap; |
| 22 | import java.util.Map; | 26 | import java.util.Map; |
| @@ -27,11 +31,14 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor { | |||
| 27 | 31 | ||
| 28 | // TODO: Really fix Procyon index problem with inner classes | 32 | // TODO: Really fix Procyon index problem with inner classes |
| 29 | private int argumentPosition; | 33 | private int argumentPosition; |
| 30 | private Map<String, Entry> argumentCache = new HashMap<>(); | 34 | private int localsPosition; |
| 35 | private Multimap<String, Identifier> unmatchedIdentifier = HashMultimap.create(); | ||
| 36 | private Map<String, Entry> identifierEntryCache = new HashMap<>(); | ||
| 31 | 37 | ||
| 32 | public SourceIndexBehaviorVisitor(BehaviorEntry behaviorEntry) { | 38 | public SourceIndexBehaviorVisitor(BehaviorEntry behaviorEntry) { |
| 33 | this.behaviorEntry = behaviorEntry; | 39 | this.behaviorEntry = behaviorEntry; |
| 34 | this.argumentPosition = 0; | 40 | this.argumentPosition = 0; |
| 41 | this.localsPosition = 0; | ||
| 35 | } | 42 | } |
| 36 | 43 | ||
| 37 | @Override | 44 | @Override |
| @@ -66,6 +73,9 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor { | |||
| 66 | } | 73 | } |
| 67 | } | 74 | } |
| 68 | 75 | ||
| 76 | // Check for identifier | ||
| 77 | node.getArguments().stream().filter(expression -> expression instanceof IdentifierExpression) | ||
| 78 | .forEach(expression -> this.checkIdentifier((IdentifierExpression) expression, index)); | ||
| 69 | return recurse(node, index); | 79 | return recurse(node, index); |
| 70 | } | 80 | } |
| 71 | 81 | ||
| @@ -106,7 +116,7 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor { | |||
| 106 | argumentPosition++, node.getName()); | 116 | argumentPosition++, node.getName()); |
| 107 | Identifier identifier = node.getNameToken(); | 117 | Identifier identifier = node.getNameToken(); |
| 108 | // cache the argument entry and the identifier | 118 | // cache the argument entry and the identifier |
| 109 | argumentCache.put(identifier.getName(), argumentEntry); | 119 | identifierEntryCache.put(identifier.getName(), argumentEntry); |
| 110 | index.addDeclaration(identifier, argumentEntry); | 120 | index.addDeclaration(identifier, argumentEntry); |
| 111 | } | 121 | } |
| 112 | 122 | ||
| @@ -121,12 +131,31 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor { | |||
| 121 | FieldEntry fieldEntry = new FieldEntry(classEntry, ref.getName(), new Type(ref.getErasedSignature())); | 131 | FieldEntry fieldEntry = new FieldEntry(classEntry, ref.getName(), new Type(ref.getErasedSignature())); |
| 122 | index.addReference(node.getIdentifierToken(), fieldEntry, this.behaviorEntry); | 132 | index.addReference(node.getIdentifierToken(), fieldEntry, this.behaviorEntry); |
| 123 | } | 133 | } |
| 124 | else if (argumentCache.containsKey(node.getIdentifier())) // If it's in the argument cache, create a token! | 134 | else |
| 125 | index.addDeclaration(node.getIdentifierToken(), argumentCache.get(node.getIdentifier())); | 135 | this.checkIdentifier(node, index); |
| 126 | |||
| 127 | return recurse(node, index); | 136 | return recurse(node, index); |
| 128 | } | 137 | } |
| 129 | 138 | ||
| 139 | private void checkIdentifier(IdentifierExpression node, SourceIndex index) | ||
| 140 | { | ||
| 141 | if (identifierEntryCache.containsKey(node.getIdentifier())) // If it's in the argument cache, create a token! | ||
| 142 | index.addDeclaration(node.getIdentifierToken(), identifierEntryCache.get(node.getIdentifier())); | ||
| 143 | else | ||
| 144 | unmatchedIdentifier.put(node.getIdentifier(), node.getIdentifierToken()); // Not matched actually, put it! | ||
| 145 | } | ||
| 146 | |||
| 147 | private void addDeclarationToUnmatched(String key, SourceIndex index) | ||
| 148 | { | ||
| 149 | Entry entry = identifierEntryCache.get(key); | ||
| 150 | |||
| 151 | // This cannot happened in theory | ||
| 152 | if (entry == null) | ||
| 153 | return; | ||
| 154 | for (Identifier identifier : unmatchedIdentifier.get(key)) | ||
| 155 | index.addDeclaration(identifier, entry); | ||
| 156 | unmatchedIdentifier.removeAll(key); | ||
| 157 | } | ||
| 158 | |||
| 130 | @Override | 159 | @Override |
| 131 | public Void visitObjectCreationExpression(ObjectCreationExpression node, SourceIndex index) { | 160 | public Void visitObjectCreationExpression(ObjectCreationExpression node, SourceIndex index) { |
| 132 | MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); | 161 | MemberReference ref = node.getUserData(Keys.MEMBER_REFERENCE); |
| @@ -141,4 +170,43 @@ public class SourceIndexBehaviorVisitor extends SourceIndexVisitor { | |||
| 141 | 170 | ||
| 142 | return recurse(node, index); | 171 | return recurse(node, index); |
| 143 | } | 172 | } |
| 173 | |||
| 174 | @Override | ||
| 175 | public Void visitForEachStatement(ForEachStatement node, SourceIndex index) { | ||
| 176 | if (node.getVariableType() instanceof SimpleType) | ||
| 177 | { | ||
| 178 | SimpleType type = (SimpleType) node.getVariableType(); | ||
| 179 | TypeReference typeReference = type.getUserData(Keys.TYPE_REFERENCE); | ||
| 180 | Identifier identifier = node.getVariableNameToken(); | ||
| 181 | String signature = Descriptor.of(typeReference.getErasedDescription()); | ||
| 182 | LocalVariableEntry localVariableEntry = new LocalVariableEntry(behaviorEntry, localsPosition++, identifier.getName(), new Type(signature)); | ||
| 183 | identifierEntryCache.put(identifier.getName(), localVariableEntry); | ||
| 184 | addDeclarationToUnmatched(identifier.getName(), index); | ||
| 185 | index.addDeclaration(identifier, localVariableEntry); | ||
| 186 | } | ||
| 187 | return recurse(node, index); | ||
| 188 | } | ||
| 189 | |||
| 190 | @Override | ||
| 191 | public Void visitVariableDeclaration(VariableDeclarationStatement node, SourceIndex index) { | ||
| 192 | AstNodeCollection<VariableInitializer> variables = node.getVariables(); | ||
| 193 | |||
| 194 | // Single assignation | ||
| 195 | if (variables.size() == 1) | ||
| 196 | { | ||
| 197 | VariableInitializer initializer = variables.firstOrNullObject(); | ||
| 198 | if (initializer != null && node.getType() instanceof SimpleType) | ||
| 199 | { | ||
| 200 | SimpleType type = (SimpleType) node.getType(); | ||
| 201 | TypeReference typeReference = type.getUserData(Keys.TYPE_REFERENCE); | ||
| 202 | String signature = Descriptor.of(typeReference.getErasedDescription()); | ||
| 203 | Identifier identifier = initializer.getNameToken(); | ||
| 204 | LocalVariableEntry localVariableEntry = new LocalVariableEntry(behaviorEntry, localsPosition++, initializer.getName(), new Type(signature)); | ||
| 205 | identifierEntryCache.put(identifier.getName(), localVariableEntry); | ||
| 206 | addDeclarationToUnmatched(identifier.getName(), index); | ||
| 207 | index.addDeclaration(identifier, localVariableEntry); | ||
| 208 | } | ||
| 209 | } | ||
| 210 | return recurse(node, index); | ||
| 211 | } | ||
| 144 | } | 212 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java b/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java index 25edaef4..d51131f6 100644 --- a/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java +++ b/src/main/java/cuchaz/enigma/analysis/TranslationIndex.java | |||
| @@ -181,6 +181,8 @@ public class TranslationIndex { | |||
| 181 | return behaviorExists((BehaviorEntry) entry); | 181 | return behaviorExists((BehaviorEntry) entry); |
| 182 | } else if (entry instanceof ArgumentEntry) { | 182 | } else if (entry instanceof ArgumentEntry) { |
| 183 | return behaviorExists(((ArgumentEntry) entry).getBehaviorEntry()); | 183 | return behaviorExists(((ArgumentEntry) entry).getBehaviorEntry()); |
| 184 | } else if (entry instanceof LocalVariableEntry) { | ||
| 185 | return behaviorExists(((LocalVariableEntry) entry).getBehaviorEntry()); | ||
| 184 | } | 186 | } |
| 185 | throw new IllegalArgumentException("Cannot check existence for " + entry.getClass()); | 187 | throw new IllegalArgumentException("Cannot check existence for " + entry.getClass()); |
| 186 | } | 188 | } |
diff --git a/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java b/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java index eb7e9a17..d49f13ab 100644 --- a/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java +++ b/src/main/java/cuchaz/enigma/bytecode/ClassRenamer.java | |||
| @@ -19,8 +19,9 @@ import java.util.Map; | |||
| 19 | 19 | ||
| 20 | import cuchaz.enigma.mapping.ClassEntry; | 20 | import cuchaz.enigma.mapping.ClassEntry; |
| 21 | import cuchaz.enigma.mapping.ClassNameReplacer; | 21 | import cuchaz.enigma.mapping.ClassNameReplacer; |
| 22 | import cuchaz.enigma.mapping.Mappings; | ||
| 22 | import cuchaz.enigma.mapping.Translator; | 23 | import cuchaz.enigma.mapping.Translator; |
| 23 | import javassist.CtClass; | 24 | import javassist.*; |
| 24 | import javassist.bytecode.*; | 25 | import javassist.bytecode.*; |
| 25 | import javassist.bytecode.SignatureAttribute.*; | 26 | import javassist.bytecode.SignatureAttribute.*; |
| 26 | 27 | ||
| @@ -70,6 +71,41 @@ public class ClassRenamer { | |||
| 70 | } | 71 | } |
| 71 | } | 72 | } |
| 72 | 73 | ||
| 74 | public static void applyModifier(Object obj, Mappings.EntryModifier modifier) | ||
| 75 | { | ||
| 76 | int mod = -1; | ||
| 77 | if (obj instanceof CtField) | ||
| 78 | mod = ((CtField) obj).getModifiers(); | ||
| 79 | else if (obj instanceof CtBehavior) | ||
| 80 | mod = ((CtBehavior) obj).getModifiers(); | ||
| 81 | else if (obj instanceof CtClass) | ||
| 82 | mod = ((CtClass) obj).getModifiers(); | ||
| 83 | |||
| 84 | if (mod != -1) | ||
| 85 | { | ||
| 86 | switch (modifier) | ||
| 87 | { | ||
| 88 | case PRIVATE: | ||
| 89 | mod = Modifier.setPrivate(mod); | ||
| 90 | break; | ||
| 91 | case PROTECTED: | ||
| 92 | mod = Modifier.setProtected(mod); | ||
| 93 | break; | ||
| 94 | case PUBLIC: | ||
| 95 | mod = Modifier.setPublic(mod); | ||
| 96 | break; | ||
| 97 | default: | ||
| 98 | break; | ||
| 99 | } | ||
| 100 | if (obj instanceof CtField) | ||
| 101 | ((CtField) obj).setModifiers(mod); | ||
| 102 | else if (obj instanceof CtBehavior) | ||
| 103 | ((CtBehavior) obj).setModifiers(mod); | ||
| 104 | else | ||
| 105 | ((CtClass) obj).setModifiers(mod); | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 73 | public static void renameClasses(CtClass c, final Translator translator) { | 109 | public static void renameClasses(CtClass c, final Translator translator) { |
| 74 | renameClasses(c, className -> { | 110 | renameClasses(c, className -> { |
| 75 | ClassEntry entry = translator.translateEntry(new ClassEntry(className)); | 111 | ClassEntry entry = translator.translateEntry(new ClassEntry(className)); |
| @@ -110,6 +146,7 @@ public class ClassRenamer { | |||
| 110 | 146 | ||
| 111 | // rename the constant pool (covers ClassInfo, MethodTypeInfo, and NameAndTypeInfo) | 147 | // rename the constant pool (covers ClassInfo, MethodTypeInfo, and NameAndTypeInfo) |
| 112 | ConstPool constPool = c.getClassFile().getConstPool(); | 148 | ConstPool constPool = c.getClassFile().getConstPool(); |
| 149 | String className = constPool.getClassName(); | ||
| 113 | constPool.renameClass(map); | 150 | constPool.renameClass(map); |
| 114 | 151 | ||
| 115 | // rename class attributes | 152 | // rename class attributes |
| @@ -140,8 +177,9 @@ public class ClassRenamer { | |||
| 140 | if (attr != null) { | 177 | if (attr != null) { |
| 141 | for (int i = 0; i < attr.tableLength(); i++) { | 178 | for (int i = 0; i < attr.tableLength(); i++) { |
| 142 | 179 | ||
| 180 | String innerName = attr.innerClass(i); | ||
| 143 | // get the inner class full name (which has already been translated) | 181 | // get the inner class full name (which has already been translated) |
| 144 | ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(attr.innerClass(i))); | 182 | ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(innerName)); |
| 145 | 183 | ||
| 146 | if (attr.innerNameIndex(i) != 0) { | 184 | if (attr.innerNameIndex(i) != 0) { |
| 147 | // update the inner name | 185 | // update the inner name |
diff --git a/src/main/java/cuchaz/enigma/bytecode/ClassTranslator.java b/src/main/java/cuchaz/enigma/bytecode/ClassTranslator.java index 6c05b838..62ebfafb 100644 --- a/src/main/java/cuchaz/enigma/bytecode/ClassTranslator.java +++ b/src/main/java/cuchaz/enigma/bytecode/ClassTranslator.java | |||
| @@ -11,14 +11,9 @@ | |||
| 11 | package cuchaz.enigma.bytecode; | 11 | package cuchaz.enigma.bytecode; |
| 12 | 12 | ||
| 13 | import cuchaz.enigma.mapping.*; | 13 | import cuchaz.enigma.mapping.*; |
| 14 | import javassist.CtBehavior; | 14 | import cuchaz.enigma.mapping.Translator; |
| 15 | import javassist.CtClass; | 15 | import javassist.*; |
| 16 | import javassist.CtField; | 16 | import javassist.bytecode.*; |
| 17 | import javassist.CtMethod; | ||
| 18 | import javassist.bytecode.ConstPool; | ||
| 19 | import javassist.bytecode.Descriptor; | ||
| 20 | import javassist.bytecode.EnclosingMethodAttribute; | ||
| 21 | import javassist.bytecode.SourceFileAttribute; | ||
| 22 | 17 | ||
| 23 | public class ClassTranslator { | 18 | public class ClassTranslator { |
| 24 | 19 | ||
| @@ -74,6 +69,9 @@ public class ClassTranslator { | |||
| 74 | } | 69 | } |
| 75 | 70 | ||
| 76 | ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); | 71 | ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); |
| 72 | Mappings.EntryModifier modifier = this.translator.getModifier(classEntry); | ||
| 73 | if (modifier != null && modifier != Mappings.EntryModifier.UNCHANGED) | ||
| 74 | ClassRenamer.applyModifier(c, modifier); | ||
| 77 | 75 | ||
| 78 | // translate all the fields | 76 | // translate all the fields |
| 79 | for (CtField field : c.getDeclaredFields()) { | 77 | for (CtField field : c.getDeclaredFields()) { |
| @@ -81,6 +79,10 @@ public class ClassTranslator { | |||
| 81 | // translate the name | 79 | // translate the name |
| 82 | FieldEntry entry = EntryFactory.getFieldEntry(field); | 80 | FieldEntry entry = EntryFactory.getFieldEntry(field); |
| 83 | String translatedName = this.translator.translate(entry); | 81 | String translatedName = this.translator.translate(entry); |
| 82 | modifier = this.translator.getModifier(entry); | ||
| 83 | if (modifier != null && modifier != Mappings.EntryModifier.UNCHANGED) | ||
| 84 | ClassRenamer.applyModifier(field, modifier); | ||
| 85 | |||
| 84 | if (translatedName != null) { | 86 | if (translatedName != null) { |
| 85 | field.setName(translatedName); | 87 | field.setName(translatedName); |
| 86 | } | 88 | } |
| @@ -95,6 +97,10 @@ public class ClassTranslator { | |||
| 95 | 97 | ||
| 96 | BehaviorEntry entry = EntryFactory.getBehaviorEntry(behavior); | 98 | BehaviorEntry entry = EntryFactory.getBehaviorEntry(behavior); |
| 97 | 99 | ||
| 100 | modifier = this.translator.getModifier(entry); | ||
| 101 | if (modifier != null && modifier != Mappings.EntryModifier.UNCHANGED) | ||
| 102 | ClassRenamer.applyModifier(behavior, modifier); | ||
| 103 | |||
| 98 | if (behavior instanceof CtMethod) { | 104 | if (behavior instanceof CtMethod) { |
| 99 | CtMethod method = (CtMethod) behavior; | 105 | CtMethod method = (CtMethod) behavior; |
| 100 | 106 | ||
| @@ -149,5 +155,8 @@ public class ClassTranslator { | |||
| 149 | String sourceFile = Descriptor.toJvmName(deobfClassEntry.getOutermostClassEntry().getSimpleName()) + ".java"; | 155 | String sourceFile = Descriptor.toJvmName(deobfClassEntry.getOutermostClassEntry().getSimpleName()) + ".java"; |
| 150 | c.getClassFile().addAttribute(new SourceFileAttribute(constants, sourceFile)); | 156 | c.getClassFile().addAttribute(new SourceFileAttribute(constants, sourceFile)); |
| 151 | } | 157 | } |
| 158 | InnerClassesAttribute attr = (InnerClassesAttribute) c.getClassFile().getAttribute(InnerClassesAttribute.tag); | ||
| 159 | if (attr != null) | ||
| 160 | InnerClassWriter.changeModifier(c, attr, translator); | ||
| 152 | } | 161 | } |
| 153 | } | 162 | } |
diff --git a/src/main/java/cuchaz/enigma/bytecode/InnerClassWriter.java b/src/main/java/cuchaz/enigma/bytecode/InnerClassWriter.java index 6d926106..6e2a29d5 100644 --- a/src/main/java/cuchaz/enigma/bytecode/InnerClassWriter.java +++ b/src/main/java/cuchaz/enigma/bytecode/InnerClassWriter.java | |||
| @@ -15,22 +15,22 @@ import com.google.common.collect.Lists; | |||
| 15 | import java.util.Collection; | 15 | import java.util.Collection; |
| 16 | import java.util.List; | 16 | import java.util.List; |
| 17 | 17 | ||
| 18 | import cuchaz.enigma.Deobfuscator; | ||
| 18 | import cuchaz.enigma.analysis.JarIndex; | 19 | import cuchaz.enigma.analysis.JarIndex; |
| 19 | import cuchaz.enigma.mapping.BehaviorEntry; | 20 | import cuchaz.enigma.mapping.*; |
| 20 | import cuchaz.enigma.mapping.ClassEntry; | 21 | import javassist.ClassPool; |
| 21 | import cuchaz.enigma.mapping.EntryFactory; | ||
| 22 | import javassist.CtClass; | 22 | import javassist.CtClass; |
| 23 | import javassist.bytecode.AccessFlag; | 23 | import javassist.NotFoundException; |
| 24 | import javassist.bytecode.ConstPool; | 24 | import javassist.bytecode.*; |
| 25 | import javassist.bytecode.EnclosingMethodAttribute; | ||
| 26 | import javassist.bytecode.InnerClassesAttribute; | ||
| 27 | 25 | ||
| 28 | public class InnerClassWriter { | 26 | public class InnerClassWriter { |
| 29 | 27 | ||
| 30 | private JarIndex index; | 28 | private JarIndex index; |
| 29 | private Translator deobfuscatorTranslator; | ||
| 31 | 30 | ||
| 32 | public InnerClassWriter(JarIndex index) { | 31 | public InnerClassWriter(JarIndex index, Translator deobfuscatorTranslator) { |
| 33 | this.index = index; | 32 | this.index = index; |
| 33 | this.deobfuscatorTranslator = deobfuscatorTranslator; | ||
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | public void write(CtClass c) { | 36 | public void write(CtClass c) { |
| @@ -96,6 +96,29 @@ public class InnerClassWriter { | |||
| 96 | } | 96 | } |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | // FIXME: modiffier is not applied to inner class | ||
| 100 | public static void changeModifier(CtClass c, InnerClassesAttribute attr, Translator translator) | ||
| 101 | { | ||
| 102 | ClassPool pool = c.getClassPool(); | ||
| 103 | for (int i = 0; i < attr.tableLength(); i++) { | ||
| 104 | |||
| 105 | String innerName = attr.innerClass(i); | ||
| 106 | // get the inner class full name (which has already been translated) | ||
| 107 | ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(innerName)); | ||
| 108 | try | ||
| 109 | { | ||
| 110 | CtClass innerClass = pool.get(innerName); | ||
| 111 | Mappings.EntryModifier modifier = translator.getModifier(classEntry); | ||
| 112 | if (modifier != null && modifier != Mappings.EntryModifier.UNCHANGED) | ||
| 113 | ClassRenamer.applyModifier(innerClass, modifier); | ||
| 114 | } catch (NotFoundException e) | ||
| 115 | { | ||
| 116 | // This shouldn't be possible in theory | ||
| 117 | //e.printStackTrace(); | ||
| 118 | } | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 99 | private void writeInnerClass(InnerClassesAttribute attr, List<ClassEntry> obfClassChain, ClassEntry obfClassEntry) { | 122 | private void writeInnerClass(InnerClassesAttribute attr, List<ClassEntry> obfClassChain, ClassEntry obfClassEntry) { |
| 100 | 123 | ||
| 101 | // get the new inner class name | 124 | // get the new inner class name |
diff --git a/src/main/java/cuchaz/enigma/bytecode/LocalVariableRenamer.java b/src/main/java/cuchaz/enigma/bytecode/LocalVariableRenamer.java index 3f4b96f9..24b5f363 100644 --- a/src/main/java/cuchaz/enigma/bytecode/LocalVariableRenamer.java +++ b/src/main/java/cuchaz/enigma/bytecode/LocalVariableRenamer.java | |||
| @@ -76,11 +76,27 @@ public class LocalVariableRenamer { | |||
| 76 | int numArgs = 0; | 76 | int numArgs = 0; |
| 77 | if (behaviorEntry.getSignature() != null) { | 77 | if (behaviorEntry.getSignature() != null) { |
| 78 | numArgs = behaviorEntry.getSignature().getArgumentTypes().size(); | 78 | numArgs = behaviorEntry.getSignature().getArgumentTypes().size(); |
| 79 | |||
| 80 | boolean isNestedClassConstructor = false; | ||
| 81 | |||
| 82 | // If the behavior is a constructor and if it have more than one arg, it's probably from a nested! | ||
| 83 | if (behaviorEntry instanceof ConstructorEntry && behaviorEntry.getClassEntry() != null && behaviorEntry.getClassEntry().isInnerClass() && numArgs >= 1) | ||
| 84 | { | ||
| 85 | // Get the first arg type | ||
| 86 | Type firstArg = behaviorEntry.getSignature().getArgumentTypes().get(0); | ||
| 87 | |||
| 88 | // If the arg is a class and if the class name match the outer class name of the constructor, it's definitely a constructor of a nested class | ||
| 89 | if (firstArg.isClass() && firstArg.getClassEntry().equals(behaviorEntry.getClassEntry().getOuterClassEntry())) { | ||
| 90 | isNestedClassConstructor = true; | ||
| 91 | numArgs--; | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 79 | for (int i = starti; i < starti + numArgs && i < table.tableLength(); i++) { | 95 | for (int i = starti; i < starti + numArgs && i < table.tableLength(); i++) { |
| 80 | int argi = i - starti; | 96 | int argi = i - starti; |
| 81 | String argName = this.translator.translate(new ArgumentEntry(behaviorEntry, argi, "")); | 97 | String argName = this.translator.translate(new ArgumentEntry(behaviorEntry, argi, "")); |
| 82 | if (argName == null) { | 98 | if (argName == null) { |
| 83 | Type argType = behaviorEntry.getSignature().getArgumentTypes().get(argi); | 99 | Type argType = behaviorEntry.getSignature().getArgumentTypes().get(isNestedClassConstructor ? argi + 1 : argi); |
| 84 | // Unfortunately each of these have different name getters, so they have different code paths | 100 | // Unfortunately each of these have different name getters, so they have different code paths |
| 85 | if (argType.isPrimitive()) { | 101 | if (argType.isPrimitive()) { |
| 86 | Type.Primitive argCls = argType.getPrimitive(); | 102 | Type.Primitive argCls = argType.getPrimitive(); |
diff --git a/src/main/java/cuchaz/enigma/convert/ClassIdentity.java b/src/main/java/cuchaz/enigma/convert/ClassIdentity.java index 0960c86b..73600114 100644 --- a/src/main/java/cuchaz/enigma/convert/ClassIdentity.java +++ b/src/main/java/cuchaz/enigma/convert/ClassIdentity.java | |||
| @@ -58,7 +58,7 @@ public class ClassIdentity { | |||
| 58 | 58 | ||
| 59 | // classes not in the none package can be passed through | 59 | // classes not in the none package can be passed through |
| 60 | ClassEntry classEntry = new ClassEntry(className); | 60 | ClassEntry classEntry = new ClassEntry(className); |
| 61 | if (!classEntry.getPackageName().equals(Constants.NONE_PACKAGE)) { | 61 | if (classEntry.getPackageName() != null) { |
| 62 | return className; | 62 | return className; |
| 63 | } | 63 | } |
| 64 | 64 | ||
diff --git a/src/main/java/cuchaz/enigma/convert/MappingsConverter.java b/src/main/java/cuchaz/enigma/convert/MappingsConverter.java index 3d2cb86a..929c89f2 100644 --- a/src/main/java/cuchaz/enigma/convert/MappingsConverter.java +++ b/src/main/java/cuchaz/enigma/convert/MappingsConverter.java | |||
| @@ -243,7 +243,7 @@ public class MappingsConverter { | |||
| 243 | 243 | ||
| 244 | // non obfuscated classes can be migrated | 244 | // non obfuscated classes can be migrated |
| 245 | ClassEntry classEntry = oldObfType.getClassEntry(); | 245 | ClassEntry classEntry = oldObfType.getClassEntry(); |
| 246 | if (!classEntry.getPackageName().equals(Constants.NONE_PACKAGE)) { | 246 | if (classEntry.getPackageName() != null) { |
| 247 | return true; | 247 | return true; |
| 248 | } | 248 | } |
| 249 | 249 | ||
diff --git a/src/main/java/cuchaz/enigma/gui/ClassMatchingGui.java b/src/main/java/cuchaz/enigma/gui/ClassMatchingGui.java index 3cd1705a..edf1e30b 100644 --- a/src/main/java/cuchaz/enigma/gui/ClassMatchingGui.java +++ b/src/main/java/cuchaz/enigma/gui/ClassMatchingGui.java | |||
| @@ -131,7 +131,7 @@ public class ClassMatchingGui { | |||
| 131 | sourceTypePanel.add(button); | 131 | sourceTypePanel.add(button); |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | m_sourceClasses = new ClassSelector(null, ClassSelector.DEOBF_CLASS_COMPARATOR); | 134 | m_sourceClasses = new ClassSelector(null, ClassSelector.DEOBF_CLASS_COMPARATOR, false); |
| 135 | m_sourceClasses.setSelectionListener(this::setSourceClass); | 135 | m_sourceClasses.setSelectionListener(this::setSourceClass); |
| 136 | JScrollPane sourceScroller = new JScrollPane(m_sourceClasses); | 136 | JScrollPane sourceScroller = new JScrollPane(m_sourceClasses); |
| 137 | sourcePanel.add(sourceScroller); | 137 | sourcePanel.add(sourceScroller); |
| @@ -147,7 +147,7 @@ public class ClassMatchingGui { | |||
| 147 | destPanel.add(m_top10Matches); | 147 | destPanel.add(m_top10Matches); |
| 148 | m_top10Matches.addActionListener(event -> toggleTop10Matches()); | 148 | m_top10Matches.addActionListener(event -> toggleTop10Matches()); |
| 149 | 149 | ||
| 150 | m_destClasses = new ClassSelector(null, ClassSelector.DEOBF_CLASS_COMPARATOR); | 150 | m_destClasses = new ClassSelector(null, ClassSelector.DEOBF_CLASS_COMPARATOR, false); |
| 151 | m_destClasses.setSelectionListener(this::setDestClass); | 151 | m_destClasses.setSelectionListener(this::setDestClass); |
| 152 | JScrollPane destScroller = new JScrollPane(m_destClasses); | 152 | JScrollPane destScroller = new JScrollPane(m_destClasses); |
| 153 | destPanel.add(destScroller); | 153 | destPanel.add(destScroller); |
diff --git a/src/main/java/cuchaz/enigma/gui/ClassSelector.java b/src/main/java/cuchaz/enigma/gui/ClassSelector.java index 92fcaba0..435509e5 100644 --- a/src/main/java/cuchaz/enigma/gui/ClassSelector.java +++ b/src/main/java/cuchaz/enigma/gui/ClassSelector.java | |||
| @@ -44,7 +44,7 @@ public class ClassSelector extends JTree { | |||
| 44 | private RenameSelectionListener renameSelectionListener; | 44 | private RenameSelectionListener renameSelectionListener; |
| 45 | private Comparator<ClassEntry> comparator; | 45 | private Comparator<ClassEntry> comparator; |
| 46 | 46 | ||
| 47 | public ClassSelector(Gui gui, Comparator<ClassEntry> comparator) { | 47 | public ClassSelector(Gui gui, Comparator<ClassEntry> comparator, boolean isRenamable) { |
| 48 | this.comparator = comparator; | 48 | this.comparator = comparator; |
| 49 | 49 | ||
| 50 | // configure the tree control | 50 | // configure the tree control |
| @@ -77,7 +77,7 @@ public class ClassSelector extends JTree { | |||
| 77 | { | 77 | { |
| 78 | @Override public boolean isCellEditable(EventObject event) | 78 | @Override public boolean isCellEditable(EventObject event) |
| 79 | { | 79 | { |
| 80 | return !(event instanceof MouseEvent) && super.isCellEditable(event); | 80 | return isRenamable && !(event instanceof MouseEvent) && super.isCellEditable(event); |
| 81 | } | 81 | } |
| 82 | }; | 82 | }; |
| 83 | this.setCellEditor(editor); | 83 | this.setCellEditor(editor); |
| @@ -112,7 +112,7 @@ public class ClassSelector extends JTree { | |||
| 112 | try | 112 | try |
| 113 | { | 113 | { |
| 114 | renameSelectionListener.onSelectionRename(node.getUserObject(), objectData, node); | 114 | renameSelectionListener.onSelectionRename(node.getUserObject(), objectData, node); |
| 115 | node.setUserObject(objectData); | 115 | node.setUserObject(objectData); // Make sure that it's modified |
| 116 | } catch (IllegalNameException ex) | 116 | } catch (IllegalNameException ex) |
| 117 | { | 117 | { |
| 118 | JOptionPane.showOptionDialog(gui.getFrame(), ex.getMessage(), "Enigma - Error", JOptionPane.OK_OPTION, | 118 | JOptionPane.showOptionDialog(gui.getFrame(), ex.getMessage(), "Enigma - Error", JOptionPane.OK_OPTION, |
| @@ -181,6 +181,10 @@ public class ClassSelector extends JTree { | |||
| 181 | // I can never keep this rule straight when writing these damn things... | 181 | // I can never keep this rule straight when writing these damn things... |
| 182 | // a < b => -1, a == b => 0, a > b => +1 | 182 | // a < b => -1, a == b => 0, a > b => +1 |
| 183 | 183 | ||
| 184 | if(b == null || a == null){ | ||
| 185 | return 0; | ||
| 186 | } | ||
| 187 | |||
| 184 | String[] aparts = a.split("/"); | 188 | String[] aparts = a.split("/"); |
| 185 | String[] bparts = b.split("/"); | 189 | String[] bparts = b.split("/"); |
| 186 | for (int i = 0; true; i++) { | 190 | for (int i = 0; true; i++) { |
| @@ -447,6 +451,51 @@ public class ClassSelector extends JTree { | |||
| 447 | model.insertNodeInto(classNode, packageNode, getPlacementIndex(packageNode, classNode)); | 451 | model.insertNodeInto(classNode, packageNode, getPlacementIndex(packageNode, classNode)); |
| 448 | } | 452 | } |
| 449 | 453 | ||
| 454 | public void reload() | ||
| 455 | { | ||
| 456 | DefaultTreeModel model = (DefaultTreeModel) getModel(); | ||
| 457 | model.reload(sort(rootNodes)); | ||
| 458 | } | ||
| 459 | |||
| 460 | private DefaultMutableTreeNode sort(DefaultMutableTreeNode node) { | ||
| 461 | |||
| 462 | for(int i = 0; i < node.getChildCount() - 1; i++) { | ||
| 463 | DefaultMutableTreeNode child = (DefaultMutableTreeNode) node.getChildAt(i); | ||
| 464 | if (child == null) | ||
| 465 | continue; | ||
| 466 | String nt = child.toString(); | ||
| 467 | |||
| 468 | for(int j = i + 1; j <= node.getChildCount() - 1; j++) { | ||
| 469 | DefaultMutableTreeNode prevNode = (DefaultMutableTreeNode) node.getChildAt(j); | ||
| 470 | if (prevNode == null || prevNode.getUserObject() == null) | ||
| 471 | continue; | ||
| 472 | String np = prevNode.getUserObject().toString(); | ||
| 473 | |||
| 474 | if(nt.compareToIgnoreCase(np) > 0) { | ||
| 475 | node.insert(child, j); | ||
| 476 | node.insert(prevNode, i); | ||
| 477 | } | ||
| 478 | } | ||
| 479 | if(child.getChildCount() > 0) { | ||
| 480 | sort(child); | ||
| 481 | } | ||
| 482 | } | ||
| 483 | |||
| 484 | for(int i = 0; i < node.getChildCount() - 1; i++) { | ||
| 485 | DefaultMutableTreeNode child = (DefaultMutableTreeNode) node.getChildAt(i); | ||
| 486 | for(int j = i + 1; j <= node.getChildCount() - 1; j++) { | ||
| 487 | DefaultMutableTreeNode prevNode = (DefaultMutableTreeNode) node.getChildAt(j); | ||
| 488 | |||
| 489 | if(!prevNode.isLeaf() && child.isLeaf()) { | ||
| 490 | node.insert(child, j); | ||
| 491 | node.insert(prevNode, i); | ||
| 492 | } | ||
| 493 | } | ||
| 494 | } | ||
| 495 | |||
| 496 | return node; | ||
| 497 | } | ||
| 498 | |||
| 450 | private int getPlacementIndex(ClassSelectorPackageNode newPackageNode, ClassSelectorClassNode classNode) | 499 | private int getPlacementIndex(ClassSelectorPackageNode newPackageNode, ClassSelectorClassNode classNode) |
| 451 | { | 500 | { |
| 452 | List<ClassSelectorClassNode> classNodes = classNodes(newPackageNode); | 501 | List<ClassSelectorClassNode> classNodes = classNodes(newPackageNode); |
diff --git a/src/main/java/cuchaz/enigma/gui/Gui.java b/src/main/java/cuchaz/enigma/gui/Gui.java index 0ccb3f79..ed18777a 100644 --- a/src/main/java/cuchaz/enigma/gui/Gui.java +++ b/src/main/java/cuchaz/enigma/gui/Gui.java | |||
| @@ -136,6 +136,9 @@ public class Gui { | |||
| 136 | m_selectionHighlightPainter = new SelectionHighlightPainter(); | 136 | m_selectionHighlightPainter = new SelectionHighlightPainter(); |
| 137 | this.editor = new PanelEditor(this); | 137 | this.editor = new PanelEditor(this); |
| 138 | JScrollPane sourceScroller = new JScrollPane(this.editor); | 138 | JScrollPane sourceScroller = new JScrollPane(this.editor); |
| 139 | this.editor.setContentType("text/java"); | ||
| 140 | DefaultSyntaxKit kit = (DefaultSyntaxKit) this.editor.getEditorKit(); | ||
| 141 | kit.toggleComponent(this.editor, "de.sciss.syntaxpane.components.TokenMarker"); | ||
| 139 | 142 | ||
| 140 | // init editor popup menu | 143 | // init editor popup menu |
| 141 | this.popupMenu = new PopupMenuBar(this); | 144 | this.popupMenu = new PopupMenuBar(this); |
| @@ -439,6 +442,8 @@ public class Gui { | |||
| 439 | showConstructorEntry((ConstructorEntry) m_reference.entry); | 442 | showConstructorEntry((ConstructorEntry) m_reference.entry); |
| 440 | } else if (m_reference.entry instanceof ArgumentEntry) { | 443 | } else if (m_reference.entry instanceof ArgumentEntry) { |
| 441 | showArgumentEntry((ArgumentEntry) m_reference.entry); | 444 | showArgumentEntry((ArgumentEntry) m_reference.entry); |
| 445 | } else if (m_reference.entry instanceof LocalVariableEntry) { | ||
| 446 | showLocalVariableEntry((LocalVariableEntry) m_reference.entry); | ||
| 442 | } else { | 447 | } else { |
| 443 | throw new Error("Unknown entry type: " + m_reference.entry.getClass().getName()); | 448 | throw new Error("Unknown entry type: " + m_reference.entry.getClass().getName()); |
| 444 | } | 449 | } |
| @@ -446,26 +451,39 @@ public class Gui { | |||
| 446 | redraw(); | 451 | redraw(); |
| 447 | } | 452 | } |
| 448 | 453 | ||
| 454 | private void showLocalVariableEntry(LocalVariableEntry entry) { | ||
| 455 | addNameValue(m_infoPanel, "Variable", entry.getName()); | ||
| 456 | addNameValue(m_infoPanel, "Class", entry.getClassEntry().getName()); | ||
| 457 | addNameValue(m_infoPanel, "Method", entry.getBehaviorEntry().getName()); | ||
| 458 | addNameValue(m_infoPanel, "Index", Integer.toString(entry.getIndex())); | ||
| 459 | addNameValue(m_infoPanel, "Type", entry.getType().toString()); | ||
| 460 | } | ||
| 461 | |||
| 449 | private void showClassEntry(ClassEntry entry) { | 462 | private void showClassEntry(ClassEntry entry) { |
| 450 | addNameValue(m_infoPanel, "Class", entry.getName()); | 463 | addNameValue(m_infoPanel, "Class", entry.getName()); |
| 464 | addModifierComboBox(m_infoPanel, "Modifier", entry); | ||
| 451 | } | 465 | } |
| 452 | 466 | ||
| 453 | private void showFieldEntry(FieldEntry entry) { | 467 | private void showFieldEntry(FieldEntry entry) { |
| 454 | addNameValue(m_infoPanel, "Field", entry.getName()); | 468 | addNameValue(m_infoPanel, "Field", entry.getName()); |
| 455 | addNameValue(m_infoPanel, "Class", entry.getClassEntry().getName()); | 469 | addNameValue(m_infoPanel, "Class", entry.getClassEntry().getName()); |
| 456 | addNameValue(m_infoPanel, "Type", entry.getType().toString()); | 470 | addNameValue(m_infoPanel, "Type", entry.getType().toString()); |
| 471 | addModifierComboBox(m_infoPanel, "Modifier", entry); | ||
| 457 | } | 472 | } |
| 458 | 473 | ||
| 459 | private void showMethodEntry(MethodEntry entry) { | 474 | private void showMethodEntry(MethodEntry entry) { |
| 460 | addNameValue(m_infoPanel, "Method", entry.getName()); | 475 | addNameValue(m_infoPanel, "Method", entry.getName()); |
| 461 | addNameValue(m_infoPanel, "Class", entry.getClassEntry().getName()); | 476 | addNameValue(m_infoPanel, "Class", entry.getClassEntry().getName()); |
| 462 | addNameValue(m_infoPanel, "Signature", entry.getSignature().toString()); | 477 | addNameValue(m_infoPanel, "Signature", entry.getSignature().toString()); |
| 478 | addModifierComboBox(m_infoPanel, "Modifier", entry); | ||
| 479 | |||
| 463 | } | 480 | } |
| 464 | 481 | ||
| 465 | private void showConstructorEntry(ConstructorEntry entry) { | 482 | private void showConstructorEntry(ConstructorEntry entry) { |
| 466 | addNameValue(m_infoPanel, "Constructor", entry.getClassEntry().getName()); | 483 | addNameValue(m_infoPanel, "Constructor", entry.getClassEntry().getName()); |
| 467 | if (!entry.isStatic()) { | 484 | if (!entry.isStatic()) { |
| 468 | addNameValue(m_infoPanel, "Signature", entry.getSignature().toString()); | 485 | addNameValue(m_infoPanel, "Signature", entry.getSignature().toString()); |
| 486 | addModifierComboBox(m_infoPanel, "Modifier", entry); | ||
| 469 | } | 487 | } |
| 470 | } | 488 | } |
| 471 | 489 | ||
| @@ -488,6 +506,25 @@ public class Gui { | |||
| 488 | panel.add(Utils.unboldLabel(new JLabel(value, JLabel.LEFT))); | 506 | panel.add(Utils.unboldLabel(new JLabel(value, JLabel.LEFT))); |
| 489 | } | 507 | } |
| 490 | 508 | ||
| 509 | private JComboBox<Mappings.EntryModifier> addModifierComboBox(JPanel container, String name, Entry entry) | ||
| 510 | { | ||
| 511 | if (!getController().entryIsInJar(entry)) | ||
| 512 | return null; | ||
| 513 | JPanel panel = new JPanel(); | ||
| 514 | panel.setLayout(new FlowLayout(FlowLayout.LEFT, 6, 0)); | ||
| 515 | container.add(panel); | ||
| 516 | JLabel label = new JLabel(name + ":", JLabel.RIGHT); | ||
| 517 | label.setPreferredSize(new Dimension(100, label.getPreferredSize().height)); | ||
| 518 | panel.add(label); | ||
| 519 | JComboBox<Mappings.EntryModifier> combo = new JComboBox<>(Mappings.EntryModifier.values()); | ||
| 520 | ((JLabel)combo.getRenderer()).setHorizontalAlignment(JLabel.LEFT); | ||
| 521 | combo.setPreferredSize(new Dimension(100, label.getPreferredSize().height)); | ||
| 522 | combo.setSelectedIndex(getController().getDeobfuscator().getModifier(entry).ordinal()); | ||
| 523 | combo.addItemListener(getController()::modifierChange); | ||
| 524 | panel.add(combo); | ||
| 525 | return combo; | ||
| 526 | } | ||
| 527 | |||
| 491 | public void onCaretMove(int pos) { | 528 | public void onCaretMove(int pos) { |
| 492 | 529 | ||
| 493 | Token token = this.controller.getToken(pos); | 530 | Token token = this.controller.getToken(pos); |
| @@ -574,8 +611,7 @@ public class Gui { | |||
| 574 | 611 | ||
| 575 | int offset = text.getText().lastIndexOf('/') + 1; | 612 | int offset = text.getText().lastIndexOf('/') + 1; |
| 576 | // If it's a class and isn't in the default package, assume that it's deobfuscated. | 613 | // If it's a class and isn't in the default package, assume that it's deobfuscated. |
| 577 | if (m_reference.getNameableEntry() instanceof ClassEntry && !text.getText().startsWith(Constants.NONE_PACKAGE) | 614 | if (m_reference.getNameableEntry() instanceof ClassEntry && text.getText().contains("/") && offset != 0) |
| 578 | && offset != 0) | ||
| 579 | text.select(offset, text.getText().length()); | 615 | text.select(offset, text.getText().length()); |
| 580 | else | 616 | else |
| 581 | text.selectAll(); | 617 | text.selectAll(); |
| @@ -766,21 +802,24 @@ public class Gui { | |||
| 766 | DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) node.getChildAt(i); | 802 | DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) node.getChildAt(i); |
| 767 | ClassEntry prevDataChild = (ClassEntry) childNode.getUserObject(); | 803 | ClassEntry prevDataChild = (ClassEntry) childNode.getUserObject(); |
| 768 | ClassEntry dataChild = new ClassEntry(data + "/" + prevDataChild.getSimpleName()); | 804 | ClassEntry dataChild = new ClassEntry(data + "/" + prevDataChild.getSimpleName()); |
| 769 | this.controller.rename(new EntryReference<>(prevDataChild, prevDataChild.getName()), dataChild.getName(), false); | 805 | this.controller.rename(new EntryReference<>(prevDataChild, prevDataChild.getName()), dataChild.getName(), false, i + 1 == node.getChildCount()); |
| 806 | childNode.setUserObject(dataChild); | ||
| 770 | } | 807 | } |
| 808 | node.setUserObject(data); | ||
| 809 | // Ob package will never be modified, just reload deob view | ||
| 810 | this.deobfPanel.deobfClasses.reload(); | ||
| 771 | } | 811 | } |
| 772 | // class rename | 812 | // class rename |
| 773 | else if (data instanceof ClassEntry) | 813 | else if (data instanceof ClassEntry) |
| 774 | this.controller.rename(new EntryReference<>((ClassEntry) prevData, ((ClassEntry) prevData).getName()), ((ClassEntry) data).getName(), false); | 814 | this.controller.rename(new EntryReference<>((ClassEntry) prevData, ((ClassEntry) prevData).getName()), ((ClassEntry) data).getName(), false, true); |
| 775 | } | 815 | } |
| 776 | 816 | ||
| 777 | public void moveClassTree(EntryReference<Entry, Entry> deobfReference, String newName) | 817 | public void moveClassTree(EntryReference<Entry, Entry> deobfReference, String newName) |
| 778 | { | 818 | { |
| 779 | String oldEntry = deobfReference.entry.getClassEntry().getPackageName(); | 819 | String oldEntry = deobfReference.entry.getClassEntry().getPackageName(); |
| 780 | String newEntry = new ClassEntry(Descriptor.toJvmName(newName)).getPackageName(); | 820 | String newEntry = new ClassEntry(Descriptor.toJvmName(newName)).getPackageName(); |
| 781 | if (oldEntry != null && newEntry != null) | 821 | moveClassTree(deobfReference, newName, oldEntry == null, |
| 782 | moveClassTree(deobfReference, newName, oldEntry.equals(Constants.NONE_PACKAGE), | 822 | newEntry == null); |
| 783 | newEntry.equals(Constants.NONE_PACKAGE)); | ||
| 784 | } | 823 | } |
| 785 | 824 | ||
| 786 | public void moveClassTree(EntryReference<Entry, Entry> deobfReference, String newName, boolean isOldOb, boolean isNewOb) | 825 | public void moveClassTree(EntryReference<Entry, Entry> deobfReference, String newName, boolean isOldOb, boolean isNewOb) |
| @@ -795,6 +834,8 @@ public class Gui { | |||
| 795 | ClassSelectorPackageNode packageNode = this.obfPanel.obfClasses.getPackageNode(oldEntry); | 834 | ClassSelectorPackageNode packageNode = this.obfPanel.obfClasses.getPackageNode(oldEntry); |
| 796 | this.obfPanel.obfClasses.removeNode(packageNode, oldEntry); | 835 | this.obfPanel.obfClasses.removeNode(packageNode, oldEntry); |
| 797 | this.obfPanel.obfClasses.removeNodeIfEmpty(packageNode); | 836 | this.obfPanel.obfClasses.removeNodeIfEmpty(packageNode); |
| 837 | this.deobfPanel.deobfClasses.reload(); | ||
| 838 | this.obfPanel.obfClasses.reload(); | ||
| 798 | } | 839 | } |
| 799 | // Deob -> ob | 840 | // Deob -> ob |
| 800 | else if (isNewOb && !isOldOb) | 841 | else if (isNewOb && !isOldOb) |
| @@ -803,17 +844,21 @@ public class Gui { | |||
| 803 | ClassSelectorPackageNode packageNode = this.deobfPanel.deobfClasses.getPackageNode(oldEntry); | 844 | ClassSelectorPackageNode packageNode = this.deobfPanel.deobfClasses.getPackageNode(oldEntry); |
| 804 | this.deobfPanel.deobfClasses.removeNode(packageNode, oldEntry); | 845 | this.deobfPanel.deobfClasses.removeNode(packageNode, oldEntry); |
| 805 | this.deobfPanel.deobfClasses.removeNodeIfEmpty(packageNode); | 846 | this.deobfPanel.deobfClasses.removeNodeIfEmpty(packageNode); |
| 847 | this.deobfPanel.deobfClasses.reload(); | ||
| 848 | this.obfPanel.obfClasses.reload(); | ||
| 806 | } | 849 | } |
| 807 | // Local move | 850 | // Local move |
| 808 | else if (isOldOb) | 851 | else if (isOldOb) |
| 809 | { | 852 | { |
| 810 | this.obfPanel.obfClasses.moveClassTree(oldEntry, newEntry, null); | 853 | this.obfPanel.obfClasses.moveClassTree(oldEntry, newEntry, null); |
| 811 | this.obfPanel.obfClasses.removeNodeIfEmpty(this.obfPanel.obfClasses.getPackageNode(oldEntry)); | 854 | this.obfPanel.obfClasses.removeNodeIfEmpty(this.obfPanel.obfClasses.getPackageNode(oldEntry)); |
| 855 | this.obfPanel.obfClasses.reload(); | ||
| 812 | } | 856 | } |
| 813 | else | 857 | else |
| 814 | { | 858 | { |
| 815 | this.deobfPanel.deobfClasses.moveClassTree(oldEntry, newEntry, null); | 859 | this.deobfPanel.deobfClasses.moveClassTree(oldEntry, newEntry, null); |
| 816 | this.deobfPanel.deobfClasses.removeNodeIfEmpty(this.deobfPanel.deobfClasses.getPackageNode(oldEntry)); | 860 | this.deobfPanel.deobfClasses.removeNodeIfEmpty(this.deobfPanel.deobfClasses.getPackageNode(oldEntry)); |
| 861 | this.deobfPanel.deobfClasses.reload(); | ||
| 817 | } | 862 | } |
| 818 | } | 863 | } |
| 819 | } | 864 | } |
diff --git a/src/main/java/cuchaz/enigma/gui/GuiController.java b/src/main/java/cuchaz/enigma/gui/GuiController.java index 3188ff02..c2e202e2 100644 --- a/src/main/java/cuchaz/enigma/gui/GuiController.java +++ b/src/main/java/cuchaz/enigma/gui/GuiController.java | |||
| @@ -20,6 +20,7 @@ import cuchaz.enigma.mapping.*; | |||
| 20 | import cuchaz.enigma.throwables.MappingParseException; | 20 | import cuchaz.enigma.throwables.MappingParseException; |
| 21 | import cuchaz.enigma.utils.ReadableToken; | 21 | import cuchaz.enigma.utils.ReadableToken; |
| 22 | 22 | ||
| 23 | import java.awt.event.ItemEvent; | ||
| 23 | import java.io.File; | 24 | import java.io.File; |
| 24 | import java.io.IOException; | 25 | import java.io.IOException; |
| 25 | import java.util.Collection; | 26 | import java.util.Collection; |
| @@ -193,16 +194,16 @@ public class GuiController { | |||
| 193 | } | 194 | } |
| 194 | 195 | ||
| 195 | public void rename(EntryReference<Entry, Entry> deobfReference, String newName) { | 196 | public void rename(EntryReference<Entry, Entry> deobfReference, String newName) { |
| 196 | rename(deobfReference, newName, true); | 197 | rename(deobfReference, newName, true, true); |
| 197 | } | 198 | } |
| 198 | 199 | ||
| 199 | public void rename(EntryReference<Entry, Entry> deobfReference, String newName, boolean refreshClassTree) | 200 | public void rename(EntryReference<Entry, Entry> deobfReference, String newName, boolean refreshClassTree, boolean clearTranslationCache) |
| 200 | { | 201 | { |
| 201 | EntryReference<Entry, Entry> obfReference = this.deobfuscator.obfuscateReference(deobfReference); | 202 | EntryReference<Entry, Entry> obfReference = this.deobfuscator.obfuscateReference(deobfReference); |
| 202 | this.deobfuscator.rename(obfReference.getNameableEntry(), newName); | 203 | this.deobfuscator.rename(obfReference.getNameableEntry(), newName, clearTranslationCache); |
| 203 | this.isDirty = true; | 204 | this.isDirty = true; |
| 204 | 205 | ||
| 205 | if (refreshClassTree && deobfReference.entry instanceof ClassEntry) | 206 | if (refreshClassTree && deobfReference.entry instanceof ClassEntry && !((ClassEntry) deobfReference.entry).isInnerClass()) |
| 206 | this.gui.moveClassTree(deobfReference, newName); | 207 | this.gui.moveClassTree(deobfReference, newName); |
| 207 | refreshCurrentClass(obfReference); | 208 | refreshCurrentClass(obfReference); |
| 208 | 209 | ||
| @@ -221,7 +222,7 @@ public class GuiController { | |||
| 221 | EntryReference<Entry, Entry> obfReference = this.deobfuscator.obfuscateReference(deobfReference); | 222 | EntryReference<Entry, Entry> obfReference = this.deobfuscator.obfuscateReference(deobfReference); |
| 222 | this.deobfuscator.markAsDeobfuscated(obfReference.getNameableEntry()); | 223 | this.deobfuscator.markAsDeobfuscated(obfReference.getNameableEntry()); |
| 223 | this.isDirty = true; | 224 | this.isDirty = true; |
| 224 | if (deobfReference.entry instanceof ClassEntry) | 225 | if (deobfReference.entry instanceof ClassEntry && !((ClassEntry) deobfReference.entry).isInnerClass()) |
| 225 | this.gui.moveClassTree(deobfReference, obfReference.entry.getName(), true, false); | 226 | this.gui.moveClassTree(deobfReference, obfReference.entry.getName(), true, false); |
| 226 | refreshCurrentClass(obfReference); | 227 | refreshCurrentClass(obfReference); |
| 227 | } | 228 | } |
| @@ -338,4 +339,19 @@ public class GuiController { | |||
| 338 | } | 339 | } |
| 339 | }.start(); | 340 | }.start(); |
| 340 | } | 341 | } |
| 342 | |||
| 343 | public Deobfuscator getDeobfuscator() | ||
| 344 | { | ||
| 345 | return deobfuscator; | ||
| 346 | } | ||
| 347 | |||
| 348 | public void modifierChange(ItemEvent event) | ||
| 349 | { | ||
| 350 | if (event.getStateChange() == ItemEvent.SELECTED) | ||
| 351 | { | ||
| 352 | deobfuscator.changeModifier(gui.m_reference.entry, (Mappings.EntryModifier) event.getItem()); | ||
| 353 | this.isDirty = true; | ||
| 354 | refreshCurrentClass(); | ||
| 355 | } | ||
| 356 | } | ||
| 341 | } | 357 | } |
diff --git a/src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java b/src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java index 50550910..ecc280d5 100644 --- a/src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java +++ b/src/main/java/cuchaz/enigma/gui/MemberMatchingGui.java | |||
| @@ -138,7 +138,7 @@ public class MemberMatchingGui<T extends Entry> { | |||
| 138 | sourceTypePanel.add(button); | 138 | sourceTypePanel.add(button); |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | m_sourceClasses = new ClassSelector(null, ClassSelector.DEOBF_CLASS_COMPARATOR); | 141 | m_sourceClasses = new ClassSelector(null, ClassSelector.DEOBF_CLASS_COMPARATOR, false); |
| 142 | m_sourceClasses.setSelectionListener(this::setSourceClass); | 142 | m_sourceClasses.setSelectionListener(this::setSourceClass); |
| 143 | JScrollPane sourceScroller = new JScrollPane(m_sourceClasses); | 143 | JScrollPane sourceScroller = new JScrollPane(m_sourceClasses); |
| 144 | classesPanel.add(sourceScroller); | 144 | classesPanel.add(sourceScroller); |
diff --git a/src/main/java/cuchaz/enigma/gui/node/ClassSelectorClassNode.java b/src/main/java/cuchaz/enigma/gui/node/ClassSelectorClassNode.java index 1c9dad4b..83418267 100644 --- a/src/main/java/cuchaz/enigma/gui/node/ClassSelectorClassNode.java +++ b/src/main/java/cuchaz/enigma/gui/node/ClassSelectorClassNode.java | |||
| @@ -49,6 +49,11 @@ public class ClassSelectorClassNode extends DefaultMutableTreeNode { | |||
| 49 | super.setUserObject(classEntry); | 49 | super.setUserObject(classEntry); |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | @Override public Object getUserObject() | ||
| 53 | { | ||
| 54 | return classEntry; | ||
| 55 | } | ||
| 56 | |||
| 52 | public boolean equals(ClassSelectorClassNode other) { | 57 | public boolean equals(ClassSelectorClassNode other) { |
| 53 | return this.classEntry.equals(other.classEntry); | 58 | return this.classEntry.equals(other.classEntry); |
| 54 | } | 59 | } |
diff --git a/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java b/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java index d2e421e7..31b4ebfa 100644 --- a/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java +++ b/src/main/java/cuchaz/enigma/gui/node/ClassSelectorPackageNode.java | |||
| @@ -19,7 +19,7 @@ public class ClassSelectorPackageNode extends DefaultMutableTreeNode { | |||
| 19 | private String packageName; | 19 | private String packageName; |
| 20 | 20 | ||
| 21 | public ClassSelectorPackageNode(String packageName) { | 21 | public ClassSelectorPackageNode(String packageName) { |
| 22 | this.packageName = packageName; | 22 | this.packageName = packageName != null ? packageName : "(none)"; |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | public String getPackageName() { | 25 | public String getPackageName() { |
| @@ -33,9 +33,14 @@ public class ClassSelectorPackageNode extends DefaultMutableTreeNode { | |||
| 33 | super.setUserObject(userObject); | 33 | super.setUserObject(userObject); |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | @Override public Object getUserObject() | ||
| 37 | { | ||
| 38 | return packageName; | ||
| 39 | } | ||
| 40 | |||
| 36 | @Override | 41 | @Override |
| 37 | public String toString() { | 42 | public String toString() { |
| 38 | return Descriptor.toJavaName(this.packageName); | 43 | return !packageName.equals("(none)") ? Descriptor.toJavaName(this.packageName) : "(none)"; |
| 39 | } | 44 | } |
| 40 | 45 | ||
| 41 | @Override | 46 | @Override |
| @@ -44,6 +49,6 @@ public class ClassSelectorPackageNode extends DefaultMutableTreeNode { | |||
| 44 | } | 49 | } |
| 45 | 50 | ||
| 46 | public boolean equals(ClassSelectorPackageNode other) { | 51 | public boolean equals(ClassSelectorPackageNode other) { |
| 47 | return this.packageName.equals(other.packageName); | 52 | return other != null && this.packageName.equals(other.packageName); |
| 48 | } | 53 | } |
| 49 | } | 54 | } |
diff --git a/src/main/java/cuchaz/enigma/gui/panels/PanelDeobf.java b/src/main/java/cuchaz/enigma/gui/panels/PanelDeobf.java index 447c51af..4f551756 100644 --- a/src/main/java/cuchaz/enigma/gui/panels/PanelDeobf.java +++ b/src/main/java/cuchaz/enigma/gui/panels/PanelDeobf.java | |||
| @@ -17,7 +17,7 @@ public class PanelDeobf extends JPanel { | |||
| 17 | public PanelDeobf(Gui gui) { | 17 | public PanelDeobf(Gui gui) { |
| 18 | this.gui = gui; | 18 | this.gui = gui; |
| 19 | 19 | ||
| 20 | this.deobfClasses = new ClassSelector(gui, ClassSelector.DEOBF_CLASS_COMPARATOR); | 20 | this.deobfClasses = new ClassSelector(gui, ClassSelector.DEOBF_CLASS_COMPARATOR, true); |
| 21 | this.deobfClasses.setSelectionListener(gui::navigateTo); | 21 | this.deobfClasses.setSelectionListener(gui::navigateTo); |
| 22 | this.deobfClasses.setRenameSelectionListener(gui::onPanelRename); | 22 | this.deobfClasses.setRenameSelectionListener(gui::onPanelRename); |
| 23 | 23 | ||
diff --git a/src/main/java/cuchaz/enigma/gui/panels/PanelEditor.java b/src/main/java/cuchaz/enigma/gui/panels/PanelEditor.java index cf3c4e93..914952b9 100644 --- a/src/main/java/cuchaz/enigma/gui/panels/PanelEditor.java +++ b/src/main/java/cuchaz/enigma/gui/panels/PanelEditor.java | |||
| @@ -10,7 +10,6 @@ import javax.swing.JEditorPane; | |||
| 10 | 10 | ||
| 11 | import cuchaz.enigma.gui.BrowserCaret; | 11 | import cuchaz.enigma.gui.BrowserCaret; |
| 12 | import cuchaz.enigma.gui.Gui; | 12 | import cuchaz.enigma.gui.Gui; |
| 13 | import de.sciss.syntaxpane.DefaultSyntaxKit; | ||
| 14 | 13 | ||
| 15 | public class PanelEditor extends JEditorPane { | 14 | public class PanelEditor extends JEditorPane { |
| 16 | private final Gui gui; | 15 | private final Gui gui; |
| @@ -21,7 +20,6 @@ public class PanelEditor extends JEditorPane { | |||
| 21 | this.setEditable(false); | 20 | this.setEditable(false); |
| 22 | this.setSelectionColor(new Color(31, 46, 90)); | 21 | this.setSelectionColor(new Color(31, 46, 90)); |
| 23 | this.setCaret(new BrowserCaret()); | 22 | this.setCaret(new BrowserCaret()); |
| 24 | this.setContentType("text/java"); | ||
| 25 | this.addCaretListener(event -> gui.onCaretMove(event.getDot())); | 23 | this.addCaretListener(event -> gui.onCaretMove(event.getDot())); |
| 26 | final PanelEditor self = this; | 24 | final PanelEditor self = this; |
| 27 | this.addMouseListener(new MouseAdapter() | 25 | this.addMouseListener(new MouseAdapter() |
| @@ -71,8 +69,5 @@ public class PanelEditor extends JEditorPane { | |||
| 71 | } | 69 | } |
| 72 | } | 70 | } |
| 73 | }); | 71 | }); |
| 74 | |||
| 75 | DefaultSyntaxKit kit = (DefaultSyntaxKit) this.getEditorKit(); | ||
| 76 | kit.toggleComponent(this, "de.sciss.syntaxpane.components.TokenMarker"); | ||
| 77 | } | 72 | } |
| 78 | } | 73 | } |
diff --git a/src/main/java/cuchaz/enigma/gui/panels/PanelObf.java b/src/main/java/cuchaz/enigma/gui/panels/PanelObf.java index 74772a5f..27bb70b4 100644 --- a/src/main/java/cuchaz/enigma/gui/panels/PanelObf.java +++ b/src/main/java/cuchaz/enigma/gui/panels/PanelObf.java | |||
| @@ -28,7 +28,7 @@ public class PanelObf extends JPanel { | |||
| 28 | return aname.compareTo(bname); | 28 | return aname.compareTo(bname); |
| 29 | }; | 29 | }; |
| 30 | 30 | ||
| 31 | this.obfClasses = new ClassSelector(gui, obfClassComparator); | 31 | this.obfClasses = new ClassSelector(gui, obfClassComparator, false); |
| 32 | this.obfClasses.setSelectionListener(gui::navigateTo); | 32 | this.obfClasses.setSelectionListener(gui::navigateTo); |
| 33 | this.obfClasses.setRenameSelectionListener(gui::onPanelRename); | 33 | this.obfClasses.setRenameSelectionListener(gui::onPanelRename); |
| 34 | 34 | ||
diff --git a/src/main/java/cuchaz/enigma/mapping/ClassMapping.java b/src/main/java/cuchaz/enigma/mapping/ClassMapping.java index 36b35f73..8f893889 100644 --- a/src/main/java/cuchaz/enigma/mapping/ClassMapping.java +++ b/src/main/java/cuchaz/enigma/mapping/ClassMapping.java | |||
| @@ -17,33 +17,49 @@ import java.util.Map; | |||
| 17 | 17 | ||
| 18 | import cuchaz.enigma.throwables.MappingConflict; | 18 | import cuchaz.enigma.throwables.MappingConflict; |
| 19 | 19 | ||
| 20 | // FIXME: Enigma doesn't support inner classes of inner class????! | ||
| 20 | public class ClassMapping implements Comparable<ClassMapping> { | 21 | public class ClassMapping implements Comparable<ClassMapping> { |
| 21 | 22 | ||
| 22 | private String m_obfFullName; | 23 | private String m_obfFullName; |
| 23 | private String m_obfSimpleName; | 24 | private String m_obfSimpleName; |
| 24 | private String m_deobfName; | 25 | private String m_deobfName; |
| 26 | private String m_previousDeobfName; | ||
| 25 | private Map<String, ClassMapping> m_innerClassesByObfSimple; | 27 | private Map<String, ClassMapping> m_innerClassesByObfSimple; |
| 28 | private Map<String, ClassMapping> m_innerClassesByObfFull; | ||
| 26 | private Map<String, ClassMapping> m_innerClassesByDeobf; | 29 | private Map<String, ClassMapping> m_innerClassesByDeobf; |
| 27 | private Map<String, FieldMapping> m_fieldsByObf; | 30 | private Map<String, FieldMapping> m_fieldsByObf; |
| 28 | private Map<String, FieldMapping> m_fieldsByDeobf; | 31 | private Map<String, FieldMapping> m_fieldsByDeobf; |
| 29 | private Map<String, MethodMapping> m_methodsByObf; | 32 | private Map<String, MethodMapping> m_methodsByObf; |
| 30 | private Map<String, MethodMapping> m_methodsByDeobf; | 33 | private Map<String, MethodMapping> m_methodsByDeobf; |
| 34 | private boolean isDirty; | ||
| 35 | private Mappings.EntryModifier modifier; | ||
| 31 | 36 | ||
| 32 | public ClassMapping(String obfFullName) { | 37 | public ClassMapping(String obfFullName) |
| 33 | this(obfFullName, null); | 38 | { |
| 39 | this(obfFullName, null, Mappings.EntryModifier.UNCHANGED); | ||
| 34 | } | 40 | } |
| 35 | 41 | ||
| 36 | public ClassMapping(String obfFullName, String deobfName) { | 42 | public ClassMapping(String obfFullName, String deobfName) |
| 43 | { | ||
| 44 | this(obfFullName, deobfName, Mappings.EntryModifier.UNCHANGED); | ||
| 45 | } | ||
| 46 | |||
| 47 | public ClassMapping(String obfFullName, String deobfName, Mappings.EntryModifier modifier) | ||
| 48 | { | ||
| 37 | m_obfFullName = obfFullName; | 49 | m_obfFullName = obfFullName; |
| 38 | ClassEntry classEntry = new ClassEntry(obfFullName); | 50 | ClassEntry classEntry = new ClassEntry(obfFullName); |
| 39 | m_obfSimpleName = classEntry.isInnerClass() ? classEntry.getInnermostClassName() : classEntry.getSimpleName(); | 51 | m_obfSimpleName = classEntry.isInnerClass() ? classEntry.getInnermostClassName() : classEntry.getSimpleName(); |
| 52 | m_previousDeobfName = null; | ||
| 40 | m_deobfName = NameValidator.validateClassName(deobfName, false); | 53 | m_deobfName = NameValidator.validateClassName(deobfName, false); |
| 41 | m_innerClassesByObfSimple = Maps.newHashMap(); | 54 | m_innerClassesByObfSimple = Maps.newHashMap(); |
| 55 | m_innerClassesByObfFull = Maps.newHashMap(); | ||
| 42 | m_innerClassesByDeobf = Maps.newHashMap(); | 56 | m_innerClassesByDeobf = Maps.newHashMap(); |
| 43 | m_fieldsByObf = Maps.newHashMap(); | 57 | m_fieldsByObf = Maps.newHashMap(); |
| 44 | m_fieldsByDeobf = Maps.newHashMap(); | 58 | m_fieldsByDeobf = Maps.newHashMap(); |
| 45 | m_methodsByObf = Maps.newHashMap(); | 59 | m_methodsByObf = Maps.newHashMap(); |
| 46 | m_methodsByDeobf = Maps.newHashMap(); | 60 | m_methodsByDeobf = Maps.newHashMap(); |
| 61 | isDirty = true; | ||
| 62 | this.modifier = modifier; | ||
| 47 | } | 63 | } |
| 48 | 64 | ||
| 49 | public String getObfFullName() { | 65 | public String getObfFullName() { |
| @@ -54,12 +70,18 @@ public class ClassMapping implements Comparable<ClassMapping> { | |||
| 54 | return m_obfSimpleName; | 70 | return m_obfSimpleName; |
| 55 | } | 71 | } |
| 56 | 72 | ||
| 73 | public String getPreviousDeobfName() { | ||
| 74 | return m_previousDeobfName; | ||
| 75 | } | ||
| 76 | |||
| 57 | public String getDeobfName() { | 77 | public String getDeobfName() { |
| 58 | return m_deobfName; | 78 | return m_deobfName; |
| 59 | } | 79 | } |
| 60 | 80 | ||
| 61 | public void setDeobfName(String val) { | 81 | public void setDeobfName(String val) { |
| 82 | m_previousDeobfName = m_deobfName; | ||
| 62 | m_deobfName = NameValidator.validateClassName(val, false); | 83 | m_deobfName = NameValidator.validateClassName(val, false); |
| 84 | this.isDirty = true; | ||
| 63 | } | 85 | } |
| 64 | 86 | ||
| 65 | //// INNER CLASSES //////// | 87 | //// INNER CLASSES //////// |
| @@ -70,9 +92,11 @@ public class ClassMapping implements Comparable<ClassMapping> { | |||
| 70 | } | 92 | } |
| 71 | 93 | ||
| 72 | public void addInnerClassMapping(ClassMapping classMapping) throws MappingConflict { | 94 | public void addInnerClassMapping(ClassMapping classMapping) throws MappingConflict { |
| 73 | if (this.m_innerClassesByObfSimple.containsKey(classMapping.getObfSimpleName())) { | 95 | // FIXME: dirty hack, that can get into issues, but it's a temp fix! |
| 96 | if (this.m_innerClassesByObfFull.containsKey(classMapping.getObfSimpleName())) { | ||
| 74 | throw new MappingConflict("classes", classMapping.getObfSimpleName(), this.m_innerClassesByObfSimple.get(classMapping.getObfSimpleName()).getObfSimpleName()); | 97 | throw new MappingConflict("classes", classMapping.getObfSimpleName(), this.m_innerClassesByObfSimple.get(classMapping.getObfSimpleName()).getObfSimpleName()); |
| 75 | } | 98 | } |
| 99 | m_innerClassesByObfFull.put(classMapping.getObfFullName(), classMapping); | ||
| 76 | m_innerClassesByObfSimple.put(classMapping.getObfSimpleName(), classMapping); | 100 | m_innerClassesByObfSimple.put(classMapping.getObfSimpleName(), classMapping); |
| 77 | 101 | ||
| 78 | if (classMapping.getDeobfName() != null) { | 102 | if (classMapping.getDeobfName() != null) { |
| @@ -81,23 +105,28 @@ public class ClassMapping implements Comparable<ClassMapping> { | |||
| 81 | } | 105 | } |
| 82 | m_innerClassesByDeobf.put(classMapping.getDeobfName(), classMapping); | 106 | m_innerClassesByDeobf.put(classMapping.getDeobfName(), classMapping); |
| 83 | } | 107 | } |
| 108 | this.isDirty = true; | ||
| 84 | } | 109 | } |
| 85 | 110 | ||
| 86 | public void removeInnerClassMapping(ClassMapping classMapping) { | 111 | public void removeInnerClassMapping(ClassMapping classMapping) { |
| 112 | m_innerClassesByObfFull.remove(classMapping.getObfFullName()); | ||
| 87 | boolean obfWasRemoved = m_innerClassesByObfSimple.remove(classMapping.getObfSimpleName()) != null; | 113 | boolean obfWasRemoved = m_innerClassesByObfSimple.remove(classMapping.getObfSimpleName()) != null; |
| 88 | assert (obfWasRemoved); | 114 | assert (obfWasRemoved); |
| 89 | if (classMapping.getDeobfName() != null) { | 115 | if (classMapping.getDeobfName() != null) { |
| 90 | boolean deobfWasRemoved = m_innerClassesByDeobf.remove(classMapping.getDeobfName()) != null; | 116 | boolean deobfWasRemoved = m_innerClassesByDeobf.remove(classMapping.getDeobfName()) != null; |
| 91 | assert (deobfWasRemoved); | 117 | assert (deobfWasRemoved); |
| 92 | } | 118 | } |
| 119 | this.isDirty = true; | ||
| 93 | } | 120 | } |
| 94 | 121 | ||
| 95 | public ClassMapping getOrCreateInnerClass(ClassEntry obfInnerClass) { | 122 | public ClassMapping getOrCreateInnerClass(ClassEntry obfInnerClass) { |
| 96 | ClassMapping classMapping = m_innerClassesByObfSimple.get(obfInnerClass.getInnermostClassName()); | 123 | ClassMapping classMapping = m_innerClassesByObfSimple.get(obfInnerClass.getInnermostClassName()); |
| 97 | if (classMapping == null) { | 124 | if (classMapping == null) { |
| 98 | classMapping = new ClassMapping(obfInnerClass.getName()); | 125 | classMapping = new ClassMapping(obfInnerClass.getName()); |
| 126 | m_innerClassesByObfFull.put(classMapping.getObfFullName(), classMapping); | ||
| 99 | boolean wasAdded = m_innerClassesByObfSimple.put(classMapping.getObfSimpleName(), classMapping) == null; | 127 | boolean wasAdded = m_innerClassesByObfSimple.put(classMapping.getObfSimpleName(), classMapping) == null; |
| 100 | assert (wasAdded); | 128 | assert (wasAdded); |
| 129 | this.isDirty = true; | ||
| 101 | } | 130 | } |
| 102 | return classMapping; | 131 | return classMapping; |
| 103 | } | 132 | } |
| @@ -141,6 +170,7 @@ public class ClassMapping implements Comparable<ClassMapping> { | |||
| 141 | boolean wasAdded = m_innerClassesByDeobf.put(deobfName, classMapping) == null; | 170 | boolean wasAdded = m_innerClassesByDeobf.put(deobfName, classMapping) == null; |
| 142 | assert (wasAdded); | 171 | assert (wasAdded); |
| 143 | } | 172 | } |
| 173 | this.isDirty = true; | ||
| 144 | } | 174 | } |
| 145 | 175 | ||
| 146 | public boolean hasInnerClassByObfSimple(String obfSimpleName) { | 176 | public boolean hasInnerClassByObfSimple(String obfSimpleName) { |
| @@ -172,15 +202,17 @@ public class ClassMapping implements Comparable<ClassMapping> { | |||
| 172 | if (m_fieldsByObf.containsKey(obfKey)) { | 202 | if (m_fieldsByObf.containsKey(obfKey)) { |
| 173 | throw new Error("Already have mapping for " + m_obfFullName + "." + obfKey); | 203 | throw new Error("Already have mapping for " + m_obfFullName + "." + obfKey); |
| 174 | } | 204 | } |
| 175 | String deobfKey = getFieldKey(fieldMapping.getDeobfName(), fieldMapping.getObfType()); | 205 | if (fieldMapping.getDeobfName() != null) { |
| 176 | if (m_fieldsByDeobf.containsKey(deobfKey)) { | 206 | String deobfKey = getFieldKey(fieldMapping.getDeobfName(), fieldMapping.getObfType()); |
| 177 | throw new Error("Already have mapping for " + m_deobfName + "." + deobfKey); | 207 | if (m_fieldsByDeobf.containsKey(deobfKey)) { |
| 208 | throw new Error("Already have mapping for " + m_deobfName + "." + deobfKey); | ||
| 209 | } | ||
| 210 | boolean deobfWasAdded = m_fieldsByDeobf.put(deobfKey, fieldMapping) == null; | ||
| 211 | assert (deobfWasAdded); | ||
| 178 | } | 212 | } |
| 179 | boolean obfWasAdded = m_fieldsByObf.put(obfKey, fieldMapping) == null; | 213 | boolean obfWasAdded = m_fieldsByObf.put(obfKey, fieldMapping) == null; |
| 180 | assert (obfWasAdded); | 214 | assert (obfWasAdded); |
| 181 | boolean deobfWasAdded = m_fieldsByDeobf.put(deobfKey, fieldMapping) == null; | 215 | this.isDirty = true; |
| 182 | assert (deobfWasAdded); | ||
| 183 | assert (m_fieldsByObf.size() == m_fieldsByDeobf.size()); | ||
| 184 | } | 216 | } |
| 185 | 217 | ||
| 186 | public void removeFieldMapping(FieldMapping fieldMapping) { | 218 | public void removeFieldMapping(FieldMapping fieldMapping) { |
| @@ -190,6 +222,7 @@ public class ClassMapping implements Comparable<ClassMapping> { | |||
| 190 | boolean deobfWasRemoved = m_fieldsByDeobf.remove(getFieldKey(fieldMapping.getDeobfName(), fieldMapping.getObfType())) != null; | 222 | boolean deobfWasRemoved = m_fieldsByDeobf.remove(getFieldKey(fieldMapping.getDeobfName(), fieldMapping.getObfType())) != null; |
| 191 | assert (deobfWasRemoved); | 223 | assert (deobfWasRemoved); |
| 192 | } | 224 | } |
| 225 | this.isDirty = true; | ||
| 193 | } | 226 | } |
| 194 | 227 | ||
| 195 | public FieldMapping getFieldByObf(String obfName, Type obfType) { | 228 | public FieldMapping getFieldByObf(String obfName, Type obfType) { |
| @@ -226,12 +259,11 @@ public class ClassMapping implements Comparable<ClassMapping> { | |||
| 226 | return name + ":" + type; | 259 | return name + ":" + type; |
| 227 | } | 260 | } |
| 228 | 261 | ||
| 229 | |||
| 230 | public void setFieldName(String obfName, Type obfType, String deobfName) { | 262 | public void setFieldName(String obfName, Type obfType, String deobfName) { |
| 231 | assert (deobfName != null); | 263 | assert (deobfName != null); |
| 232 | FieldMapping fieldMapping = m_fieldsByObf.get(getFieldKey(obfName, obfType)); | 264 | FieldMapping fieldMapping = m_fieldsByObf.get(getFieldKey(obfName, obfType)); |
| 233 | if (fieldMapping == null) { | 265 | if (fieldMapping == null) { |
| 234 | fieldMapping = new FieldMapping(obfName, obfType, deobfName); | 266 | fieldMapping = new FieldMapping(obfName, obfType, deobfName, Mappings.EntryModifier.UNCHANGED); |
| 235 | boolean obfWasAdded = m_fieldsByObf.put(getFieldKey(obfName, obfType), fieldMapping) == null; | 267 | boolean obfWasAdded = m_fieldsByObf.put(getFieldKey(obfName, obfType), fieldMapping) == null; |
| 236 | assert (obfWasAdded); | 268 | assert (obfWasAdded); |
| 237 | } else { | 269 | } else { |
| @@ -243,6 +275,7 @@ public class ClassMapping implements Comparable<ClassMapping> { | |||
| 243 | boolean wasAdded = m_fieldsByDeobf.put(getFieldKey(deobfName, obfType), fieldMapping) == null; | 275 | boolean wasAdded = m_fieldsByDeobf.put(getFieldKey(deobfName, obfType), fieldMapping) == null; |
| 244 | assert (wasAdded); | 276 | assert (wasAdded); |
| 245 | } | 277 | } |
| 278 | this.isDirty = true; | ||
| 246 | } | 279 | } |
| 247 | 280 | ||
| 248 | public void setFieldObfNameAndType(String oldObfName, Type obfType, String newObfName, Type newObfType) { | 281 | public void setFieldObfNameAndType(String oldObfName, Type obfType, String newObfName, Type newObfType) { |
| @@ -253,6 +286,7 @@ public class ClassMapping implements Comparable<ClassMapping> { | |||
| 253 | fieldMapping.setObfType(newObfType); | 286 | fieldMapping.setObfType(newObfType); |
| 254 | boolean obfWasAdded = m_fieldsByObf.put(getFieldKey(newObfName, newObfType), fieldMapping) == null; | 287 | boolean obfWasAdded = m_fieldsByObf.put(getFieldKey(newObfName, newObfType), fieldMapping) == null; |
| 255 | assert(obfWasAdded); | 288 | assert(obfWasAdded); |
| 289 | this.isDirty = true; | ||
| 256 | } | 290 | } |
| 257 | 291 | ||
| 258 | //// METHODS //////// | 292 | //// METHODS //////// |
| @@ -285,6 +319,7 @@ public class ClassMapping implements Comparable<ClassMapping> { | |||
| 285 | boolean deobfWasAdded = m_methodsByDeobf.put(deobfKey, methodMapping) == null; | 319 | boolean deobfWasAdded = m_methodsByDeobf.put(deobfKey, methodMapping) == null; |
| 286 | assert (deobfWasAdded); | 320 | assert (deobfWasAdded); |
| 287 | } | 321 | } |
| 322 | this.isDirty = true; | ||
| 288 | assert (m_methodsByObf.size() >= m_methodsByDeobf.size()); | 323 | assert (m_methodsByObf.size() >= m_methodsByDeobf.size()); |
| 289 | } | 324 | } |
| 290 | 325 | ||
| @@ -295,6 +330,7 @@ public class ClassMapping implements Comparable<ClassMapping> { | |||
| 295 | boolean deobfWasRemoved = m_methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature())) != null; | 330 | boolean deobfWasRemoved = m_methodsByDeobf.remove(getMethodKey(methodMapping.getDeobfName(), methodMapping.getObfSignature())) != null; |
| 296 | assert (deobfWasRemoved); | 331 | assert (deobfWasRemoved); |
| 297 | } | 332 | } |
| 333 | this.isDirty = true; | ||
| 298 | } | 334 | } |
| 299 | 335 | ||
| 300 | public MethodMapping getMethodByObf(String obfName, Signature obfSignature) { | 336 | public MethodMapping getMethodByObf(String obfName, Signature obfSignature) { |
| @@ -328,6 +364,7 @@ public class ClassMapping implements Comparable<ClassMapping> { | |||
| 328 | boolean wasAdded = m_methodsByDeobf.put(getMethodKey(deobfName, obfSignature), methodMapping) == null; | 364 | boolean wasAdded = m_methodsByDeobf.put(getMethodKey(deobfName, obfSignature), methodMapping) == null; |
| 329 | assert (wasAdded); | 365 | assert (wasAdded); |
| 330 | } | 366 | } |
| 367 | this.isDirty = true; | ||
| 331 | } | 368 | } |
| 332 | 369 | ||
| 333 | public void setMethodObfNameAndSignature(String oldObfName, Signature obfSignature, String newObfName, Signature newObfSignature) { | 370 | public void setMethodObfNameAndSignature(String oldObfName, Signature obfSignature, String newObfName, Signature newObfSignature) { |
| @@ -338,6 +375,7 @@ public class ClassMapping implements Comparable<ClassMapping> { | |||
| 338 | methodMapping.setObfSignature(newObfSignature); | 375 | methodMapping.setObfSignature(newObfSignature); |
| 339 | boolean obfWasAdded = m_methodsByObf.put(getMethodKey(newObfName, newObfSignature), methodMapping) == null; | 376 | boolean obfWasAdded = m_methodsByObf.put(getMethodKey(newObfName, newObfSignature), methodMapping) == null; |
| 340 | assert(obfWasAdded); | 377 | assert(obfWasAdded); |
| 378 | this.isDirty = true; | ||
| 341 | } | 379 | } |
| 342 | 380 | ||
| 343 | //// ARGUMENTS //////// | 381 | //// ARGUMENTS //////// |
| @@ -349,16 +387,19 @@ public class ClassMapping implements Comparable<ClassMapping> { | |||
| 349 | methodMapping = createMethodMapping(obfMethodName, obfMethodSignature); | 387 | methodMapping = createMethodMapping(obfMethodName, obfMethodSignature); |
| 350 | } | 388 | } |
| 351 | methodMapping.setArgumentName(argumentIndex, argumentName); | 389 | methodMapping.setArgumentName(argumentIndex, argumentName); |
| 390 | this.isDirty = true; | ||
| 352 | } | 391 | } |
| 353 | 392 | ||
| 354 | public void removeArgumentName(String obfMethodName, Signature obfMethodSignature, int argumentIndex) { | 393 | public void removeArgumentName(String obfMethodName, Signature obfMethodSignature, int argumentIndex) { |
| 355 | m_methodsByObf.get(getMethodKey(obfMethodName, obfMethodSignature)).removeArgumentName(argumentIndex); | 394 | m_methodsByObf.get(getMethodKey(obfMethodName, obfMethodSignature)).removeArgumentName(argumentIndex); |
| 395 | this.isDirty = true; | ||
| 356 | } | 396 | } |
| 357 | 397 | ||
| 358 | private MethodMapping createMethodMapping(String obfName, Signature obfSignature) { | 398 | private MethodMapping createMethodMapping(String obfName, Signature obfSignature) { |
| 359 | MethodMapping methodMapping = new MethodMapping(obfName, obfSignature); | 399 | MethodMapping methodMapping = new MethodMapping(obfName, obfSignature); |
| 360 | boolean wasAdded = m_methodsByObf.put(getMethodKey(obfName, obfSignature), methodMapping) == null; | 400 | boolean wasAdded = m_methodsByObf.put(getMethodKey(obfName, obfSignature), methodMapping) == null; |
| 361 | assert (wasAdded); | 401 | assert (wasAdded); |
| 402 | this.isDirty = true; | ||
| 362 | return methodMapping; | 403 | return methodMapping; |
| 363 | } | 404 | } |
| 364 | 405 | ||
| @@ -441,6 +482,7 @@ public class ClassMapping implements Comparable<ClassMapping> { | |||
| 441 | m_obfFullName = newObfClassName; | 482 | m_obfFullName = newObfClassName; |
| 442 | return true; | 483 | return true; |
| 443 | } | 484 | } |
| 485 | this.isDirty = true; | ||
| 444 | return false; | 486 | return false; |
| 445 | } | 487 | } |
| 446 | 488 | ||
| @@ -456,4 +498,54 @@ public class ClassMapping implements Comparable<ClassMapping> { | |||
| 456 | public ClassEntry getObfEntry() { | 498 | public ClassEntry getObfEntry() { |
| 457 | return new ClassEntry(m_obfFullName); | 499 | return new ClassEntry(m_obfFullName); |
| 458 | } | 500 | } |
| 501 | |||
| 502 | public boolean isDirty() | ||
| 503 | { | ||
| 504 | return isDirty; | ||
| 505 | } | ||
| 506 | |||
| 507 | public void resetDirty() | ||
| 508 | { | ||
| 509 | this.isDirty = false; | ||
| 510 | } | ||
| 511 | |||
| 512 | public void setModifier(Mappings.EntryModifier modifier) | ||
| 513 | { | ||
| 514 | if (this.modifier != modifier) | ||
| 515 | this.isDirty = true; | ||
| 516 | this.modifier = modifier; | ||
| 517 | } | ||
| 518 | |||
| 519 | public Mappings.EntryModifier getModifier() | ||
| 520 | { | ||
| 521 | return modifier; | ||
| 522 | } | ||
| 523 | |||
| 524 | public void setFieldModifier(String obfName, Type obfType, Mappings.EntryModifier modifier) { | ||
| 525 | FieldMapping fieldMapping = m_fieldsByObf.get(getFieldKey(obfName, obfType)); | ||
| 526 | if (fieldMapping == null) { | ||
| 527 | fieldMapping = new FieldMapping(obfName, obfType, null, Mappings.EntryModifier.UNCHANGED); | ||
| 528 | m_fieldsByObf.put(getFieldKey(obfName, obfType), fieldMapping); | ||
| 529 | } | ||
| 530 | |||
| 531 | if (fieldMapping.getModifier() != modifier) | ||
| 532 | { | ||
| 533 | fieldMapping.setModifier(modifier); | ||
| 534 | this.isDirty = true; | ||
| 535 | } | ||
| 536 | } | ||
| 537 | |||
| 538 | public void setMethodModifier(String obfName, Signature sig, Mappings.EntryModifier modifier) { | ||
| 539 | MethodMapping methodMapping = m_methodsByObf.get(getMethodKey(obfName, sig)); | ||
| 540 | if (methodMapping == null) { | ||
| 541 | methodMapping = new MethodMapping(obfName, sig, null, Mappings.EntryModifier.UNCHANGED); | ||
| 542 | m_methodsByObf.put(getMethodKey(obfName, sig), methodMapping); | ||
| 543 | } | ||
| 544 | |||
| 545 | if (methodMapping.getModifier() != modifier) | ||
| 546 | { | ||
| 547 | methodMapping.setModifier(modifier); | ||
| 548 | this.isDirty = true; | ||
| 549 | } | ||
| 550 | } | ||
| 459 | } | 551 | } |
diff --git a/src/main/java/cuchaz/enigma/mapping/FieldMapping.java b/src/main/java/cuchaz/enigma/mapping/FieldMapping.java index 1b596606..e75485cd 100644 --- a/src/main/java/cuchaz/enigma/mapping/FieldMapping.java +++ b/src/main/java/cuchaz/enigma/mapping/FieldMapping.java | |||
| @@ -15,16 +15,19 @@ public class FieldMapping implements Comparable<FieldMapping>, MemberMapping<Fie | |||
| 15 | private String obfName; | 15 | private String obfName; |
| 16 | private String deobfName; | 16 | private String deobfName; |
| 17 | private Type obfType; | 17 | private Type obfType; |
| 18 | private Mappings.EntryModifier modifier; | ||
| 18 | 19 | ||
| 19 | public FieldMapping(String obfName, Type obfType, String deobfName) { | 20 | public FieldMapping(String obfName, Type obfType, String deobfName, Mappings.EntryModifier modifier) { |
| 20 | this.obfName = obfName; | 21 | this.obfName = obfName; |
| 21 | this.deobfName = NameValidator.validateFieldName(deobfName); | 22 | this.deobfName = NameValidator.validateFieldName(deobfName); |
| 22 | this.obfType = obfType; | 23 | this.obfType = obfType; |
| 24 | this.modifier = modifier; | ||
| 23 | } | 25 | } |
| 24 | 26 | ||
| 25 | public FieldMapping(FieldMapping other, ClassNameReplacer obfClassNameReplacer) { | 27 | public FieldMapping(FieldMapping other, ClassNameReplacer obfClassNameReplacer) { |
| 26 | this.obfName = other.obfName; | 28 | this.obfName = other.obfName; |
| 27 | this.deobfName = other.deobfName; | 29 | this.deobfName = other.deobfName; |
| 30 | this.modifier = other.modifier; | ||
| 28 | this.obfType = new Type(other.obfType, obfClassNameReplacer); | 31 | this.obfType = new Type(other.obfType, obfClassNameReplacer); |
| 29 | } | 32 | } |
| 30 | 33 | ||
| @@ -58,6 +61,16 @@ public class FieldMapping implements Comparable<FieldMapping>, MemberMapping<Fie | |||
| 58 | this.obfType = val; | 61 | this.obfType = val; |
| 59 | } | 62 | } |
| 60 | 63 | ||
| 64 | public void setModifier(Mappings.EntryModifier modifier) | ||
| 65 | { | ||
| 66 | this.modifier = modifier; | ||
| 67 | } | ||
| 68 | |||
| 69 | public Mappings.EntryModifier getModifier() | ||
| 70 | { | ||
| 71 | return modifier; | ||
| 72 | } | ||
| 73 | |||
| 61 | @Override | 74 | @Override |
| 62 | public int compareTo(FieldMapping other) { | 75 | public int compareTo(FieldMapping other) { |
| 63 | return (this.obfName + this.obfType).compareTo(other.obfName + other.obfType); | 76 | return (this.obfName + this.obfType).compareTo(other.obfName + other.obfType); |
diff --git a/src/main/java/cuchaz/enigma/mapping/LocalVariableEntry.java b/src/main/java/cuchaz/enigma/mapping/LocalVariableEntry.java new file mode 100644 index 00000000..8bbaaaf6 --- /dev/null +++ b/src/main/java/cuchaz/enigma/mapping/LocalVariableEntry.java | |||
| @@ -0,0 +1,104 @@ | |||
| 1 | package cuchaz.enigma.mapping; | ||
| 2 | |||
| 3 | import cuchaz.enigma.utils.Utils; | ||
| 4 | |||
| 5 | /** | ||
| 6 | * Desc... | ||
| 7 | * Created by Thog | ||
| 8 | * 19/10/2016 | ||
| 9 | */ | ||
| 10 | public class LocalVariableEntry implements Entry | ||
| 11 | { | ||
| 12 | |||
| 13 | protected final BehaviorEntry behaviorEntry; | ||
| 14 | protected final String name; | ||
| 15 | protected final Type type; | ||
| 16 | protected final int index; | ||
| 17 | |||
| 18 | public LocalVariableEntry(BehaviorEntry behaviorEntry, int index, String name, Type type) { | ||
| 19 | if (behaviorEntry == null) { | ||
| 20 | throw new IllegalArgumentException("Behavior cannot be null!"); | ||
| 21 | } | ||
| 22 | if (index < 0) { | ||
| 23 | throw new IllegalArgumentException("Index must be non-negative!"); | ||
| 24 | } | ||
| 25 | if (name == null) { | ||
| 26 | throw new IllegalArgumentException("Variable name cannot be null!"); | ||
| 27 | } | ||
| 28 | if (type == null) { | ||
| 29 | throw new IllegalArgumentException("Variable type cannot be null!"); | ||
| 30 | } | ||
| 31 | |||
| 32 | this.behaviorEntry = behaviorEntry; | ||
| 33 | this.name = name; | ||
| 34 | this.type = type; | ||
| 35 | this.index = index; | ||
| 36 | } | ||
| 37 | |||
| 38 | |||
| 39 | public LocalVariableEntry(LocalVariableEntry other, ClassEntry newClassEntry) { | ||
| 40 | this.behaviorEntry = (BehaviorEntry) other.behaviorEntry.cloneToNewClass(newClassEntry); | ||
| 41 | this.name = other.name; | ||
| 42 | this.type = other.type; | ||
| 43 | this.index = other.index; | ||
| 44 | } | ||
| 45 | |||
| 46 | public BehaviorEntry getBehaviorEntry() { | ||
| 47 | return this.behaviorEntry; | ||
| 48 | } | ||
| 49 | |||
| 50 | public Type getType() { | ||
| 51 | return type; | ||
| 52 | } | ||
| 53 | |||
| 54 | public int getIndex() { | ||
| 55 | return index; | ||
| 56 | } | ||
| 57 | |||
| 58 | @Override | ||
| 59 | public String getName() { | ||
| 60 | return this.name; | ||
| 61 | } | ||
| 62 | |||
| 63 | @Override | ||
| 64 | public ClassEntry getClassEntry() { | ||
| 65 | return this.behaviorEntry.getClassEntry(); | ||
| 66 | } | ||
| 67 | |||
| 68 | @Override | ||
| 69 | public String getClassName() { | ||
| 70 | return this.behaviorEntry.getClassName(); | ||
| 71 | } | ||
| 72 | |||
| 73 | @Override | ||
| 74 | public LocalVariableEntry cloneToNewClass(ClassEntry classEntry) { | ||
| 75 | return new LocalVariableEntry(this, classEntry); | ||
| 76 | } | ||
| 77 | |||
| 78 | public String getMethodName() { | ||
| 79 | return this.behaviorEntry.getName(); | ||
| 80 | } | ||
| 81 | |||
| 82 | public Signature getMethodSignature() { | ||
| 83 | return this.behaviorEntry.getSignature(); | ||
| 84 | } | ||
| 85 | |||
| 86 | @Override | ||
| 87 | public int hashCode() { | ||
| 88 | return Utils.combineHashesOrdered(this.behaviorEntry, this.type.hashCode(), this.name.hashCode(), Integer.hashCode(this.index)); | ||
| 89 | } | ||
| 90 | |||
| 91 | @Override | ||
| 92 | public boolean equals(Object other) { | ||
| 93 | return other instanceof LocalVariableEntry && equals((LocalVariableEntry) other); | ||
| 94 | } | ||
| 95 | |||
| 96 | public boolean equals(LocalVariableEntry other) { | ||
| 97 | return this.behaviorEntry.equals(other.behaviorEntry) && this.type.equals(other.type) && this.name.equals(other.name) && this.index == other.index; | ||
| 98 | } | ||
| 99 | |||
| 100 | @Override | ||
| 101 | public String toString() { | ||
| 102 | return this.behaviorEntry.toString() + "(" + this.index + ":" + this.name + ":" + this.type + ")"; | ||
| 103 | } | ||
| 104 | } | ||
diff --git a/src/main/java/cuchaz/enigma/mapping/Mappings.java b/src/main/java/cuchaz/enigma/mapping/Mappings.java index 7061be79..d493dcfa 100644 --- a/src/main/java/cuchaz/enigma/mapping/Mappings.java +++ b/src/main/java/cuchaz/enigma/mapping/Mappings.java | |||
| @@ -15,11 +15,7 @@ import com.google.common.collect.Maps; | |||
| 15 | 15 | ||
| 16 | import java.io.File; | 16 | import java.io.File; |
| 17 | import java.io.IOException; | 17 | import java.io.IOException; |
| 18 | import java.util.ArrayList; | 18 | import java.util.*; |
| 19 | import java.util.Collection; | ||
| 20 | import java.util.List; | ||
| 21 | import java.util.Map; | ||
| 22 | import java.util.Set; | ||
| 23 | 19 | ||
| 24 | import com.google.common.collect.Sets; | 20 | import com.google.common.collect.Sets; |
| 25 | import cuchaz.enigma.analysis.TranslationIndex; | 21 | import cuchaz.enigma.analysis.TranslationIndex; |
| @@ -30,6 +26,7 @@ public class Mappings { | |||
| 30 | protected Map<String, ClassMapping> classesByObf; | 26 | protected Map<String, ClassMapping> classesByObf; |
| 31 | protected Map<String, ClassMapping> classesByDeobf; | 27 | protected Map<String, ClassMapping> classesByDeobf; |
| 32 | private final FormatType originMapping; | 28 | private final FormatType originMapping; |
| 29 | private Mappings previousState; | ||
| 33 | 30 | ||
| 34 | public Mappings() | 31 | public Mappings() |
| 35 | { | 32 | { |
| @@ -40,6 +37,7 @@ public class Mappings { | |||
| 40 | this.originMapping = originMapping; | 37 | this.originMapping = originMapping; |
| 41 | this.classesByObf = Maps.newHashMap(); | 38 | this.classesByObf = Maps.newHashMap(); |
| 42 | this.classesByDeobf = Maps.newHashMap(); | 39 | this.classesByDeobf = Maps.newHashMap(); |
| 40 | this.previousState = null; | ||
| 43 | } | 41 | } |
| 44 | 42 | ||
| 45 | public Collection<ClassMapping> classes() { | 43 | public Collection<ClassMapping> classes() { |
| @@ -175,6 +173,16 @@ public class Mappings { | |||
| 175 | return classMapping != null && classMapping.containsDeobfField(deobfName, obfType); | 173 | return classMapping != null && classMapping.containsDeobfField(deobfName, obfType); |
| 176 | } | 174 | } |
| 177 | 175 | ||
| 176 | public boolean containsDeobfField(ClassEntry obfClassEntry, String deobfName) { | ||
| 177 | ClassMapping classMapping = this.classesByObf.get(obfClassEntry.getName()); | ||
| 178 | if (classMapping != null) | ||
| 179 | for (FieldMapping fieldMapping : classMapping.fields()) | ||
| 180 | if (deobfName.equals(fieldMapping.getDeobfName()) || deobfName.equals(fieldMapping.getObfName())) | ||
| 181 | return true; | ||
| 182 | |||
| 183 | return false; | ||
| 184 | } | ||
| 185 | |||
| 178 | public boolean containsDeobfMethod(ClassEntry obfClassEntry, String deobfName, Signature obfSignature) { | 186 | public boolean containsDeobfMethod(ClassEntry obfClassEntry, String deobfName, Signature obfSignature) { |
| 179 | ClassMapping classMapping = this.classesByObf.get(obfClassEntry.getName()); | 187 | ClassMapping classMapping = this.classesByObf.get(obfClassEntry.getName()); |
| 180 | return classMapping != null && classMapping.containsDeobfMethod(deobfName, obfSignature); | 188 | return classMapping != null && classMapping.containsDeobfMethod(deobfName, obfSignature); |
| @@ -204,9 +212,19 @@ public class Mappings { | |||
| 204 | return originMapping; | 212 | return originMapping; |
| 205 | } | 213 | } |
| 206 | 214 | ||
| 215 | public void savePreviousState() | ||
| 216 | { | ||
| 217 | this.previousState = new Mappings(this.originMapping); | ||
| 218 | this.previousState.classesByDeobf = Maps.newHashMap(this.classesByDeobf); | ||
| 219 | this.previousState.classesByObf = Maps.newHashMap(this.classesByObf); | ||
| 220 | classesByDeobf.values().forEach(ClassMapping::resetDirty); | ||
| 221 | classesByObf.values().forEach(ClassMapping::resetDirty); | ||
| 222 | } | ||
| 223 | |||
| 207 | public void saveEnigmaMappings(File file, boolean isDirectoryFormat) throws IOException | 224 | public void saveEnigmaMappings(File file, boolean isDirectoryFormat) throws IOException |
| 208 | { | 225 | { |
| 209 | new MappingsEnigmaWriter().write(file, this, isDirectoryFormat); | 226 | new MappingsEnigmaWriter().write(file, this, isDirectoryFormat); |
| 227 | this.savePreviousState(); | ||
| 210 | } | 228 | } |
| 211 | 229 | ||
| 212 | public void saveSRGMappings(File file) throws IOException | 230 | public void saveSRGMappings(File file) throws IOException |
| @@ -214,8 +232,22 @@ public class Mappings { | |||
| 214 | new MappingsSRGWriter().write(file, this); | 232 | new MappingsSRGWriter().write(file, this); |
| 215 | } | 233 | } |
| 216 | 234 | ||
| 235 | public Mappings getPreviousState() { | ||
| 236 | return previousState; | ||
| 237 | } | ||
| 238 | |||
| 217 | public enum FormatType | 239 | public enum FormatType |
| 218 | { | 240 | { |
| 219 | ENIGMA_FILE, ENIGMA_DIRECTORY, SRG_FILE | 241 | ENIGMA_FILE, ENIGMA_DIRECTORY, SRG_FILE |
| 220 | } | 242 | } |
| 243 | |||
| 244 | public enum EntryModifier | ||
| 245 | { | ||
| 246 | UNCHANGED, PUBLIC, PROTECTED, PRIVATE; | ||
| 247 | |||
| 248 | public String getFormattedName() | ||
| 249 | { | ||
| 250 | return " ACC:" + super.toString(); | ||
| 251 | } | ||
| 252 | } | ||
| 221 | } | 253 | } |
diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java b/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java index 74c5340c..cdfed726 100644 --- a/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java +++ b/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaReader.java | |||
| @@ -37,6 +37,7 @@ public class MappingsEnigmaReader | |||
| 37 | else if (file.isDirectory()) | 37 | else if (file.isDirectory()) |
| 38 | readDirectory(mappings, file.getAbsoluteFile()); | 38 | readDirectory(mappings, file.getAbsoluteFile()); |
| 39 | } | 39 | } |
| 40 | mappings.savePreviousState(); | ||
| 40 | } | 41 | } |
| 41 | else | 42 | else |
| 42 | throw new IOException("Cannot access directory" + directory.getAbsolutePath()); | 43 | throw new IOException("Cannot access directory" + directory.getAbsolutePath()); |
| @@ -134,21 +135,51 @@ public class MappingsEnigmaReader | |||
| 134 | private ClassMapping readClass(String[] parts, boolean makeSimple) { | 135 | private ClassMapping readClass(String[] parts, boolean makeSimple) { |
| 135 | if (parts.length == 2) { | 136 | if (parts.length == 2) { |
| 136 | return new ClassMapping(parts[1]); | 137 | return new ClassMapping(parts[1]); |
| 137 | } else { | 138 | } else if (parts.length == 3) { |
| 138 | return new ClassMapping(parts[1], parts[2]); | 139 | boolean access = parts[2].startsWith("ACC:"); |
| 139 | } | 140 | ClassMapping mapping; |
| 141 | if (access) | ||
| 142 | mapping = new ClassMapping(parts[1], null, Mappings.EntryModifier.valueOf(parts[2].substring(4))); | ||
| 143 | else | ||
| 144 | mapping = new ClassMapping(parts[1], parts[2]); | ||
| 145 | |||
| 146 | return mapping; | ||
| 147 | } else if (parts.length == 4) | ||
| 148 | return new ClassMapping(parts[1], parts[2], Mappings.EntryModifier.valueOf(parts[3].substring(4))); | ||
| 149 | return null; | ||
| 140 | } | 150 | } |
| 141 | 151 | ||
| 142 | /* TEMP */ | 152 | /* TEMP */ |
| 143 | protected FieldMapping readField(String[] parts) { | 153 | protected FieldMapping readField(String[] parts) { |
| 144 | return new FieldMapping(parts[1], new Type(parts[3]), parts[2]); | 154 | FieldMapping mapping = null; |
| 155 | if (parts.length == 4) | ||
| 156 | { | ||
| 157 | boolean access = parts[3].startsWith("ACC:"); | ||
| 158 | if (access) | ||
| 159 | mapping = new FieldMapping(parts[1], new Type(parts[2]), null, | ||
| 160 | Mappings.EntryModifier.valueOf(parts[3].substring(4))); | ||
| 161 | else | ||
| 162 | mapping = new FieldMapping(parts[1], new Type(parts[3]), parts[2], Mappings.EntryModifier.UNCHANGED); | ||
| 163 | } | ||
| 164 | else if (parts.length == 5) | ||
| 165 | mapping = new FieldMapping(parts[1], new Type(parts[3]), parts[2], Mappings.EntryModifier.valueOf(parts[4].substring(4))); | ||
| 166 | return mapping; | ||
| 145 | } | 167 | } |
| 146 | 168 | ||
| 147 | private MethodMapping readMethod(String[] parts) { | 169 | private MethodMapping readMethod(String[] parts) { |
| 148 | if (parts.length == 3) { | 170 | MethodMapping mapping = null; |
| 149 | return new MethodMapping(parts[1], new Signature(parts[2])); | 171 | if (parts.length == 3) |
| 150 | } else { | 172 | mapping = new MethodMapping(parts[1], new Signature(parts[2])); |
| 151 | return new MethodMapping(parts[1], new Signature(parts[3]), parts[2]); | 173 | else if (parts.length == 4){ |
| 174 | boolean access = parts[3].startsWith("ACC:"); | ||
| 175 | if (access) | ||
| 176 | mapping = new MethodMapping(parts[1], new Signature(parts[2]), null, Mappings.EntryModifier.valueOf(parts[3].substring(4))); | ||
| 177 | else | ||
| 178 | mapping = new MethodMapping(parts[1], new Signature(parts[3]), parts[2]); | ||
| 152 | } | 179 | } |
| 180 | else if (parts.length == 5) | ||
| 181 | mapping = new MethodMapping(parts[1], new Signature(parts[3]), parts[2], | ||
| 182 | Mappings.EntryModifier.valueOf(parts[4].substring(4))); | ||
| 183 | return mapping; | ||
| 153 | } | 184 | } |
| 154 | } | 185 | } |
diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaWriter.java b/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaWriter.java index ba0720a0..c09f4a67 100644 --- a/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaWriter.java +++ b/src/main/java/cuchaz/enigma/mapping/MappingsEnigmaWriter.java | |||
| @@ -30,24 +30,14 @@ public class MappingsEnigmaWriter { | |||
| 30 | writeAsDirectory(out, mappings); | 30 | writeAsDirectory(out, mappings); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | private void deleteDir(File file) { | ||
| 34 | File[] contents = file.listFiles(); | ||
| 35 | if (contents != null) { | ||
| 36 | for (File f : contents) { | ||
| 37 | deleteDir(f); | ||
| 38 | } | ||
| 39 | } | ||
| 40 | file.delete(); | ||
| 41 | } | ||
| 42 | |||
| 43 | public void writeAsDirectory(File target, Mappings mappings) throws IOException { | 33 | public void writeAsDirectory(File target, Mappings mappings) throws IOException { |
| 44 | //TODO: Know what have changes during write to not rewrite all the things | ||
| 45 | deleteDir(target); | ||
| 46 | if (!target.exists() && !target.mkdirs()) | 34 | if (!target.exists() && !target.mkdirs()) |
| 47 | throw new IOException("Cannot create mapping directory!"); | 35 | throw new IOException("Cannot create mapping directory!"); |
| 48 | |||
| 49 | 36 | ||
| 50 | for (ClassMapping classMapping : sorted(mappings.classes())) { | 37 | for (ClassMapping classMapping : sorted(mappings.classes())) { |
| 38 | if (!classMapping.isDirty()) | ||
| 39 | continue; | ||
| 40 | this.deletePreviousClassMapping(target, classMapping); | ||
| 51 | File obFile = new File(target, classMapping.getObfFullName() + ".mapping"); | 41 | File obFile = new File(target, classMapping.getObfFullName() + ".mapping"); |
| 52 | File result; | 42 | File result; |
| 53 | if (classMapping.getDeobfName() == null) | 43 | if (classMapping.getDeobfName() == null) |
| @@ -68,8 +58,53 @@ public class MappingsEnigmaWriter { | |||
| 68 | outputWriter.close(); | 58 | outputWriter.close(); |
| 69 | } | 59 | } |
| 70 | 60 | ||
| 61 | // Remove dropped mappings | ||
| 62 | if (mappings.getPreviousState() != null) | ||
| 63 | { | ||
| 64 | List<ClassMapping> droppedClassMappings = new ArrayList<>(mappings.getPreviousState().classes()); | ||
| 65 | List<ClassMapping> classMappings = new ArrayList<>(mappings.classes()); | ||
| 66 | droppedClassMappings.removeAll(classMappings); | ||
| 67 | for (ClassMapping classMapping : droppedClassMappings) | ||
| 68 | { | ||
| 69 | File obFile = new File(target, classMapping.getObfFullName() + ".mapping"); | ||
| 70 | File result; | ||
| 71 | if (classMapping.getDeobfName() == null) | ||
| 72 | result = obFile; | ||
| 73 | else | ||
| 74 | { | ||
| 75 | // Make sure that old version of the file doesn't exist | ||
| 76 | if (obFile.exists()) | ||
| 77 | obFile.delete(); | ||
| 78 | result = new File(target, classMapping.getDeobfName() + ".mapping"); | ||
| 79 | } | ||
| 80 | if (result.exists()) | ||
| 81 | result.delete(); | ||
| 82 | } | ||
| 83 | } | ||
| 71 | } | 84 | } |
| 72 | 85 | ||
| 86 | private void deletePreviousClassMapping(File target, ClassMapping classMapping) { | ||
| 87 | File prevFile = null; | ||
| 88 | // Deob rename | ||
| 89 | if (classMapping.getDeobfName() != null && classMapping.getPreviousDeobfName() != null && !classMapping.getPreviousDeobfName().equals(classMapping.getDeobfName())) | ||
| 90 | { | ||
| 91 | prevFile = new File(target, classMapping.getPreviousDeobfName() + ".mapping"); | ||
| 92 | } | ||
| 93 | // Deob to ob rename | ||
| 94 | else if (classMapping.getDeobfName() == null && classMapping.getPreviousDeobfName() != null) | ||
| 95 | { | ||
| 96 | prevFile = new File(target, classMapping.getPreviousDeobfName() + ".mapping"); | ||
| 97 | } | ||
| 98 | // Ob to Deob rename | ||
| 99 | else if (classMapping.getDeobfName() != null && classMapping.getPreviousDeobfName() == null) | ||
| 100 | { | ||
| 101 | prevFile = new File(target, classMapping.getObfFullName() + ".mapping"); | ||
| 102 | } | ||
| 103 | |||
| 104 | if (prevFile != null && prevFile.exists()) | ||
| 105 | prevFile.delete(); | ||
| 106 | } | ||
| 107 | |||
| 73 | public void write(PrintWriter out, Mappings mappings) throws IOException { | 108 | public void write(PrintWriter out, Mappings mappings) throws IOException { |
| 74 | for (ClassMapping classMapping : sorted(mappings.classes())) { | 109 | for (ClassMapping classMapping : sorted(mappings.classes())) { |
| 75 | write(out, classMapping, 0); | 110 | write(out, classMapping, 0); |
| @@ -78,9 +113,9 @@ public class MappingsEnigmaWriter { | |||
| 78 | 113 | ||
| 79 | private void write(PrintWriter out, ClassMapping classMapping, int depth) throws IOException { | 114 | private void write(PrintWriter out, ClassMapping classMapping, int depth) throws IOException { |
| 80 | if (classMapping.getDeobfName() == null) { | 115 | if (classMapping.getDeobfName() == null) { |
| 81 | out.format("%sCLASS %s\n", getIndent(depth), classMapping.getObfFullName()); | 116 | out.format("%sCLASS %s%s\n", getIndent(depth), classMapping.getObfFullName(), classMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : classMapping.getModifier().getFormattedName()); |
| 82 | } else { | 117 | } else { |
| 83 | out.format("%sCLASS %s %s\n", getIndent(depth), classMapping.getObfFullName(), classMapping.getDeobfName()); | 118 | out.format("%sCLASS %s %s%s\n", getIndent(depth), classMapping.getObfFullName(), classMapping.getDeobfName(), classMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : classMapping.getModifier().getFormattedName()); |
| 84 | } | 119 | } |
| 85 | 120 | ||
| 86 | for (ClassMapping innerClassMapping : sorted(classMapping.innerClasses())) { | 121 | for (ClassMapping innerClassMapping : sorted(classMapping.innerClasses())) { |
| @@ -97,14 +132,17 @@ public class MappingsEnigmaWriter { | |||
| 97 | } | 132 | } |
| 98 | 133 | ||
| 99 | private void write(PrintWriter out, FieldMapping fieldMapping, int depth) throws IOException { | 134 | private void write(PrintWriter out, FieldMapping fieldMapping, int depth) throws IOException { |
| 100 | out.format("%sFIELD %s %s %s\n", getIndent(depth), fieldMapping.getObfName(), fieldMapping.getDeobfName(), fieldMapping.getObfType().toString()); | 135 | if (fieldMapping.getDeobfName() == null) |
| 136 | out.format("%sFIELD %s %s%s\n", getIndent(depth), fieldMapping.getObfName(), fieldMapping.getObfType().toString(), fieldMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : fieldMapping.getModifier().getFormattedName()); | ||
| 137 | else | ||
| 138 | out.format("%sFIELD %s %s %s%s\n", getIndent(depth), fieldMapping.getObfName(), fieldMapping.getDeobfName(), fieldMapping.getObfType().toString(), fieldMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : fieldMapping.getModifier().getFormattedName()); | ||
| 101 | } | 139 | } |
| 102 | 140 | ||
| 103 | private void write(PrintWriter out, MethodMapping methodMapping, int depth) throws IOException { | 141 | private void write(PrintWriter out, MethodMapping methodMapping, int depth) throws IOException { |
| 104 | if (methodMapping.getDeobfName() == null) { | 142 | if (methodMapping.getDeobfName() == null) { |
| 105 | out.format("%sMETHOD %s %s\n", getIndent(depth), methodMapping.getObfName(), methodMapping.getObfSignature()); | 143 | out.format("%sMETHOD %s %s%s\n", getIndent(depth), methodMapping.getObfName(), methodMapping.getObfSignature(), methodMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" :methodMapping.getModifier().getFormattedName()); |
| 106 | } else { | 144 | } else { |
| 107 | out.format("%sMETHOD %s %s %s\n", getIndent(depth), methodMapping.getObfName(), methodMapping.getDeobfName(), methodMapping.getObfSignature()); | 145 | out.format("%sMETHOD %s %s %s%s\n", getIndent(depth), methodMapping.getObfName(), methodMapping.getDeobfName(), methodMapping.getObfSignature(), methodMapping.getModifier() == Mappings.EntryModifier.UNCHANGED ? "" : methodMapping.getModifier().getFormattedName()); |
| 108 | } | 146 | } |
| 109 | 147 | ||
| 110 | for (ArgumentMapping argumentMapping : sorted(methodMapping.arguments())) { | 148 | for (ArgumentMapping argumentMapping : sorted(methodMapping.arguments())) { |
diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java b/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java index 5c299e3e..bac62503 100644 --- a/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java +++ b/src/main/java/cuchaz/enigma/mapping/MappingsRenamer.java | |||
| @@ -90,8 +90,23 @@ public class MappingsRenamer { | |||
| 90 | public void setFieldName(FieldEntry obf, String deobfName) { | 90 | public void setFieldName(FieldEntry obf, String deobfName) { |
| 91 | deobfName = NameValidator.validateFieldName(deobfName); | 91 | deobfName = NameValidator.validateFieldName(deobfName); |
| 92 | FieldEntry targetEntry = new FieldEntry(obf.getClassEntry(), deobfName, obf.getType()); | 92 | FieldEntry targetEntry = new FieldEntry(obf.getClassEntry(), deobfName, obf.getType()); |
| 93 | if (m_mappings.containsDeobfField(obf.getClassEntry(), deobfName, obf.getType()) || m_index.containsObfField(targetEntry)) { | 93 | ClassEntry definedClass = null; |
| 94 | throw new IllegalNameException(deobfName, "There is already a field with that name"); | 94 | if (m_mappings.containsDeobfField(obf.getClassEntry(), deobfName) || m_index.containsEntryWithSameName(targetEntry)) |
| 95 | definedClass = obf.getClassEntry(); | ||
| 96 | else { | ||
| 97 | for (ClassEntry ancestorEntry : this.m_index.getTranslationIndex().getAncestry(obf.getClassEntry())) { | ||
| 98 | if (m_mappings.containsDeobfField(ancestorEntry, deobfName) || m_index.containsEntryWithSameName(targetEntry.cloneToNewClass(ancestorEntry))) { | ||
| 99 | definedClass = ancestorEntry; | ||
| 100 | break; | ||
| 101 | } | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | if (definedClass != null) { | ||
| 106 | String className = m_mappings.getTranslator(TranslationDirection.Deobfuscating, m_index.getTranslationIndex()).translateClass(definedClass.getClassName()); | ||
| 107 | if (className == null) | ||
| 108 | className = definedClass.getClassName(); | ||
| 109 | throw new IllegalNameException(deobfName, "There is already a field with that name in " + className); | ||
| 95 | } | 110 | } |
| 96 | 111 | ||
| 97 | ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry()); | 112 | ClassMapping classMapping = getOrCreateClassMapping(obf.getClassEntry()); |
| @@ -306,4 +321,22 @@ public class MappingsRenamer { | |||
| 306 | } | 321 | } |
| 307 | return mappingChain; | 322 | return mappingChain; |
| 308 | } | 323 | } |
| 324 | |||
| 325 | public void setClassModifier(ClassEntry obEntry, Mappings.EntryModifier modifier) | ||
| 326 | { | ||
| 327 | ClassMapping classMapping = getOrCreateClassMapping(obEntry); | ||
| 328 | classMapping.setModifier(modifier); | ||
| 329 | } | ||
| 330 | |||
| 331 | public void setFieldModifier(FieldEntry obEntry, Mappings.EntryModifier modifier) | ||
| 332 | { | ||
| 333 | ClassMapping classMapping = getOrCreateClassMapping(obEntry.getClassEntry()); | ||
| 334 | classMapping.setFieldModifier(obEntry.getName(), obEntry.getType(), modifier); | ||
| 335 | } | ||
| 336 | |||
| 337 | public void setMethodModifier(BehaviorEntry obEntry, Mappings.EntryModifier modifier) | ||
| 338 | { | ||
| 339 | ClassMapping classMapping = getOrCreateClassMapping(obEntry.getClassEntry()); | ||
| 340 | classMapping.setMethodModifier(obEntry.getName(), obEntry.getSignature(), modifier); | ||
| 341 | } | ||
| 309 | } | 342 | } |
diff --git a/src/main/java/cuchaz/enigma/mapping/MappingsSRGWriter.java b/src/main/java/cuchaz/enigma/mapping/MappingsSRGWriter.java index 229bf464..4d0c2610 100644 --- a/src/main/java/cuchaz/enigma/mapping/MappingsSRGWriter.java +++ b/src/main/java/cuchaz/enigma/mapping/MappingsSRGWriter.java | |||
| @@ -34,25 +34,25 @@ public class MappingsSRGWriter { | |||
| 34 | if(innerClassMapping.getDeobfName() == null || innerClassMapping.getObfSimpleName() == null || innerClassMapping.getDeobfName() == null){ | 34 | if(innerClassMapping.getDeobfName() == null || innerClassMapping.getObfSimpleName() == null || innerClassMapping.getDeobfName() == null){ |
| 35 | continue; | 35 | continue; |
| 36 | } | 36 | } |
| 37 | String innerClassName = classMapping.getObfSimpleName() + "$" + innerClassMapping.getObfSimpleName().replace("none/", ""); | 37 | String innerClassName = classMapping.getObfSimpleName() + "$" + innerClassMapping.getObfSimpleName(); |
| 38 | String innerDebofClassName = classMapping.getDeobfName() + "$" + innerClassMapping.getDeobfName().replace("none/", ""); | 38 | String innerDeobfClassName = classMapping.getDeobfName() + "$" + innerClassMapping.getDeobfName(); |
| 39 | writer.write("CL: " + innerClassName + " " + classMapping.getDeobfName() + "$" + innerClassMapping.getDeobfName()); | 39 | writer.write("CL: " + innerClassName + " " + classMapping.getDeobfName() + "$" + innerClassMapping.getDeobfName()); |
| 40 | writer.write(System.lineSeparator()); | 40 | writer.write(System.lineSeparator()); |
| 41 | for (FieldMapping fieldMapping : sorted(innerClassMapping.fields())) { | 41 | for (FieldMapping fieldMapping : sorted(innerClassMapping.fields())) { |
| 42 | fieldMappings.add("FD: " + innerClassName + "/" + fieldMapping.getObfName() + " " + innerDebofClassName + "/" + fieldMapping.getDeobfName()); | 42 | fieldMappings.add("FD: " + innerClassName + "/" + fieldMapping.getObfName() + " " + innerDeobfClassName + "/" + fieldMapping.getDeobfName()); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | for (MethodMapping methodMapping : sorted(innerClassMapping.methods())) { | 45 | for (MethodMapping methodMapping : sorted(innerClassMapping.methods())) { |
| 46 | methodMappings.add("MD: " + innerClassName + "/" + methodMapping.getObfName() + " " + methodMapping.getObfSignature().toString().replace("none/", "") + " " + innerDebofClassName + "/" + methodMapping.getDeobfName() + " " + mappings.getTranslator(TranslationDirection.Deobfuscating, index).translateSignature(methodMapping.getObfSignature())); | 46 | methodMappings.add("MD: " + innerClassName + "/" + methodMapping.getObfName() + " " + methodMapping.getObfSignature().toString() + " " + innerDeobfClassName + "/" + methodMapping.getDeobfName() + " " + mappings.getTranslator(TranslationDirection.Deobfuscating, index).translateSignature(methodMapping.getObfSignature())); |
| 47 | } | 47 | } |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | for (FieldMapping fieldMapping : sorted(classMapping.fields())) { | 50 | for (FieldMapping fieldMapping : sorted(classMapping.fields())) { |
| 51 | fieldMappings.add("FD: " + classMapping.getObfFullName().replace("none/", "") + "/" + fieldMapping.getObfName() + " " + classMapping.getDeobfName() + "/" + fieldMapping.getDeobfName()); | 51 | fieldMappings.add("FD: " + classMapping.getObfFullName() + "/" + fieldMapping.getObfName() + " " + classMapping.getDeobfName() + "/" + fieldMapping.getDeobfName()); |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | for (MethodMapping methodMapping : sorted(classMapping.methods())) { | 54 | for (MethodMapping methodMapping : sorted(classMapping.methods())) { |
| 55 | methodMappings.add("MD: " + classMapping.getObfFullName().replace("none/", "") + "/" + methodMapping.getObfName() + " " + methodMapping.getObfSignature().toString().replace("none/", "") + " " + classMapping.getDeobfName() + "/" + methodMapping.getDeobfName() + " " + mappings.getTranslator(TranslationDirection.Deobfuscating, index).translateSignature(methodMapping.getObfSignature())); | 55 | methodMappings.add("MD: " + classMapping.getObfFullName() + "/" + methodMapping.getObfName() + " " + methodMapping.getObfSignature().toString() + " " + classMapping.getDeobfName() + "/" + methodMapping.getDeobfName() + " " + mappings.getTranslator(TranslationDirection.Deobfuscating, index).translateSignature(methodMapping.getObfSignature())); |
| 56 | } | 56 | } |
| 57 | } | 57 | } |
| 58 | for(String fd : fieldMappings){ | 58 | for(String fd : fieldMappings){ |
diff --git a/src/main/java/cuchaz/enigma/mapping/MethodMapping.java b/src/main/java/cuchaz/enigma/mapping/MethodMapping.java index 99b9c887..455ff6b7 100644 --- a/src/main/java/cuchaz/enigma/mapping/MethodMapping.java +++ b/src/main/java/cuchaz/enigma/mapping/MethodMapping.java | |||
| @@ -22,12 +22,17 @@ public class MethodMapping implements Comparable<MethodMapping>, MemberMapping<B | |||
| 22 | private String deobfName; | 22 | private String deobfName; |
| 23 | private Signature obfSignature; | 23 | private Signature obfSignature; |
| 24 | private Map<Integer, ArgumentMapping> arguments; | 24 | private Map<Integer, ArgumentMapping> arguments; |
| 25 | private Mappings.EntryModifier modifier; | ||
| 25 | 26 | ||
| 26 | public MethodMapping(String obfName, Signature obfSignature) { | 27 | public MethodMapping(String obfName, Signature obfSignature) { |
| 27 | this(obfName, obfSignature, null); | 28 | this(obfName, obfSignature, null,Mappings.EntryModifier.UNCHANGED); |
| 28 | } | 29 | } |
| 29 | 30 | ||
| 30 | public MethodMapping(String obfName, Signature obfSignature, String deobfName) { | 31 | public MethodMapping(String obfName, Signature obfSignature, String deobfName) { |
| 32 | this(obfName, obfSignature, deobfName, Mappings.EntryModifier.UNCHANGED); | ||
| 33 | } | ||
| 34 | |||
| 35 | public MethodMapping(String obfName, Signature obfSignature, String deobfName, Mappings.EntryModifier modifier) { | ||
| 31 | if (obfName == null) { | 36 | if (obfName == null) { |
| 32 | throw new IllegalArgumentException("obf name cannot be null!"); | 37 | throw new IllegalArgumentException("obf name cannot be null!"); |
| 33 | } | 38 | } |
| @@ -38,11 +43,13 @@ public class MethodMapping implements Comparable<MethodMapping>, MemberMapping<B | |||
| 38 | this.deobfName = NameValidator.validateMethodName(deobfName); | 43 | this.deobfName = NameValidator.validateMethodName(deobfName); |
| 39 | this.obfSignature = obfSignature; | 44 | this.obfSignature = obfSignature; |
| 40 | this.arguments = Maps.newTreeMap(); | 45 | this.arguments = Maps.newTreeMap(); |
| 46 | this.modifier = modifier; | ||
| 41 | } | 47 | } |
| 42 | 48 | ||
| 43 | public MethodMapping(MethodMapping other, ClassNameReplacer obfClassNameReplacer) { | 49 | public MethodMapping(MethodMapping other, ClassNameReplacer obfClassNameReplacer) { |
| 44 | this.obfName = other.obfName; | 50 | this.obfName = other.obfName; |
| 45 | this.deobfName = other.deobfName; | 51 | this.deobfName = other.deobfName; |
| 52 | this.modifier = other.modifier; | ||
| 46 | this.obfSignature = new Signature(other.obfSignature, obfClassNameReplacer); | 53 | this.obfSignature = new Signature(other.obfSignature, obfClassNameReplacer); |
| 47 | this.arguments = Maps.newTreeMap(); | 54 | this.arguments = Maps.newTreeMap(); |
| 48 | for (Map.Entry<Integer,ArgumentMapping> entry : other.arguments.entrySet()) { | 55 | for (Map.Entry<Integer,ArgumentMapping> entry : other.arguments.entrySet()) { |
| @@ -187,4 +194,14 @@ public class MethodMapping implements Comparable<MethodMapping>, MemberMapping<B | |||
| 187 | return new MethodEntry(classEntry, this.obfName, this.obfSignature); | 194 | return new MethodEntry(classEntry, this.obfName, this.obfSignature); |
| 188 | } | 195 | } |
| 189 | } | 196 | } |
| 197 | |||
| 198 | public Mappings.EntryModifier getModifier() | ||
| 199 | { | ||
| 200 | return modifier; | ||
| 201 | } | ||
| 202 | |||
| 203 | public void setModifier(Mappings.EntryModifier modifier) | ||
| 204 | { | ||
| 205 | this.modifier = modifier; | ||
| 206 | } | ||
| 190 | } | 207 | } |
diff --git a/src/main/java/cuchaz/enigma/mapping/Translator.java b/src/main/java/cuchaz/enigma/mapping/Translator.java index b05714cc..e94009ee 100644 --- a/src/main/java/cuchaz/enigma/mapping/Translator.java +++ b/src/main/java/cuchaz/enigma/mapping/Translator.java | |||
| @@ -58,6 +58,8 @@ public class Translator { | |||
| 58 | return (T) translateEntry((ConstructorEntry) entry); | 58 | return (T) translateEntry((ConstructorEntry) entry); |
| 59 | } else if (entry instanceof ArgumentEntry) { | 59 | } else if (entry instanceof ArgumentEntry) { |
| 60 | return (T) translateEntry((ArgumentEntry) entry); | 60 | return (T) translateEntry((ArgumentEntry) entry); |
| 61 | } else if (entry instanceof LocalVariableEntry) { | ||
| 62 | return (T) translateEntry((LocalVariableEntry) entry); | ||
| 61 | } else { | 63 | } else { |
| 62 | throw new Error("Unknown entry type: " + entry.getClass().getName()); | 64 | throw new Error("Unknown entry type: " + entry.getClass().getName()); |
| 63 | } | 65 | } |
| @@ -74,11 +76,28 @@ public class Translator { | |||
| 74 | return translate(entry); | 76 | return translate(entry); |
| 75 | } else if (entry instanceof ArgumentEntry) { | 77 | } else if (entry instanceof ArgumentEntry) { |
| 76 | return translate((ArgumentEntry) entry); | 78 | return translate((ArgumentEntry) entry); |
| 79 | } else if (entry instanceof LocalVariableEntry) { | ||
| 80 | return translate((LocalVariableEntry) entry); | ||
| 77 | } else { | 81 | } else { |
| 78 | throw new Error("Unknown entry type: " + entry.getClass().getName()); | 82 | throw new Error("Unknown entry type: " + entry.getClass().getName()); |
| 79 | } | 83 | } |
| 80 | } | 84 | } |
| 81 | 85 | ||
| 86 | public String translate(LocalVariableEntry in) | ||
| 87 | { | ||
| 88 | LocalVariableEntry translated = translateEntry(in); | ||
| 89 | if (translated.equals(in)) { | ||
| 90 | return null; | ||
| 91 | } | ||
| 92 | return translated.getName(); | ||
| 93 | } | ||
| 94 | |||
| 95 | public LocalVariableEntry translateEntry(LocalVariableEntry in) | ||
| 96 | { | ||
| 97 | // TODO: Implement it | ||
| 98 | return in; | ||
| 99 | } | ||
| 100 | |||
| 82 | public String translate(ClassEntry in) { | 101 | public String translate(ClassEntry in) { |
| 83 | ClassEntry translated = translateEntry(in); | 102 | ClassEntry translated = translateEntry(in); |
| 84 | if (translated.equals(in)) { | 103 | if (translated.equals(in)) { |
| @@ -310,4 +329,27 @@ public class Translator { | |||
| 310 | assert (mappingsChain.size() == parts.length); | 329 | assert (mappingsChain.size() == parts.length); |
| 311 | return mappingsChain; | 330 | return mappingsChain; |
| 312 | } | 331 | } |
| 332 | |||
| 333 | public Mappings.EntryModifier getModifier(Entry entry) | ||
| 334 | { | ||
| 335 | ClassMapping classMapping = findClassMapping(entry.getClassEntry()); | ||
| 336 | if (classMapping != null && !entry.getName().equals("<clinit>")) | ||
| 337 | { | ||
| 338 | if (entry instanceof ClassEntry) | ||
| 339 | return classMapping.getModifier(); | ||
| 340 | else if (entry instanceof FieldEntry) | ||
| 341 | { | ||
| 342 | FieldMapping fieldMapping = classMapping.getFieldByObf(entry.getName(), ((FieldEntry) entry).getType()); | ||
| 343 | return fieldMapping != null ? fieldMapping.getModifier() : Mappings.EntryModifier.UNCHANGED; | ||
| 344 | } | ||
| 345 | else if (entry instanceof BehaviorEntry) | ||
| 346 | { | ||
| 347 | MethodMapping methodMapping = classMapping.getMethodByObf(entry.getName(), ((BehaviorEntry) entry).getSignature()); | ||
| 348 | return methodMapping != null ? methodMapping.getModifier() : Mappings.EntryModifier.UNCHANGED; | ||
| 349 | } | ||
| 350 | else | ||
| 351 | throw new Error("Unknown entry type: " + entry.getClass().getName()); | ||
| 352 | } | ||
| 353 | return Mappings.EntryModifier.UNCHANGED; | ||
| 354 | } | ||
| 313 | } | 355 | } |