diff options
Diffstat (limited to 'src/main/java')
12 files changed, 954 insertions, 45 deletions
diff --git a/src/main/java/cuchaz/enigma/Deobfuscator.java b/src/main/java/cuchaz/enigma/Deobfuscator.java index e9a998da..82d0775b 100644 --- a/src/main/java/cuchaz/enigma/Deobfuscator.java +++ b/src/main/java/cuchaz/enigma/Deobfuscator.java | |||
| @@ -21,13 +21,12 @@ import com.strobel.decompiler.DecompilerContext; | |||
| 21 | import com.strobel.decompiler.DecompilerSettings; | 21 | import com.strobel.decompiler.DecompilerSettings; |
| 22 | import com.strobel.decompiler.PlainTextOutput; | 22 | import com.strobel.decompiler.PlainTextOutput; |
| 23 | import com.strobel.decompiler.languages.java.JavaOutputVisitor; | 23 | import com.strobel.decompiler.languages.java.JavaOutputVisitor; |
| 24 | import com.strobel.decompiler.languages.java.ast.AstBuilder; | 24 | import com.strobel.decompiler.languages.java.ast.*; |
| 25 | import com.strobel.decompiler.languages.java.ast.CompilationUnit; | ||
| 26 | import com.strobel.decompiler.languages.java.ast.InsertParenthesesVisitor; | ||
| 27 | import cuchaz.enigma.analysis.*; | 25 | import cuchaz.enigma.analysis.*; |
| 28 | import cuchaz.enigma.bytecode.ClassProtectifier; | 26 | import cuchaz.enigma.bytecode.ClassProtectifier; |
| 29 | import cuchaz.enigma.bytecode.ClassPublifier; | 27 | import cuchaz.enigma.bytecode.ClassPublifier; |
| 30 | import cuchaz.enigma.mapping.*; | 28 | import cuchaz.enigma.mapping.*; |
| 29 | import cuchaz.enigma.mapping.javadoc.JavaDocMapping; | ||
| 31 | import cuchaz.enigma.utils.Utils; | 30 | import cuchaz.enigma.utils.Utils; |
| 32 | import javassist.CtClass; | 31 | import javassist.CtClass; |
| 33 | import javassist.bytecode.Descriptor; | 32 | import javassist.bytecode.Descriptor; |
| @@ -40,6 +39,8 @@ import java.util.jar.JarOutputStream; | |||
| 40 | 39 | ||
| 41 | public class Deobfuscator { | 40 | public class Deobfuscator { |
| 42 | 41 | ||
| 42 | private final JavaDocMapping docMapping; | ||
| 43 | |||
| 43 | public interface ProgressListener { | 44 | public interface ProgressListener { |
| 44 | void init(int totalWork, String title); | 45 | void init(int totalWork, String title); |
| 45 | 46 | ||
| @@ -75,6 +76,8 @@ public class Deobfuscator { | |||
| 75 | this.renamer = new MappingsRenamer(this.jarIndex, null); | 76 | this.renamer = new MappingsRenamer(this.jarIndex, null); |
| 76 | // init mappings | 77 | // init mappings |
| 77 | setMappings(new Mappings()); | 78 | setMappings(new Mappings()); |
| 79 | |||
| 80 | this.docMapping = new JavaDocMapping(); | ||
| 78 | } | 81 | } |
| 79 | 82 | ||
| 80 | public JarFile getJar() { | 83 | public JarFile getJar() { |
| @@ -93,6 +96,11 @@ public class Deobfuscator { | |||
| 93 | return this.mappings; | 96 | return this.mappings; |
| 94 | } | 97 | } |
| 95 | 98 | ||
| 99 | public JavaDocMapping getDocMapping() | ||
| 100 | { | ||
| 101 | return docMapping; | ||
| 102 | } | ||
| 103 | |||
| 96 | public void setMappings(Mappings val) { | 104 | public void setMappings(Mappings val) { |
| 97 | setMappings(val, true); | 105 | setMappings(val, true); |
| 98 | } | 106 | } |
| @@ -176,7 +184,8 @@ public class Deobfuscator { | |||
| 176 | this.jar, | 184 | this.jar, |
| 177 | this.jarIndex, | 185 | this.jarIndex, |
| 178 | getTranslator(TranslationDirection.Obfuscating), | 186 | getTranslator(TranslationDirection.Obfuscating), |
| 179 | getTranslator(TranslationDirection.Deobfuscating) | 187 | getTranslator(TranslationDirection.Deobfuscating), |
| 188 | this.docMapping | ||
| 180 | ); | 189 | ); |
| 181 | this.settings.setTypeLoader(loader); | 190 | this.settings.setTypeLoader(loader); |
| 182 | 191 | ||
| @@ -204,6 +213,14 @@ public class Deobfuscator { | |||
| 204 | } | 213 | } |
| 205 | 214 | ||
| 206 | public SourceIndex getSourceIndex(CompilationUnit sourceTree, String source, Boolean ignoreBadTokens) { | 215 | public SourceIndex getSourceIndex(CompilationUnit sourceTree, String source, Boolean ignoreBadTokens) { |
| 216 | List<Annotation> annotations = new ArrayList<>(); | ||
| 217 | |||
| 218 | sourceTree.acceptVisitor(new JavadocIndexVisitor(), annotations); | ||
| 219 | |||
| 220 | // DEBUG | ||
| 221 | // sourceTree.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); | ||
| 222 | |||
| 223 | annotations.forEach(AstNode::remove); | ||
| 207 | 224 | ||
| 208 | // build the source index | 225 | // build the source index |
| 209 | SourceIndex index; | 226 | SourceIndex index; |
| @@ -214,9 +231,6 @@ public class Deobfuscator { | |||
| 214 | } | 231 | } |
| 215 | sourceTree.acceptVisitor(new SourceIndexVisitor(), index); | 232 | sourceTree.acceptVisitor(new SourceIndexVisitor(), index); |
| 216 | 233 | ||
| 217 | // DEBUG | ||
| 218 | // sourceTree.acceptVisitor( new TreeDumpVisitor( new File( "tree.txt" ) ), null ); | ||
| 219 | |||
| 220 | // resolve all the classes in the source references | 234 | // resolve all the classes in the source references |
| 221 | for (Token token : index.referenceTokens()) { | 235 | for (Token token : index.referenceTokens()) { |
| 222 | EntryReference<Entry, Entry> deobfReference = index.getDeobfReference(token); | 236 | EntryReference<Entry, Entry> deobfReference = index.getDeobfReference(token); |
| @@ -234,11 +248,52 @@ public class Deobfuscator { | |||
| 234 | deobfReference.entry = deobfuscateEntry(obfEntry); | 248 | deobfReference.entry = deobfuscateEntry(obfEntry); |
| 235 | index.replaceDeobfReference(token, deobfReference); | 249 | index.replaceDeobfReference(token, deobfReference); |
| 236 | } | 250 | } |
| 237 | |||
| 238 | // DEBUG | 251 | // DEBUG |
| 239 | // System.out.println( token + " -> " + reference + " -> " + index.getReferenceToken( reference ) ); | 252 | // System.out.println( token + " -> " + reference + " -> " + index.getReferenceToken( reference ) ); |
| 240 | } | 253 | } |
| 241 | 254 | ||
| 255 | source = index.getSource(); | ||
| 256 | |||
| 257 | for (Annotation annotation : annotations) | ||
| 258 | { | ||
| 259 | // Get the decompiler before calling getText (after that we can get it...) | ||
| 260 | int pos = annotation.getRegion().getBeginLine(); | ||
| 261 | |||
| 262 | // Get the exact annotation | ||
| 263 | String original = annotation.getText(); | ||
| 264 | |||
| 265 | int originalAnnotationPosInSource = source.indexOf(original) - 1; | ||
| 266 | int prevLineBreak; | ||
| 267 | for (prevLineBreak = originalAnnotationPosInSource; prevLineBreak < source.length(); prevLineBreak--) | ||
| 268 | { | ||
| 269 | if (source.charAt(prevLineBreak) != ' ') | ||
| 270 | break; | ||
| 271 | } | ||
| 272 | |||
| 273 | // Format | ||
| 274 | String theComment = docMapping.convertAnnotationToJavaDoc(annotation, originalAnnotationPosInSource - prevLineBreak); | ||
| 275 | |||
| 276 | // Replace the annotation by the JavaDoc | ||
| 277 | source = source.replace(original, theComment); | ||
| 278 | |||
| 279 | // Calculate the offset of the changes for tokens | ||
| 280 | int offset = theComment.length() - original.length(); | ||
| 281 | |||
| 282 | // Propagate positions changes | ||
| 283 | for (Token token : index.referenceTokens()) | ||
| 284 | if (pos <= token.getRegion().getBeginLine()) | ||
| 285 | token.offsetColum += offset; | ||
| 286 | } | ||
| 287 | |||
| 288 | // Set the source because of JavaDoc changes | ||
| 289 | index.setSource(source); | ||
| 290 | |||
| 291 | // Reccompute the start and end using the offset | ||
| 292 | for (Token token : index.referenceTokens()) | ||
| 293 | token.computePos(); | ||
| 294 | |||
| 295 | annotations.clear(); | ||
| 296 | |||
| 242 | return index; | 297 | return index; |
| 243 | } | 298 | } |
| 244 | 299 | ||
| @@ -387,8 +442,7 @@ public class Deobfuscator { | |||
| 387 | this.jar, | 442 | this.jar, |
| 388 | this.jarIndex, | 443 | this.jarIndex, |
| 389 | getTranslator(TranslationDirection.Obfuscating), | 444 | getTranslator(TranslationDirection.Obfuscating), |
| 390 | getTranslator(TranslationDirection.Deobfuscating) | 445 | getTranslator(TranslationDirection.Deobfuscating), this.docMapping); |
| 391 | ); | ||
| 392 | transformJar(out, progress, loader::transformClass); | 446 | transformJar(out, progress, loader::transformClass); |
| 393 | } | 447 | } |
| 394 | 448 | ||
| @@ -422,7 +476,7 @@ public class Deobfuscator { | |||
| 422 | outJar.write(c.toBytecode()); | 476 | outJar.write(c.toBytecode()); |
| 423 | outJar.closeEntry(); | 477 | outJar.closeEntry(); |
| 424 | } catch (Throwable t) { | 478 | } catch (Throwable t) { |
| 425 | throw new Error("Unable to transform class " + c.getName(), t); | 479 | throw new Error("Unable to tryToAddJavaDoc class " + c.getName(), t); |
| 426 | } | 480 | } |
| 427 | } | 481 | } |
| 428 | if (progress != null) { | 482 | if (progress != null) { |
| @@ -508,7 +562,7 @@ public class Deobfuscator { | |||
| 508 | } | 562 | } |
| 509 | 563 | ||
| 510 | public boolean isRenameable(EntryReference<Entry, Entry> obfReference, boolean activeHack) { | 564 | public boolean isRenameable(EntryReference<Entry, Entry> obfReference, boolean activeHack) { |
| 511 | return obfReference.isNamed() && isObfuscatedIdentifier(obfReference.getNameableEntry(), activeHack); | 565 | return obfReference != null && obfReference.isNamed() && isObfuscatedIdentifier(obfReference.getNameableEntry(), activeHack); |
| 512 | } | 566 | } |
| 513 | 567 | ||
| 514 | public boolean isRenameable(EntryReference<Entry, Entry> obfReference) { | 568 | public boolean isRenameable(EntryReference<Entry, Entry> obfReference) { |
diff --git a/src/main/java/cuchaz/enigma/TranslatingTypeLoader.java b/src/main/java/cuchaz/enigma/TranslatingTypeLoader.java index e4c162da..6ddfa634 100644 --- a/src/main/java/cuchaz/enigma/TranslatingTypeLoader.java +++ b/src/main/java/cuchaz/enigma/TranslatingTypeLoader.java | |||
| @@ -12,10 +12,17 @@ package cuchaz.enigma; | |||
| 12 | 12 | ||
| 13 | import com.google.common.collect.Lists; | 13 | import com.google.common.collect.Lists; |
| 14 | import com.google.common.collect.Maps; | 14 | import com.google.common.collect.Maps; |
| 15 | |||
| 16 | import com.strobel.assembler.metadata.Buffer; | 15 | import com.strobel.assembler.metadata.Buffer; |
| 17 | import com.strobel.assembler.metadata.ClasspathTypeLoader; | 16 | import com.strobel.assembler.metadata.ClasspathTypeLoader; |
| 18 | import com.strobel.assembler.metadata.ITypeLoader; | 17 | import com.strobel.assembler.metadata.ITypeLoader; |
| 18 | import cuchaz.enigma.analysis.BridgeMarker; | ||
| 19 | import cuchaz.enigma.analysis.JarIndex; | ||
| 20 | import cuchaz.enigma.bytecode.*; | ||
| 21 | import cuchaz.enigma.mapping.ClassEntry; | ||
| 22 | import cuchaz.enigma.mapping.Translator; | ||
| 23 | import cuchaz.enigma.mapping.javadoc.JavaDocMapping; | ||
| 24 | import javassist.*; | ||
| 25 | import javassist.bytecode.Descriptor; | ||
| 19 | 26 | ||
| 20 | import java.io.ByteArrayOutputStream; | 27 | import java.io.ByteArrayOutputStream; |
| 21 | import java.io.IOException; | 28 | import java.io.IOException; |
| @@ -25,14 +32,6 @@ import java.util.Map; | |||
| 25 | import java.util.jar.JarEntry; | 32 | import java.util.jar.JarEntry; |
| 26 | import java.util.jar.JarFile; | 33 | import java.util.jar.JarFile; |
| 27 | 34 | ||
| 28 | import cuchaz.enigma.analysis.BridgeMarker; | ||
| 29 | import cuchaz.enigma.analysis.JarIndex; | ||
| 30 | import cuchaz.enigma.bytecode.*; | ||
| 31 | import cuchaz.enigma.mapping.ClassEntry; | ||
| 32 | import cuchaz.enigma.mapping.Translator; | ||
| 33 | import javassist.*; | ||
| 34 | import javassist.bytecode.Descriptor; | ||
| 35 | |||
| 36 | public class TranslatingTypeLoader implements ITypeLoader { | 35 | public class TranslatingTypeLoader implements ITypeLoader { |
| 37 | 36 | ||
| 38 | private JarFile jar; | 37 | private JarFile jar; |
| @@ -41,14 +40,18 @@ public class TranslatingTypeLoader implements ITypeLoader { | |||
| 41 | private Translator deobfuscatingTranslator; | 40 | private Translator deobfuscatingTranslator; |
| 42 | private Map<String, byte[]> cache; | 41 | private Map<String, byte[]> cache; |
| 43 | private ClasspathTypeLoader defaultTypeLoader; | 42 | private ClasspathTypeLoader defaultTypeLoader; |
| 43 | private JavaDocMapping docMapping; | ||
| 44 | 44 | ||
| 45 | public TranslatingTypeLoader(JarFile jar, JarIndex jarIndex, Translator obfuscatingTranslator, Translator deobfuscatingTranslator) { | 45 | public TranslatingTypeLoader(JarFile jar, JarIndex jarIndex, Translator obfuscatingTranslator, |
| 46 | Translator deobfuscatingTranslator, JavaDocMapping docMapping) { | ||
| 46 | this.jar = jar; | 47 | this.jar = jar; |
| 47 | this.jarIndex = jarIndex; | 48 | this.jarIndex = jarIndex; |
| 48 | this.obfuscatingTranslator = obfuscatingTranslator; | 49 | this.obfuscatingTranslator = obfuscatingTranslator; |
| 49 | this.deobfuscatingTranslator = deobfuscatingTranslator; | 50 | this.deobfuscatingTranslator = deobfuscatingTranslator; |
| 50 | this.cache = Maps.newHashMap(); | 51 | this.cache = Maps.newHashMap(); |
| 51 | this.defaultTypeLoader = new ClasspathTypeLoader(); | 52 | this.defaultTypeLoader = new ClasspathTypeLoader(); |
| 53 | this.docMapping = docMapping; | ||
| 54 | this.docMapping.cleanBehaviors(); | ||
| 52 | } | 55 | } |
| 53 | 56 | ||
| 54 | public void clearCache() { | 57 | public void clearCache() { |
| @@ -214,8 +217,7 @@ public class TranslatingTypeLoader implements ITypeLoader { | |||
| 214 | new BridgeMarker(this.jarIndex).markBridges(c); | 217 | new BridgeMarker(this.jarIndex).markBridges(c); |
| 215 | new MethodParameterWriter(this.deobfuscatingTranslator).writeMethodArguments(c); | 218 | new MethodParameterWriter(this.deobfuscatingTranslator).writeMethodArguments(c); |
| 216 | new LocalVariableRenamer(this.deobfuscatingTranslator).rename(c); | 219 | new LocalVariableRenamer(this.deobfuscatingTranslator).rename(c); |
| 217 | new ClassTranslator(this.deobfuscatingTranslator).translate(c); | 220 | new ClassTranslator(this.deobfuscatingTranslator, this.docMapping).translate(c); |
| 218 | |||
| 219 | return c; | 221 | return c; |
| 220 | } | 222 | } |
| 221 | 223 | ||
diff --git a/src/main/java/cuchaz/enigma/analysis/JavadocIndexVisitor.java b/src/main/java/cuchaz/enigma/analysis/JavadocIndexVisitor.java new file mode 100644 index 00000000..2845b497 --- /dev/null +++ b/src/main/java/cuchaz/enigma/analysis/JavadocIndexVisitor.java | |||
| @@ -0,0 +1,375 @@ | |||
| 1 | package cuchaz.enigma.analysis; | ||
| 2 | |||
| 3 | import com.strobel.decompiler.languages.java.ast.*; | ||
| 4 | import com.strobel.decompiler.patterns.Pattern; | ||
| 5 | |||
| 6 | import java.util.List; | ||
| 7 | |||
| 8 | /** | ||
| 9 | * Permit to data all javadoc markers | ||
| 10 | * Created by Thog | ||
| 11 | * 19/08/2016 | ||
| 12 | */ | ||
| 13 | public class JavadocIndexVisitor implements IAstVisitor<List<Annotation>, Void> | ||
| 14 | { | ||
| 15 | |||
| 16 | protected Void recurse(AstNode node, List<Annotation> data) { | ||
| 17 | for (final AstNode child : node.getChildren()) { | ||
| 18 | child.acceptVisitor(this, data); | ||
| 19 | } | ||
| 20 | return null; | ||
| 21 | } | ||
| 22 | |||
| 23 | @Override | ||
| 24 | public Void visitMethodDeclaration(MethodDeclaration node, List<Annotation> data) { | ||
| 25 | return recurse(node, data); | ||
| 26 | } | ||
| 27 | |||
| 28 | @Override | ||
| 29 | public Void visitConstructorDeclaration(ConstructorDeclaration node, List<Annotation> data) { | ||
| 30 | return recurse(node, data); | ||
| 31 | } | ||
| 32 | |||
| 33 | @Override | ||
| 34 | public Void visitFieldDeclaration(FieldDeclaration node, List<Annotation> data) { | ||
| 35 | return recurse(node, data); | ||
| 36 | } | ||
| 37 | |||
| 38 | @Override public Void visitTypeDeclaration(TypeDeclaration node, List<Annotation> data) | ||
| 39 | { | ||
| 40 | return recurse(node, data); | ||
| 41 | } | ||
| 42 | |||
| 43 | @Override | ||
| 44 | public Void visitEnumValueDeclaration(EnumValueDeclaration node, List<Annotation> data) { | ||
| 45 | return recurse(node, data); | ||
| 46 | } | ||
| 47 | |||
| 48 | @Override | ||
| 49 | public Void visitParameterDeclaration(ParameterDeclaration node, List<Annotation> data) { | ||
| 50 | return recurse(node, data); | ||
| 51 | } | ||
| 52 | |||
| 53 | @Override | ||
| 54 | public Void visitInvocationExpression(InvocationExpression node, List<Annotation> data) { | ||
| 55 | return recurse(node, data); | ||
| 56 | } | ||
| 57 | |||
| 58 | @Override | ||
| 59 | public Void visitMemberReferenceExpression(MemberReferenceExpression node, List<Annotation> data) { | ||
| 60 | return recurse(node, data); | ||
| 61 | } | ||
| 62 | |||
| 63 | @Override | ||
| 64 | public Void visitSimpleType(SimpleType node, List<Annotation> data) { | ||
| 65 | return recurse(node, data); | ||
| 66 | } | ||
| 67 | |||
| 68 | @Override | ||
| 69 | public Void visitIdentifierExpression(IdentifierExpression node, List<Annotation> data) { | ||
| 70 | return recurse(node, data); | ||
| 71 | } | ||
| 72 | |||
| 73 | @Override | ||
| 74 | public Void visitComment(Comment node, List<Annotation> data) { | ||
| 75 | return recurse(node, data); | ||
| 76 | } | ||
| 77 | |||
| 78 | @Override | ||
| 79 | public Void visitPatternPlaceholder(AstNode node, Pattern pattern, List<Annotation> data) { | ||
| 80 | return recurse(node, data); | ||
| 81 | } | ||
| 82 | |||
| 83 | @Override | ||
| 84 | public Void visitTypeReference(TypeReferenceExpression node, List<Annotation> data) { | ||
| 85 | return recurse(node, data); | ||
| 86 | } | ||
| 87 | |||
| 88 | @Override | ||
| 89 | public Void visitJavaTokenNode(JavaTokenNode node, List<Annotation> data) { | ||
| 90 | return recurse(node, data); | ||
| 91 | } | ||
| 92 | |||
| 93 | @Override | ||
| 94 | public Void visitIdentifier(Identifier node, List<Annotation> data) { | ||
| 95 | return recurse(node, data); | ||
| 96 | } | ||
| 97 | |||
| 98 | @Override | ||
| 99 | public Void visitNullReferenceExpression(NullReferenceExpression node, List<Annotation> data) { | ||
| 100 | return recurse(node, data); | ||
| 101 | } | ||
| 102 | |||
| 103 | @Override | ||
| 104 | public Void visitThisReferenceExpression(ThisReferenceExpression node, List<Annotation> data) { | ||
| 105 | return recurse(node, data); | ||
| 106 | } | ||
| 107 | |||
| 108 | @Override | ||
| 109 | public Void visitSuperReferenceExpression(SuperReferenceExpression node, List<Annotation> data) { | ||
| 110 | return recurse(node, data); | ||
| 111 | } | ||
| 112 | |||
| 113 | @Override | ||
| 114 | public Void visitClassOfExpression(ClassOfExpression node, List<Annotation> data) { | ||
| 115 | return recurse(node, data); | ||
| 116 | } | ||
| 117 | |||
| 118 | @Override | ||
| 119 | public Void visitBlockStatement(BlockStatement node, List<Annotation> data) { | ||
| 120 | return recurse(node, data); | ||
| 121 | } | ||
| 122 | |||
| 123 | @Override | ||
| 124 | public Void visitExpressionStatement(ExpressionStatement node, List<Annotation> data) { | ||
| 125 | return recurse(node, data); | ||
| 126 | } | ||
| 127 | |||
| 128 | @Override | ||
| 129 | public Void visitBreakStatement(BreakStatement node, List<Annotation> data) { | ||
| 130 | return recurse(node, data); | ||
| 131 | } | ||
| 132 | |||
| 133 | @Override | ||
| 134 | public Void visitContinueStatement(ContinueStatement node, List<Annotation> data) { | ||
| 135 | return recurse(node, data); | ||
| 136 | } | ||
| 137 | |||
| 138 | @Override | ||
| 139 | public Void visitDoWhileStatement(DoWhileStatement node, List<Annotation> data) { | ||
| 140 | return recurse(node, data); | ||
| 141 | } | ||
| 142 | |||
| 143 | @Override | ||
| 144 | public Void visitEmptyStatement(EmptyStatement node, List<Annotation> data) { | ||
| 145 | return recurse(node, data); | ||
| 146 | } | ||
| 147 | |||
| 148 | @Override | ||
| 149 | public Void visitIfElseStatement(IfElseStatement node, List<Annotation> data) { | ||
| 150 | return recurse(node, data); | ||
| 151 | } | ||
| 152 | |||
| 153 | @Override | ||
| 154 | public Void visitLabelStatement(LabelStatement node, List<Annotation> data) { | ||
| 155 | return recurse(node, data); | ||
| 156 | } | ||
| 157 | |||
| 158 | @Override | ||
| 159 | public Void visitLabeledStatement(LabeledStatement node, List<Annotation> data) { | ||
| 160 | return recurse(node, data); | ||
| 161 | } | ||
| 162 | |||
| 163 | @Override | ||
| 164 | public Void visitReturnStatement(ReturnStatement node, List<Annotation> data) { | ||
| 165 | return recurse(node, data); | ||
| 166 | } | ||
| 167 | |||
| 168 | @Override | ||
| 169 | public Void visitSwitchStatement(SwitchStatement node, List<Annotation> data) { | ||
| 170 | return recurse(node, data); | ||
| 171 | } | ||
| 172 | |||
| 173 | @Override | ||
| 174 | public Void visitSwitchSection(SwitchSection node, List<Annotation> data) { | ||
| 175 | return recurse(node, data); | ||
| 176 | } | ||
| 177 | |||
| 178 | @Override | ||
| 179 | public Void visitCaseLabel(CaseLabel node, List<Annotation> data) { | ||
| 180 | return recurse(node, data); | ||
| 181 | } | ||
| 182 | |||
| 183 | @Override | ||
| 184 | public Void visitThrowStatement(ThrowStatement node, List<Annotation> data) { | ||
| 185 | return recurse(node, data); | ||
| 186 | } | ||
| 187 | |||
| 188 | @Override | ||
| 189 | public Void visitCatchClause(CatchClause node, List<Annotation> data) { | ||
| 190 | return recurse(node, data); | ||
| 191 | } | ||
| 192 | |||
| 193 | @Override | ||
| 194 | public Void visitAnnotation(Annotation node, List<Annotation> data) { | ||
| 195 | String annotationType = node.getFirstChild().toString(); | ||
| 196 | if (annotationType.startsWith("FieldDoc") || annotationType.startsWith("MethodDoc") || annotationType.startsWith("ClassDoc")) | ||
| 197 | data.add(node); | ||
| 198 | return recurse(node, data); | ||
| 199 | } | ||
| 200 | |||
| 201 | @Override | ||
| 202 | public Void visitNewLine(NewLineNode node, List<Annotation> data) { | ||
| 203 | return recurse(node, data); | ||
| 204 | } | ||
| 205 | |||
| 206 | @Override | ||
| 207 | public Void visitVariableDeclaration(VariableDeclarationStatement node, List<Annotation> data) { | ||
| 208 | return recurse(node, data); | ||
| 209 | } | ||
| 210 | |||
| 211 | @Override | ||
| 212 | public Void visitVariableInitializer(VariableInitializer node, List<Annotation> data) { | ||
| 213 | return recurse(node, data); | ||
| 214 | } | ||
| 215 | |||
| 216 | @Override | ||
| 217 | public Void visitText(TextNode node, List<Annotation> data) { | ||
| 218 | return recurse(node, data); | ||
| 219 | } | ||
| 220 | |||
| 221 | @Override | ||
| 222 | public Void visitImportDeclaration(ImportDeclaration node, List<Annotation> data) { | ||
| 223 | return recurse(node, data); | ||
| 224 | } | ||
| 225 | |||
| 226 | @Override | ||
| 227 | public Void visitInitializerBlock(InstanceInitializer node, List<Annotation> data) { | ||
| 228 | return recurse(node, data); | ||
| 229 | } | ||
| 230 | |||
| 231 | @Override | ||
| 232 | public Void visitTypeParameterDeclaration(TypeParameterDeclaration node, List<Annotation> data) { | ||
| 233 | return recurse(node, data); | ||
| 234 | } | ||
| 235 | |||
| 236 | @Override | ||
| 237 | public Void visitCompilationUnit(CompilationUnit node, List<Annotation> data) { | ||
| 238 | return recurse(node, data); | ||
| 239 | } | ||
| 240 | |||
| 241 | @Override | ||
| 242 | public Void visitPackageDeclaration(PackageDeclaration node, List<Annotation> data) { | ||
| 243 | return recurse(node, data); | ||
| 244 | } | ||
| 245 | |||
| 246 | @Override | ||
| 247 | public Void visitArraySpecifier(ArraySpecifier node, List<Annotation> data) { | ||
| 248 | return recurse(node, data); | ||
| 249 | } | ||
| 250 | |||
| 251 | @Override | ||
| 252 | public Void visitComposedType(ComposedType node, List<Annotation> data) { | ||
| 253 | return recurse(node, data); | ||
| 254 | } | ||
| 255 | |||
| 256 | @Override | ||
| 257 | public Void visitWhileStatement(WhileStatement node, List<Annotation> data) { | ||
| 258 | return recurse(node, data); | ||
| 259 | } | ||
| 260 | |||
| 261 | @Override | ||
| 262 | public Void visitPrimitiveExpression(PrimitiveExpression node, List<Annotation> data) { | ||
| 263 | return recurse(node, data); | ||
| 264 | } | ||
| 265 | |||
| 266 | @Override | ||
| 267 | public Void visitCastExpression(CastExpression node, List<Annotation> data) { | ||
| 268 | return recurse(node, data); | ||
| 269 | } | ||
| 270 | |||
| 271 | @Override | ||
| 272 | public Void visitBinaryOperatorExpression(BinaryOperatorExpression node, List<Annotation> data) { | ||
| 273 | return recurse(node, data); | ||
| 274 | } | ||
| 275 | |||
| 276 | @Override | ||
| 277 | public Void visitInstanceOfExpression(InstanceOfExpression node, List<Annotation> data) { | ||
| 278 | return recurse(node, data); | ||
| 279 | } | ||
| 280 | |||
| 281 | @Override | ||
| 282 | public Void visitIndexerExpression(IndexerExpression node, List<Annotation> data) { | ||
| 283 | return recurse(node, data); | ||
| 284 | } | ||
| 285 | |||
| 286 | @Override | ||
| 287 | public Void visitUnaryOperatorExpression(UnaryOperatorExpression node, List<Annotation> data) { | ||
| 288 | return recurse(node, data); | ||
| 289 | } | ||
| 290 | |||
| 291 | @Override | ||
| 292 | public Void visitConditionalExpression(ConditionalExpression node, List<Annotation> data) { | ||
| 293 | return recurse(node, data); | ||
| 294 | } | ||
| 295 | |||
| 296 | @Override | ||
| 297 | public Void visitArrayInitializerExpression(ArrayInitializerExpression node, List<Annotation> data) { | ||
| 298 | return recurse(node, data); | ||
| 299 | } | ||
| 300 | |||
| 301 | @Override | ||
| 302 | public Void visitObjectCreationExpression(ObjectCreationExpression node, List<Annotation> data) { | ||
| 303 | return recurse(node, data); | ||
| 304 | } | ||
| 305 | |||
| 306 | @Override | ||
| 307 | public Void visitArrayCreationExpression(ArrayCreationExpression node, List<Annotation> data) { | ||
| 308 | return recurse(node, data); | ||
| 309 | } | ||
| 310 | |||
| 311 | @Override | ||
| 312 | public Void visitAssignmentExpression(AssignmentExpression node, List<Annotation> data) { | ||
| 313 | return recurse(node, data); | ||
| 314 | } | ||
| 315 | |||
| 316 | @Override | ||
| 317 | public Void visitForStatement(ForStatement node, List<Annotation> data) { | ||
| 318 | return recurse(node, data); | ||
| 319 | } | ||
| 320 | |||
| 321 | @Override | ||
| 322 | public Void visitForEachStatement(ForEachStatement node, List<Annotation> data) { | ||
| 323 | return recurse(node, data); | ||
| 324 | } | ||
| 325 | |||
| 326 | @Override | ||
| 327 | public Void visitTryCatchStatement(TryCatchStatement node, List<Annotation> data) { | ||
| 328 | return recurse(node, data); | ||
| 329 | } | ||
| 330 | |||
| 331 | @Override | ||
| 332 | public Void visitGotoStatement(GotoStatement node, List<Annotation> data) { | ||
| 333 | return recurse(node, data); | ||
| 334 | } | ||
| 335 | |||
| 336 | @Override | ||
| 337 | public Void visitParenthesizedExpression(ParenthesizedExpression node, List<Annotation> data) { | ||
| 338 | return recurse(node, data); | ||
| 339 | } | ||
| 340 | |||
| 341 | @Override | ||
| 342 | public Void visitSynchronizedStatement(SynchronizedStatement node, List<Annotation> data) { | ||
| 343 | return recurse(node, data); | ||
| 344 | } | ||
| 345 | |||
| 346 | @Override | ||
| 347 | public Void visitAnonymousObjectCreationExpression(AnonymousObjectCreationExpression node, List<Annotation> data) { | ||
| 348 | return recurse(node, data); | ||
| 349 | } | ||
| 350 | |||
| 351 | @Override | ||
| 352 | public Void visitWildcardType(WildcardType node, List<Annotation> data) { | ||
| 353 | return recurse(node, data); | ||
| 354 | } | ||
| 355 | |||
| 356 | @Override | ||
| 357 | public Void visitMethodGroupExpression(MethodGroupExpression node, List<Annotation> data) { | ||
| 358 | return recurse(node, data); | ||
| 359 | } | ||
| 360 | |||
| 361 | @Override | ||
| 362 | public Void visitAssertStatement(AssertStatement node, List<Annotation> data) { | ||
| 363 | return recurse(node, data); | ||
| 364 | } | ||
| 365 | |||
| 366 | @Override | ||
| 367 | public Void visitLambdaExpression(LambdaExpression node, List<Annotation> data) { | ||
| 368 | return recurse(node, data); | ||
| 369 | } | ||
| 370 | |||
| 371 | @Override | ||
| 372 | public Void visitLocalTypeDeclarationStatement(LocalTypeDeclarationStatement node, List<Annotation> data) { | ||
| 373 | return recurse(node, data); | ||
| 374 | } | ||
| 375 | } | ||
diff --git a/src/main/java/cuchaz/enigma/analysis/SourceIndex.java b/src/main/java/cuchaz/enigma/analysis/SourceIndex.java index 719930e9..d7bbafa9 100644 --- a/src/main/java/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/main/java/cuchaz/enigma/analysis/SourceIndex.java | |||
| @@ -14,18 +14,16 @@ import com.google.common.collect.HashMultimap; | |||
| 14 | import com.google.common.collect.Lists; | 14 | import com.google.common.collect.Lists; |
| 15 | import com.google.common.collect.Maps; | 15 | import com.google.common.collect.Maps; |
| 16 | import com.google.common.collect.Multimap; | 16 | import com.google.common.collect.Multimap; |
| 17 | |||
| 18 | import com.strobel.decompiler.languages.Region; | 17 | import com.strobel.decompiler.languages.Region; |
| 19 | import com.strobel.decompiler.languages.java.ast.AstNode; | 18 | import com.strobel.decompiler.languages.java.ast.AstNode; |
| 20 | import com.strobel.decompiler.languages.java.ast.Identifier; | 19 | import com.strobel.decompiler.languages.java.ast.Identifier; |
| 20 | import cuchaz.enigma.mapping.Entry; | ||
| 21 | 21 | ||
| 22 | import java.util.Collection; | 22 | import java.util.Collection; |
| 23 | import java.util.List; | 23 | import java.util.List; |
| 24 | import java.util.Map; | 24 | import java.util.Map; |
| 25 | import java.util.TreeMap; | 25 | import java.util.TreeMap; |
| 26 | 26 | ||
| 27 | import cuchaz.enigma.mapping.Entry; | ||
| 28 | |||
| 29 | public class SourceIndex { | 27 | public class SourceIndex { |
| 30 | 28 | ||
| 31 | private String source; | 29 | private String source; |
| @@ -56,10 +54,27 @@ public class SourceIndex { | |||
| 56 | } | 54 | } |
| 57 | } | 55 | } |
| 58 | 56 | ||
| 57 | public void setSource(String source) | ||
| 58 | { | ||
| 59 | this.source = source; | ||
| 60 | } | ||
| 61 | |||
| 59 | public String getSource() { | 62 | public String getSource() { |
| 60 | return this.source; | 63 | return this.source; |
| 61 | } | 64 | } |
| 62 | 65 | ||
| 66 | public int getLineNumber(int offset) | ||
| 67 | { | ||
| 68 | int i = 0; | ||
| 69 | for (Integer lineOffset : lineOffsets) | ||
| 70 | { | ||
| 71 | if (lineOffset <= offset) | ||
| 72 | return i; | ||
| 73 | i++; | ||
| 74 | } | ||
| 75 | return i; | ||
| 76 | } | ||
| 77 | |||
| 63 | public Token getToken(AstNode node) { | 78 | public Token getToken(AstNode node) { |
| 64 | 79 | ||
| 65 | // get the text of the node | 80 | // get the text of the node |
| @@ -75,7 +90,7 @@ public class SourceIndex { | |||
| 75 | System.err.println(String.format("WARNING: %s \"%s\" has invalid region: %s", node.getNodeType(), name, region)); | 90 | System.err.println(String.format("WARNING: %s \"%s\" has invalid region: %s", node.getNodeType(), name, region)); |
| 76 | return null; | 91 | return null; |
| 77 | } | 92 | } |
| 78 | Token token = new Token(toPos(region.getBeginLine(), region.getBeginColumn()), toPos(region.getEndLine(), region.getEndColumn()), this.source); | 93 | Token token = new Token(this, region, this.source); |
| 79 | if (token.start == 0) { | 94 | if (token.start == 0) { |
| 80 | // DEBUG | 95 | // DEBUG |
| 81 | System.err.println(String.format("WARNING: %s \"%s\" has invalid start: %s", node.getNodeType(), name, region)); | 96 | System.err.println(String.format("WARNING: %s \"%s\" has invalid start: %s", node.getNodeType(), name, region)); |
| @@ -157,24 +172,12 @@ public class SourceIndex { | |||
| 157 | return this.declarationToToken.get(deobfEntry); | 172 | return this.declarationToToken.get(deobfEntry); |
| 158 | } | 173 | } |
| 159 | 174 | ||
| 160 | public int getLineNumber(int pos) { | ||
| 161 | // line number is 1-based | ||
| 162 | int line = 0; | ||
| 163 | for (Integer offset : this.lineOffsets) { | ||
| 164 | if (offset > pos) { | ||
| 165 | break; | ||
| 166 | } | ||
| 167 | line++; | ||
| 168 | } | ||
| 169 | return line; | ||
| 170 | } | ||
| 171 | |||
| 172 | public int getColumnNumber(int pos) { | 175 | public int getColumnNumber(int pos) { |
| 173 | // column number is 1-based | 176 | // column number is 1-based |
| 174 | return pos - this.lineOffsets.get(getLineNumber(pos) - 1) + 1; | 177 | return pos - this.lineOffsets.get(getLineNumber(pos) - 1) + 1; |
| 175 | } | 178 | } |
| 176 | 179 | ||
| 177 | private int toPos(int line, int col) { | 180 | public int toPos(int line, int col) { |
| 178 | // line and col are 1-based | 181 | // line and col are 1-based |
| 179 | return this.lineOffsets.get(line - 1) + col - 1; | 182 | return this.lineOffsets.get(line - 1) + col - 1; |
| 180 | } | 183 | } |
diff --git a/src/main/java/cuchaz/enigma/analysis/Token.java b/src/main/java/cuchaz/enigma/analysis/Token.java index 419842af..0f730cb4 100644 --- a/src/main/java/cuchaz/enigma/analysis/Token.java +++ b/src/main/java/cuchaz/enigma/analysis/Token.java | |||
| @@ -10,18 +10,48 @@ | |||
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | package cuchaz.enigma.analysis; | 11 | package cuchaz.enigma.analysis; |
| 12 | 12 | ||
| 13 | import com.strobel.decompiler.languages.Region; | ||
| 14 | |||
| 13 | public class Token implements Comparable<Token> { | 15 | public class Token implements Comparable<Token> { |
| 14 | 16 | ||
| 15 | public int start; | 17 | public int start; |
| 16 | public int end; | 18 | public int end; |
| 19 | public int offsetLine; | ||
| 20 | public int offsetColum; | ||
| 17 | public String text; | 21 | public String text; |
| 22 | private Region region; | ||
| 23 | private SourceIndex index; | ||
| 24 | |||
| 25 | public Token(SourceIndex index, Region region, String source) | ||
| 26 | { | ||
| 27 | this(index.toPos(region.getBeginLine(), region.getBeginColumn()), index | ||
| 28 | .toPos(region.getEndLine(), region.getEndColumn()), source); | ||
| 29 | this.region = region; | ||
| 30 | this.index = index; | ||
| 31 | //toPos(region.getBeginLine(), region.getBeginColumn()), toPos(region.getEndLine(), region.getEndColumn()) | ||
| 32 | } | ||
| 33 | |||
| 34 | public void computePos() | ||
| 35 | { | ||
| 36 | if (region == null) | ||
| 37 | return; | ||
| 38 | this.start = index.toPos(region.getBeginLine() + offsetLine, region.getBeginColumn() + offsetColum); | ||
| 39 | this.end = index.toPos(region.getEndLine() + offsetLine, region.getEndColumn() + offsetColum); | ||
| 40 | this.offsetLine = 0; | ||
| 41 | this.offsetColum = 0; | ||
| 42 | this.region = null; | ||
| 43 | } | ||
| 44 | |||
| 45 | public Region getRegion() | ||
| 46 | { | ||
| 47 | return region; | ||
| 48 | } | ||
| 18 | 49 | ||
| 19 | public Token(int start, int end, String source) { | 50 | public Token(int start, int end, String source) { |
| 20 | this.start = start; | 51 | this.start = start; |
| 21 | this.end = end; | 52 | this.end = end; |
| 22 | if (source != null) { | 53 | if (source != null) |
| 23 | this.text = source.substring(start, end); | 54 | this.text = source.substring(start, end); |
| 24 | } | ||
| 25 | } | 55 | } |
| 26 | 56 | ||
| 27 | public boolean contains(int pos) { | 57 | public boolean contains(int pos) { |
diff --git a/src/main/java/cuchaz/enigma/bytecode/ClassTranslator.java b/src/main/java/cuchaz/enigma/bytecode/ClassTranslator.java index 6c05b838..7f8779fc 100644 --- a/src/main/java/cuchaz/enigma/bytecode/ClassTranslator.java +++ b/src/main/java/cuchaz/enigma/bytecode/ClassTranslator.java | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | package cuchaz.enigma.bytecode; | 11 | package cuchaz.enigma.bytecode; |
| 12 | 12 | ||
| 13 | import cuchaz.enigma.mapping.*; | 13 | import cuchaz.enigma.mapping.*; |
| 14 | import cuchaz.enigma.mapping.javadoc.JavaDocMapping; | ||
| 14 | import javassist.CtBehavior; | 15 | import javassist.CtBehavior; |
| 15 | import javassist.CtClass; | 16 | import javassist.CtClass; |
| 16 | import javassist.CtField; | 17 | import javassist.CtField; |
| @@ -22,10 +23,13 @@ import javassist.bytecode.SourceFileAttribute; | |||
| 22 | 23 | ||
| 23 | public class ClassTranslator { | 24 | public class ClassTranslator { |
| 24 | 25 | ||
| 26 | private JavaDocMapping docMapping; | ||
| 25 | private Translator translator; | 27 | private Translator translator; |
| 26 | 28 | ||
| 27 | public ClassTranslator(Translator translator) { | 29 | public ClassTranslator(Translator translator, JavaDocMapping docMapping) { |
| 28 | this.translator = translator; | 30 | this.translator = translator; |
| 31 | this.docMapping = docMapping == null ? new JavaDocMapping() : docMapping; | ||
| 32 | this.docMapping.setTranslator(translator); | ||
| 29 | } | 33 | } |
| 30 | 34 | ||
| 31 | public void translate(CtClass c) { | 35 | public void translate(CtClass c) { |
| @@ -75,14 +79,22 @@ public class ClassTranslator { | |||
| 75 | 79 | ||
| 76 | ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); | 80 | ClassEntry classEntry = new ClassEntry(Descriptor.toJvmName(c.getName())); |
| 77 | 81 | ||
| 82 | // Try to add javadoc to constructor | ||
| 83 | docMapping.tryToAddJavaDoc(c, classEntry); | ||
| 78 | // translate all the fields | 84 | // translate all the fields |
| 79 | for (CtField field : c.getDeclaredFields()) { | 85 | for (CtField field : c.getDeclaredFields()) { |
| 80 | 86 | ||
| 81 | // translate the name | 87 | // translate the name |
| 82 | FieldEntry entry = EntryFactory.getFieldEntry(field); | 88 | FieldEntry entry = EntryFactory.getFieldEntry(field); |
| 83 | String translatedName = this.translator.translate(entry); | 89 | String translatedName = this.translator.translate(entry); |
| 90 | |||
| 91 | // Try to add javadoc as ob | ||
| 92 | docMapping.tryToAddJavaDoc(field, entry); | ||
| 84 | if (translatedName != null) { | 93 | if (translatedName != null) { |
| 85 | field.setName(translatedName); | 94 | field.setName(translatedName); |
| 95 | |||
| 96 | // Try to add javadoc as ob | ||
| 97 | docMapping.tryToAddJavaDoc(field, entry); | ||
| 86 | } | 98 | } |
| 87 | 99 | ||
| 88 | // translate the type | 100 | // translate the type |
| @@ -98,12 +110,22 @@ public class ClassTranslator { | |||
| 98 | if (behavior instanceof CtMethod) { | 110 | if (behavior instanceof CtMethod) { |
| 99 | CtMethod method = (CtMethod) behavior; | 111 | CtMethod method = (CtMethod) behavior; |
| 100 | 112 | ||
| 113 | // Try to add javadoc as ob | ||
| 114 | docMapping.tryToAddJavaDoc(method, entry); | ||
| 101 | // translate the name | 115 | // translate the name |
| 102 | String translatedName = this.translator.translate(entry); | 116 | String translatedName = this.translator.translate(entry); |
| 103 | if (translatedName != null) { | 117 | if (translatedName != null) { |
| 118 | MethodEntry deObfuscatedMethod = new MethodEntry(entry.getClassEntry(), translatedName, entry.getSignature()); | ||
| 104 | method.setName(translatedName); | 119 | method.setName(translatedName); |
| 120 | // Try to add javadoc as ob | ||
| 121 | docMapping.tryToAddJavaDoc(method, entry, deObfuscatedMethod); | ||
| 105 | } | 122 | } |
| 106 | } | 123 | } |
| 124 | else | ||
| 125 | { | ||
| 126 | // Try to add javadoc to constructor | ||
| 127 | docMapping.tryToAddJavaDoc(behavior, entry); | ||
| 128 | } | ||
| 107 | 129 | ||
| 108 | if (entry.getSignature() != null) { | 130 | if (entry.getSignature() != null) { |
| 109 | // translate the signature | 131 | // translate the signature |
diff --git a/src/main/java/cuchaz/enigma/convert/ClassIdentifier.java b/src/main/java/cuchaz/enigma/convert/ClassIdentifier.java index 557e6083..ce1e1dc3 100644 --- a/src/main/java/cuchaz/enigma/convert/ClassIdentifier.java +++ b/src/main/java/cuchaz/enigma/convert/ClassIdentifier.java | |||
| @@ -35,7 +35,7 @@ public class ClassIdentifier { | |||
| 35 | this.index = index; | 35 | this.index = index; |
| 36 | this.namer = namer; | 36 | this.namer = namer; |
| 37 | this.useReferences = useReferences; | 37 | this.useReferences = useReferences; |
| 38 | this.loader = new TranslatingTypeLoader(jar, index, new Translator(), new Translator()); | 38 | this.loader = new TranslatingTypeLoader(jar, index, new Translator(), new Translator(), null); |
| 39 | this.cache = Maps.newHashMap(); | 39 | this.cache = Maps.newHashMap(); |
| 40 | } | 40 | } |
| 41 | 41 | ||
diff --git a/src/main/java/cuchaz/enigma/mapping/javadoc/BaseJavaDocEntry.java b/src/main/java/cuchaz/enigma/mapping/javadoc/BaseJavaDocEntry.java new file mode 100644 index 00000000..fa373a57 --- /dev/null +++ b/src/main/java/cuchaz/enigma/mapping/javadoc/BaseJavaDocEntry.java | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | package cuchaz.enigma.mapping.javadoc; | ||
| 2 | |||
| 3 | import cuchaz.enigma.mapping.Entry; | ||
| 4 | import cuchaz.enigma.mapping.Type; | ||
| 5 | |||
| 6 | /** | ||
| 7 | * Base of any JavaDoc entry | ||
| 8 | * Created by Thog | ||
| 9 | * 19/08/2016 | ||
| 10 | */ | ||
| 11 | public abstract class BaseJavaDocEntry | ||
| 12 | { | ||
| 13 | private String identifier; | ||
| 14 | private String comment; | ||
| 15 | |||
| 16 | public BaseJavaDocEntry(String identifier, String comment) | ||
| 17 | { | ||
| 18 | this.identifier = identifier; | ||
| 19 | this.comment = comment; | ||
| 20 | } | ||
| 21 | |||
| 22 | public void setIdentifier(String identifier) | ||
| 23 | { | ||
| 24 | this.identifier = identifier; | ||
| 25 | } | ||
| 26 | |||
| 27 | public String getIdentifier() | ||
| 28 | { | ||
| 29 | return identifier; | ||
| 30 | } | ||
| 31 | |||
| 32 | public void setComment(String comment) | ||
| 33 | { | ||
| 34 | this.comment = comment; | ||
| 35 | } | ||
| 36 | |||
| 37 | public String getComment() | ||
| 38 | { | ||
| 39 | return comment; | ||
| 40 | } | ||
| 41 | |||
| 42 | public Type getType() | ||
| 43 | { | ||
| 44 | return new Type(getIdentifier()); | ||
| 45 | } | ||
| 46 | |||
| 47 | public abstract JavaDocClass getClassDocEntry(); | ||
| 48 | |||
| 49 | public abstract Entry getEntry(); | ||
| 50 | } | ||
diff --git a/src/main/java/cuchaz/enigma/mapping/javadoc/JavaDocClass.java b/src/main/java/cuchaz/enigma/mapping/javadoc/JavaDocClass.java new file mode 100644 index 00000000..9bc7e734 --- /dev/null +++ b/src/main/java/cuchaz/enigma/mapping/javadoc/JavaDocClass.java | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | package cuchaz.enigma.mapping.javadoc; | ||
| 2 | |||
| 3 | import cuchaz.enigma.mapping.ClassEntry; | ||
| 4 | import cuchaz.enigma.mapping.Entry; | ||
| 5 | |||
| 6 | /** | ||
| 7 | * JavaDoc representation of a class | ||
| 8 | * Created by Thog | ||
| 9 | * 19/08/2016 | ||
| 10 | */ | ||
| 11 | public class JavaDocClass extends BaseJavaDocEntry | ||
| 12 | { | ||
| 13 | |||
| 14 | public JavaDocClass(String identifier, String comment) | ||
| 15 | { | ||
| 16 | super(identifier, comment); | ||
| 17 | } | ||
| 18 | |||
| 19 | @Override public JavaDocClass getClassDocEntry() | ||
| 20 | { | ||
| 21 | return this; | ||
| 22 | } | ||
| 23 | |||
| 24 | @Override | ||
| 25 | public Entry getEntry() | ||
| 26 | { | ||
| 27 | return new ClassEntry(getIdentifier()); | ||
| 28 | } | ||
| 29 | } | ||
diff --git a/src/main/java/cuchaz/enigma/mapping/javadoc/JavaDocField.java b/src/main/java/cuchaz/enigma/mapping/javadoc/JavaDocField.java new file mode 100644 index 00000000..a2a67f45 --- /dev/null +++ b/src/main/java/cuchaz/enigma/mapping/javadoc/JavaDocField.java | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | package cuchaz.enigma.mapping.javadoc; | ||
| 2 | |||
| 3 | import cuchaz.enigma.mapping.ClassEntry; | ||
| 4 | import cuchaz.enigma.mapping.Entry; | ||
| 5 | import cuchaz.enigma.mapping.FieldEntry; | ||
| 6 | |||
| 7 | /** | ||
| 8 | * JavaDoc of a Field | ||
| 9 | * Created by Thog | ||
| 10 | * 19/08/2016 | ||
| 11 | */ | ||
| 12 | public class JavaDocField extends BaseJavaDocEntry | ||
| 13 | { | ||
| 14 | private final JavaDocClass classDocEntry; | ||
| 15 | private final String name; | ||
| 16 | public JavaDocField(JavaDocClass classDocEntry, String name, String identifier, String comment) | ||
| 17 | { | ||
| 18 | super(identifier, comment); | ||
| 19 | this.name = name; | ||
| 20 | this.classDocEntry = classDocEntry; | ||
| 21 | } | ||
| 22 | |||
| 23 | @Override public JavaDocClass getClassDocEntry() | ||
| 24 | { | ||
| 25 | return classDocEntry; | ||
| 26 | } | ||
| 27 | |||
| 28 | @Override public Entry getEntry() | ||
| 29 | { | ||
| 30 | return new FieldEntry((ClassEntry) classDocEntry.getEntry(), name, getType()); | ||
| 31 | } | ||
| 32 | } | ||
diff --git a/src/main/java/cuchaz/enigma/mapping/javadoc/JavaDocMapping.java b/src/main/java/cuchaz/enigma/mapping/javadoc/JavaDocMapping.java new file mode 100644 index 00000000..98996fdb --- /dev/null +++ b/src/main/java/cuchaz/enigma/mapping/javadoc/JavaDocMapping.java | |||
| @@ -0,0 +1,263 @@ | |||
| 1 | package cuchaz.enigma.mapping.javadoc; | ||
| 2 | |||
| 3 | import com.strobel.decompiler.languages.java.ast.*; | ||
| 4 | import cuchaz.enigma.mapping.*; | ||
| 5 | import javassist.CtBehavior; | ||
| 6 | import javassist.CtClass; | ||
| 7 | import javassist.CtField; | ||
| 8 | import javassist.bytecode.AnnotationsAttribute; | ||
| 9 | import javassist.bytecode.ConstPool; | ||
| 10 | import javassist.bytecode.annotation.*; | ||
| 11 | import javassist.bytecode.annotation.Annotation; | ||
| 12 | |||
| 13 | import java.io.File; | ||
| 14 | import java.util.*; | ||
| 15 | |||
| 16 | /** | ||
| 17 | * Representation of a javadoc mapping | ||
| 18 | * Created by Thog | ||
| 19 | * 19/08/2016 | ||
| 20 | */ | ||
| 21 | public class JavaDocMapping | ||
| 22 | { | ||
| 23 | private final Map<ClassEntry, JavaDocClass> javaDocClassByID; | ||
| 24 | private final Map<FieldEntry, JavaDocField> javaDocFieldByID; | ||
| 25 | private final Map<BehaviorEntry, JavaDocMethod> javaDocMethodByID; | ||
| 26 | private final List<BehaviorEntry> behaviorByID; | ||
| 27 | private Translator translator; | ||
| 28 | |||
| 29 | public JavaDocMapping() | ||
| 30 | { | ||
| 31 | this.javaDocClassByID = new HashMap<>(); | ||
| 32 | this.javaDocFieldByID = new HashMap<>(); | ||
| 33 | this.javaDocMethodByID = new HashMap<>(); | ||
| 34 | this.behaviorByID = new ArrayList<>(); | ||
| 35 | |||
| 36 | // TODO: File format | ||
| 37 | addField("a", "none/akw", "Lnone/kp;", "Hello from Enigma"); | ||
| 38 | addMethod("<init>", "none/akw", "(Lnone/ayo;)V", "You know what? I love constructors!", "The material of the block!"); | ||
| 39 | addClass("none/akw", "HEY I'M A BLOCK YOU KNOW THAT?!"); | ||
| 40 | } | ||
| 41 | |||
| 42 | private void addClass(String className, String comment) | ||
| 43 | { | ||
| 44 | this.javaDocClassByID.put(new ClassEntry(className), new JavaDocClass(className, comment)); | ||
| 45 | } | ||
| 46 | |||
| 47 | public void addField(String fieldName, String className, String type, String comment) | ||
| 48 | { | ||
| 49 | this.javaDocFieldByID.put(new FieldEntry(new ClassEntry(className), fieldName, new Type(type)), new JavaDocField(new JavaDocClass(className, "LOL"), fieldName, type, comment)); | ||
| 50 | } | ||
| 51 | |||
| 52 | public void addMethod(String methodName, String className, String signature, String comment, String... argComment) | ||
| 53 | { | ||
| 54 | BehaviorEntry behaviorEntry; | ||
| 55 | if (methodName.equals("<init>")) | ||
| 56 | behaviorEntry = new ConstructorEntry(new ClassEntry(className), new Signature(signature)); | ||
| 57 | else | ||
| 58 | behaviorEntry = new MethodEntry(new ClassEntry(className), methodName, new Signature(signature)); | ||
| 59 | |||
| 60 | this.javaDocMethodByID.put(behaviorEntry, new JavaDocMethod(new JavaDocClass(className, "LOL"), methodName, signature, comment, | ||
| 61 | Arrays.asList(argComment))); | ||
| 62 | } | ||
| 63 | |||
| 64 | public void cleanBehaviors() | ||
| 65 | { | ||
| 66 | behaviorByID.clear(); | ||
| 67 | } | ||
| 68 | |||
| 69 | public void loadMapping(File mappingDirectory) | ||
| 70 | { | ||
| 71 | // NOP | ||
| 72 | } | ||
| 73 | |||
| 74 | public void closeMapping() | ||
| 75 | { | ||
| 76 | behaviorByID.clear(); | ||
| 77 | javaDocClassByID.clear(); | ||
| 78 | javaDocFieldByID.clear(); | ||
| 79 | javaDocMethodByID.clear(); | ||
| 80 | } | ||
| 81 | |||
| 82 | public CtClass tryToAddJavaDoc(CtClass ctClass, ClassEntry entry) | ||
| 83 | { | ||
| 84 | if (javaDocClassByID.containsKey(entry)) | ||
| 85 | { | ||
| 86 | JavaDocClass javaDocClass = javaDocClassByID.get(entry); | ||
| 87 | |||
| 88 | // Get the constant pool | ||
| 89 | ConstPool constpool = ctClass.getClassFile().getConstPool(); | ||
| 90 | |||
| 91 | // Prepare the annotation | ||
| 92 | AnnotationsAttribute attr = new AnnotationsAttribute(constpool, AnnotationsAttribute.visibleTag); | ||
| 93 | Annotation annot = new Annotation("enigma.remapper.ClassDoc", constpool); | ||
| 94 | annot.addMemberValue("comment", new StringMemberValue(javaDocClass.getComment(), constpool)); | ||
| 95 | attr.addAnnotation(annot); | ||
| 96 | ctClass.getClassFile().addAttribute(attr); | ||
| 97 | } | ||
| 98 | return ctClass; | ||
| 99 | } | ||
| 100 | |||
| 101 | public CtBehavior tryToAddJavaDoc(CtBehavior ctBehavior, BehaviorEntry obEntry, BehaviorEntry deobEntry) | ||
| 102 | { | ||
| 103 | if (javaDocMethodByID.containsKey(obEntry)) | ||
| 104 | { | ||
| 105 | int id = getEntryID(obEntry); | ||
| 106 | if (id != -1) | ||
| 107 | behaviorByID.set(id, deobEntry); | ||
| 108 | } | ||
| 109 | return tryToAddJavaDoc(ctBehavior, deobEntry); | ||
| 110 | } | ||
| 111 | |||
| 112 | public CtBehavior tryToAddJavaDoc(CtBehavior ctBehavior, BehaviorEntry entry) | ||
| 113 | { | ||
| 114 | if (javaDocMethodByID.containsKey(entry)) | ||
| 115 | { | ||
| 116 | JavaDocMethod javaDocMethod = javaDocMethodByID.get(entry); | ||
| 117 | |||
| 118 | // Get the constant pool | ||
| 119 | ConstPool constpool = ctBehavior.getDeclaringClass().getClassFile().getConstPool(); | ||
| 120 | |||
| 121 | // Prepare the annotation | ||
| 122 | AnnotationsAttribute attr = new AnnotationsAttribute(constpool, AnnotationsAttribute.visibleTag); | ||
| 123 | Annotation annot = new Annotation("enigma.remapper.MethodDoc", constpool); | ||
| 124 | annot.addMemberValue("comment", new StringMemberValue(javaDocMethod.getComment(), constpool)); | ||
| 125 | behaviorByID.add(entry); | ||
| 126 | annot.addMemberValue("behavior", new IntegerMemberValue(constpool, behaviorByID.size() - 1)); | ||
| 127 | annot.addMemberValue("args", translateStringArray(constpool, javaDocMethod.getArgsComments())); | ||
| 128 | attr.addAnnotation(annot); | ||
| 129 | ctBehavior.getMethodInfo().addAttribute(attr); | ||
| 130 | } | ||
| 131 | return ctBehavior; | ||
| 132 | } | ||
| 133 | |||
| 134 | public CtField tryToAddJavaDoc(CtField ctField, FieldEntry entry) | ||
| 135 | { | ||
| 136 | if (javaDocFieldByID.containsKey(entry)) | ||
| 137 | { | ||
| 138 | JavaDocField javaDocField = javaDocFieldByID.get(entry); | ||
| 139 | |||
| 140 | // Get the constant pool | ||
| 141 | ConstPool constpool = ctField.getDeclaringClass().getClassFile().getConstPool(); | ||
| 142 | |||
| 143 | // Prepare the annotation | ||
| 144 | AnnotationsAttribute attr = new AnnotationsAttribute(constpool, AnnotationsAttribute.visibleTag); | ||
| 145 | Annotation annot = new Annotation("enigma.remapper.FieldDoc", constpool); | ||
| 146 | annot.addMemberValue("comment", new StringMemberValue(javaDocField.getComment(), constpool)); | ||
| 147 | attr.addAnnotation(annot); | ||
| 148 | ctField.getFieldInfo().addAttribute(attr); | ||
| 149 | } | ||
| 150 | return ctField; | ||
| 151 | } | ||
| 152 | |||
| 153 | private MemberValue[] toMemberValue(ConstPool pool, String[] args) | ||
| 154 | { | ||
| 155 | MemberValue[] result = new MemberValue[args.length]; | ||
| 156 | for (int i = 0; i < result.length; i++) | ||
| 157 | result[i] = new StringMemberValue(args[i], pool); | ||
| 158 | |||
| 159 | return result; | ||
| 160 | } | ||
| 161 | |||
| 162 | private ArrayMemberValue translateStringArray(ConstPool pool, String[] args) | ||
| 163 | { | ||
| 164 | ArrayMemberValue res = new ArrayMemberValue(new StringMemberValue(pool), pool); | ||
| 165 | res.setValue(toMemberValue(pool, args)); | ||
| 166 | return res; | ||
| 167 | } | ||
| 168 | |||
| 169 | public BehaviorEntry getEntry(int id) | ||
| 170 | { | ||
| 171 | if (id == -1) | ||
| 172 | return null; | ||
| 173 | return this.behaviorByID.get(id); | ||
| 174 | } | ||
| 175 | |||
| 176 | public int getEntryID(BehaviorEntry taget) | ||
| 177 | { | ||
| 178 | for (int i = 0; i < behaviorByID.size(); i++) | ||
| 179 | if (behaviorByID.get(i).equals(taget)) | ||
| 180 | return i; | ||
| 181 | return -1; | ||
| 182 | } | ||
| 183 | |||
| 184 | /** | ||
| 185 | * | ||
| 186 | * @param annotation | ||
| 187 | * @param spacesCount | ||
| 188 | * @return | ||
| 189 | */ | ||
| 190 | public String convertAnnotationToJavaDoc(com.strobel.decompiler.languages.java.ast.Annotation annotation, int spacesCount) | ||
| 191 | { | ||
| 192 | int behaviorID = -1; | ||
| 193 | StringBuilder builder = new StringBuilder(); | ||
| 194 | String spaces = buildLineSpace(spacesCount); | ||
| 195 | builder.append("/**\n"); | ||
| 196 | AstNodeCollection<Expression> annotationArgs = annotation.getArguments(); | ||
| 197 | for (Expression expression : annotationArgs) | ||
| 198 | { | ||
| 199 | String id = expression.getFirstChild().toString(); | ||
| 200 | for (AstNode child : expression.getChildren()) | ||
| 201 | { | ||
| 202 | if (child instanceof PrimitiveExpression) | ||
| 203 | { | ||
| 204 | PrimitiveExpression data = (PrimitiveExpression) child; | ||
| 205 | if (id.equals("comment")) | ||
| 206 | { | ||
| 207 | builder.append(spaces); | ||
| 208 | builder.append(" * "); | ||
| 209 | builder.append(data.getValue()); | ||
| 210 | builder.append("\n"); | ||
| 211 | } | ||
| 212 | else if (id.equals("behavior")) | ||
| 213 | behaviorID = (Integer) data.getValue(); | ||
| 214 | } | ||
| 215 | else if (child instanceof ArrayInitializerExpression) | ||
| 216 | { | ||
| 217 | ArrayInitializerExpression data = (ArrayInitializerExpression) child; | ||
| 218 | if (id.equals("args")) | ||
| 219 | { | ||
| 220 | BehaviorEntry entry = getEntry(behaviorID); | ||
| 221 | if (entry == null) | ||
| 222 | System.err.println("(SEVERE): CANNOT FIND BEHAVIOR ENTRY FOR ID " + behaviorID); | ||
| 223 | |||
| 224 | int i = 0; | ||
| 225 | for (Expression expArg : data.getElements()) | ||
| 226 | { | ||
| 227 | if (expArg instanceof PrimitiveExpression) | ||
| 228 | { | ||
| 229 | PrimitiveExpression primitiveExpression = (PrimitiveExpression) expArg; | ||
| 230 | String argName = entry == null ? null : this.translator.translate(new ArgumentEntry(entry, i, "")); | ||
| 231 | if (argName == null) | ||
| 232 | argName = "a" + (i + 1); | ||
| 233 | builder.append(spaces); | ||
| 234 | builder.append(" * @param "); | ||
| 235 | builder.append(argName); | ||
| 236 | builder.append(" "); | ||
| 237 | builder.append(primitiveExpression.getValue()); | ||
| 238 | builder.append("\n"); | ||
| 239 | } | ||
| 240 | i++; | ||
| 241 | } | ||
| 242 | } | ||
| 243 | } | ||
| 244 | } | ||
| 245 | } | ||
| 246 | builder.append(spaces); | ||
| 247 | builder.append(" */"); | ||
| 248 | return builder.toString(); | ||
| 249 | } | ||
| 250 | |||
| 251 | private String buildLineSpace(int spacesCount) | ||
| 252 | { | ||
| 253 | StringBuilder builder = new StringBuilder(); | ||
| 254 | for (int i = 0; i< spacesCount; i++) | ||
| 255 | builder.append(" "); | ||
| 256 | return builder.toString(); | ||
| 257 | } | ||
| 258 | |||
| 259 | public void setTranslator(Translator translator) | ||
| 260 | { | ||
| 261 | this.translator = translator; | ||
| 262 | } | ||
| 263 | } | ||
diff --git a/src/main/java/cuchaz/enigma/mapping/javadoc/JavaDocMethod.java b/src/main/java/cuchaz/enigma/mapping/javadoc/JavaDocMethod.java new file mode 100644 index 00000000..1508aede --- /dev/null +++ b/src/main/java/cuchaz/enigma/mapping/javadoc/JavaDocMethod.java | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | package cuchaz.enigma.mapping.javadoc; | ||
| 2 | |||
| 3 | import cuchaz.enigma.mapping.ClassEntry; | ||
| 4 | import cuchaz.enigma.mapping.Entry; | ||
| 5 | import cuchaz.enigma.mapping.MethodEntry; | ||
| 6 | import cuchaz.enigma.mapping.Signature; | ||
| 7 | |||
| 8 | import java.util.List; | ||
| 9 | |||
| 10 | /** | ||
| 11 | * Javadoc of a Method | ||
| 12 | * TODO: @return | ||
| 13 | * Created by Thog | ||
| 14 | * 19/08/2016 | ||
| 15 | */ | ||
| 16 | public class JavaDocMethod extends BaseJavaDocEntry | ||
| 17 | { | ||
| 18 | private final JavaDocClass classDocEntry; | ||
| 19 | private final String name; | ||
| 20 | private final List<String> argsComments; | ||
| 21 | |||
| 22 | public JavaDocMethod(JavaDocClass classDocEntry, String name, String identifier, String comment, List<String> argsComments) | ||
| 23 | { | ||
| 24 | super(identifier, comment); | ||
| 25 | this.name = name; | ||
| 26 | this.classDocEntry = classDocEntry; | ||
| 27 | this.argsComments = argsComments; | ||
| 28 | } | ||
| 29 | |||
| 30 | @Override public JavaDocClass getClassDocEntry() | ||
| 31 | { | ||
| 32 | return classDocEntry; | ||
| 33 | } | ||
| 34 | |||
| 35 | @Override public Entry getEntry() | ||
| 36 | { | ||
| 37 | return new MethodEntry((ClassEntry) classDocEntry.getEntry(), name, new Signature(getIdentifier())); | ||
| 38 | } | ||
| 39 | |||
| 40 | public String[] getArgsComments() | ||
| 41 | { | ||
| 42 | return argsComments.toArray(new String[argsComments.size()]); | ||
| 43 | } | ||
| 44 | |||
| 45 | public String getArgsComment(int id) | ||
| 46 | { | ||
| 47 | return argsComments.size() > id ? argsComments.get(id) : null; | ||
| 48 | } | ||
| 49 | } | ||