diff options
| author | 2014-08-07 00:55:43 -0400 | |
|---|---|---|
| committer | 2014-08-07 00:55:43 -0400 | |
| commit | 6aa7c6121a2ecbe78f14f8c3d7ddb55b8ddb10bd (patch) | |
| tree | 0b97553e42e2e3a52a1aab30914d885d143d5bf0 | |
| parent | added un-obfuscated classes to the deobfuscated classes list (diff) | |
| download | enigma-6aa7c6121a2ecbe78f14f8c3d7ddb55b8ddb10bd.tar.gz enigma-6aa7c6121a2ecbe78f14f8c3d7ddb55b8ddb10bd.tar.xz enigma-6aa7c6121a2ecbe78f14f8c3d7ddb55b8ddb10bd.zip | |
started working on recognition of non-class member identifiers in the source
got class extends,implements working
and argument,field types
added filtering to make sure highlighted class names are actually classes in the jar
| -rw-r--r-- | src/cuchaz/enigma/Deobfuscator.java | 87 | ||||
| -rw-r--r-- | src/cuchaz/enigma/analysis/Analyzer.java | 91 | ||||
| -rw-r--r-- | src/cuchaz/enigma/analysis/Lexer.java | 42 | ||||
| -rw-r--r-- | src/cuchaz/enigma/analysis/SourceIndex.java | 34 | ||||
| -rw-r--r-- | src/cuchaz/enigma/analysis/SourcedAst.java | 43 | ||||
| -rw-r--r-- | src/cuchaz/enigma/gui/GuiController.java | 12 | ||||
| -rw-r--r-- | src/cuchaz/enigma/gui/SourceFormatter.java | 62 |
7 files changed, 223 insertions, 148 deletions
diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index e067183e..e6e647e9 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java | |||
| @@ -10,10 +10,12 @@ | |||
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | package cuchaz.enigma; | 11 | package cuchaz.enigma; |
| 12 | 12 | ||
| 13 | import java.io.BufferedReader; | ||
| 13 | import java.io.File; | 14 | import java.io.File; |
| 14 | import java.io.FileInputStream; | 15 | import java.io.FileInputStream; |
| 15 | import java.io.IOException; | 16 | import java.io.IOException; |
| 16 | import java.io.InputStream; | 17 | import java.io.InputStream; |
| 18 | import java.io.StringReader; | ||
| 17 | import java.io.StringWriter; | 19 | import java.io.StringWriter; |
| 18 | import java.util.Enumeration; | 20 | import java.util.Enumeration; |
| 19 | import java.util.List; | 21 | import java.util.List; |
| @@ -21,6 +23,7 @@ import java.util.Map; | |||
| 21 | import java.util.jar.JarEntry; | 23 | import java.util.jar.JarEntry; |
| 22 | import java.util.jar.JarFile; | 24 | import java.util.jar.JarFile; |
| 23 | 25 | ||
| 26 | import com.beust.jcommander.internal.Lists; | ||
| 24 | import com.strobel.decompiler.Decompiler; | 27 | import com.strobel.decompiler.Decompiler; |
| 25 | import com.strobel.decompiler.DecompilerSettings; | 28 | import com.strobel.decompiler.DecompilerSettings; |
| 26 | import com.strobel.decompiler.PlainTextOutput; | 29 | import com.strobel.decompiler.PlainTextOutput; |
| @@ -45,6 +48,7 @@ public class Deobfuscator | |||
| 45 | private Ancestries m_ancestries; | 48 | private Ancestries m_ancestries; |
| 46 | private Mappings m_mappings; | 49 | private Mappings m_mappings; |
| 47 | private Renamer m_renamer; | 50 | private Renamer m_renamer; |
| 51 | private List<String> m_obfClassNames; | ||
| 48 | 52 | ||
| 49 | public Deobfuscator( File file ) | 53 | public Deobfuscator( File file ) |
| 50 | throws IOException | 54 | throws IOException |
| @@ -65,6 +69,26 @@ public class Deobfuscator | |||
| 65 | Util.closeQuietly( jarIn ); | 69 | Util.closeQuietly( jarIn ); |
| 66 | } | 70 | } |
| 67 | 71 | ||
| 72 | // get the obf class names | ||
| 73 | m_obfClassNames = Lists.newArrayList(); | ||
| 74 | { | ||
| 75 | Enumeration<JarEntry> entries = m_jar.entries(); | ||
| 76 | while( entries.hasMoreElements() ) | ||
| 77 | { | ||
| 78 | JarEntry entry = entries.nextElement(); | ||
| 79 | |||
| 80 | // skip everything but class files | ||
| 81 | if( !entry.getName().endsWith( ".class" ) ) | ||
| 82 | { | ||
| 83 | continue; | ||
| 84 | } | ||
| 85 | |||
| 86 | // get the class name from the file | ||
| 87 | String className = entry.getName().substring( 0, entry.getName().length() - 6 ); | ||
| 88 | m_obfClassNames.add( className ); | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 68 | // config the decompiler | 92 | // config the decompiler |
| 69 | m_settings = DecompilerSettings.javaDefaults(); | 93 | m_settings = DecompilerSettings.javaDefaults(); |
| 70 | m_settings.setForceExplicitImports( true ); | 94 | m_settings.setForceExplicitImports( true ); |
| @@ -112,20 +136,9 @@ public class Deobfuscator | |||
| 112 | 136 | ||
| 113 | public void getSeparatedClasses( List<ClassFile> obfClasses, Map<ClassFile,String> deobfClasses ) | 137 | public void getSeparatedClasses( List<ClassFile> obfClasses, Map<ClassFile,String> deobfClasses ) |
| 114 | { | 138 | { |
| 115 | Enumeration<JarEntry> entries = m_jar.entries(); | 139 | for( String obfClassName : m_obfClassNames ) |
| 116 | while( entries.hasMoreElements() ) | ||
| 117 | { | 140 | { |
| 118 | JarEntry entry = entries.nextElement(); | 141 | ClassFile classFile = new ClassFile( obfClassName ); |
| 119 | |||
| 120 | // skip everything but class files | ||
| 121 | if( !entry.getName().endsWith( ".class" ) ) | ||
| 122 | { | ||
| 123 | continue; | ||
| 124 | } | ||
| 125 | |||
| 126 | // get the class name from the file | ||
| 127 | String className = entry.getName().substring( 0, entry.getName().length() - 6 ); | ||
| 128 | ClassFile classFile = new ClassFile( className ); | ||
| 129 | 142 | ||
| 130 | // separate the classes | 143 | // separate the classes |
| 131 | ClassMapping classMapping = m_mappings.getClassByObf( classFile.getName() ); | 144 | ClassMapping classMapping = m_mappings.getClassByObf( classFile.getName() ); |
| @@ -159,7 +172,41 @@ public class Deobfuscator | |||
| 159 | // decompile it! | 172 | // decompile it! |
| 160 | StringWriter buf = new StringWriter(); | 173 | StringWriter buf = new StringWriter(); |
| 161 | Decompiler.decompile( deobfName, new PlainTextOutput( buf ), m_settings ); | 174 | Decompiler.decompile( deobfName, new PlainTextOutput( buf ), m_settings ); |
| 162 | return buf.toString(); | 175 | return fixSource( buf.toString() ); |
| 176 | } | ||
| 177 | |||
| 178 | private String fixSource( String source ) | ||
| 179 | { | ||
| 180 | // fix the imports from the default package in the source | ||
| 181 | try | ||
| 182 | { | ||
| 183 | StringBuilder buf = new StringBuilder(); | ||
| 184 | BufferedReader reader = new BufferedReader( new StringReader( source ) ); | ||
| 185 | String line = null; | ||
| 186 | while( ( line = reader.readLine() ) != null ) | ||
| 187 | { | ||
| 188 | String[] parts = line.trim().split( " " ); | ||
| 189 | if( parts.length == 2 && parts[0].equals( "import" ) ) | ||
| 190 | { | ||
| 191 | // is this an (illegal) import from the default package? | ||
| 192 | String className = parts[1]; | ||
| 193 | if( className.indexOf( '.' ) < 0 ) | ||
| 194 | { | ||
| 195 | // this is an illegal import, replace it | ||
| 196 | line = "import __DEFAULT__." + parts[1]; | ||
| 197 | } | ||
| 198 | } | ||
| 199 | |||
| 200 | buf.append( line ); | ||
| 201 | buf.append( "\n" ); | ||
| 202 | } | ||
| 203 | return buf.toString(); | ||
| 204 | } | ||
| 205 | catch( IOException ex ) | ||
| 206 | { | ||
| 207 | // dealing with IOExceptions on StringReaders is silly... | ||
| 208 | throw new Error( ex ); | ||
| 209 | } | ||
| 163 | } | 210 | } |
| 164 | 211 | ||
| 165 | // NOTE: these methods are a bit messy... oh well | 212 | // NOTE: these methods are a bit messy... oh well |
| @@ -265,4 +312,16 @@ public class Deobfuscator | |||
| 265 | throw new Error( "Unknown entry type: " + obfEntry.getClass().getName() ); | 312 | throw new Error( "Unknown entry type: " + obfEntry.getClass().getName() ); |
| 266 | } | 313 | } |
| 267 | } | 314 | } |
| 315 | |||
| 316 | public boolean entryIsObfuscatedIdenfitier( Entry obfEntry ) | ||
| 317 | { | ||
| 318 | if( obfEntry instanceof ClassEntry ) | ||
| 319 | { | ||
| 320 | // obf classes must be in the list | ||
| 321 | return m_obfClassNames.contains( obfEntry.getName() ); | ||
| 322 | } | ||
| 323 | |||
| 324 | // assume everything else is an identifier | ||
| 325 | return true; | ||
| 326 | } | ||
| 268 | } | 327 | } |
diff --git a/src/cuchaz/enigma/analysis/Analyzer.java b/src/cuchaz/enigma/analysis/Analyzer.java index dad8dc52..2b7e0b0b 100644 --- a/src/cuchaz/enigma/analysis/Analyzer.java +++ b/src/cuchaz/enigma/analysis/Analyzer.java | |||
| @@ -35,6 +35,7 @@ import com.sun.source.util.Trees; | |||
| 35 | 35 | ||
| 36 | import cuchaz.enigma.mapping.ArgumentEntry; | 36 | import cuchaz.enigma.mapping.ArgumentEntry; |
| 37 | import cuchaz.enigma.mapping.ClassEntry; | 37 | import cuchaz.enigma.mapping.ClassEntry; |
| 38 | import cuchaz.enigma.mapping.Entry; | ||
| 38 | import cuchaz.enigma.mapping.FieldEntry; | 39 | import cuchaz.enigma.mapping.FieldEntry; |
| 39 | import cuchaz.enigma.mapping.MethodEntry; | 40 | import cuchaz.enigma.mapping.MethodEntry; |
| 40 | 41 | ||
| @@ -78,39 +79,31 @@ class TreeVisitor extends TreeScanner<CompilationUnitTree, SourcedAst> | |||
| 78 | 79 | ||
| 79 | private ClassEntry indexClass( ClassTree classTree, SourcedAst ast ) | 80 | private ClassEntry indexClass( ClassTree classTree, SourcedAst ast ) |
| 80 | { | 81 | { |
| 81 | // build the entry | 82 | // index the class name |
| 82 | ClassEntry entry = new ClassEntry( ast.getFullClassName( classTree.getSimpleName().toString() ) ); | 83 | ClassEntry classEntry = indexClassIdentifier( classTree, ast ); |
| 84 | assert( classEntry != null ); | ||
| 83 | 85 | ||
| 84 | // lex the source at this tree node | 86 | // index the extends clause |
| 85 | for( Token token : new Lexer( ast.getSource( classTree ).toString() ) ) | 87 | indexClassIdentifier( classTree.getExtendsClause(), ast ); |
| 88 | |||
| 89 | // index the implements clauses | ||
| 90 | for( Tree implementsTree : classTree.getImplementsClause() ) | ||
| 86 | { | 91 | { |
| 87 | // scan until we get the first identifier | 92 | indexClassIdentifier( implementsTree, ast ); |
| 88 | if( token.type == TokenType.IDENTIFIER ) | ||
| 89 | { | ||
| 90 | m_index.add( entry, offsetToken( token, ast.getStart( classTree ) ) ); | ||
| 91 | break; | ||
| 92 | } | ||
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | return entry; | 95 | return classEntry; |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | private FieldEntry indexField( VariableTree variableTree, SourcedAst ast, ClassEntry classEntry ) | 98 | private FieldEntry indexField( VariableTree variableTree, SourcedAst ast, ClassEntry classEntry ) |
| 99 | { | 99 | { |
| 100 | // build the entry | 100 | // index the field name |
| 101 | FieldEntry entry = new FieldEntry( classEntry, variableTree.getName().toString() ); | 101 | FieldEntry entry = new FieldEntry( classEntry, variableTree.getName().toString() ); |
| 102 | Token nameToken = new Lexer( ast.getSource( variableTree ) ).getFirstIdentifierMatching( variableTree.getName() ); | ||
| 103 | addToken( entry, nameToken, variableTree, ast ); | ||
| 102 | 104 | ||
| 103 | // lex the source at this tree node | 105 | // index the field type |
| 104 | Lexer lexer = new Lexer( ast.getSource( variableTree ).toString() ); | 106 | indexClassIdentifier( variableTree.getType(), ast ); |
| 105 | for( Token token : lexer ) | ||
| 106 | { | ||
| 107 | // scan until we find an identifier that matches the field name | ||
| 108 | if( token.type == TokenType.IDENTIFIER && lexer.getText( token ).equals( entry.getName() ) ) | ||
| 109 | { | ||
| 110 | m_index.add( entry, offsetToken( token, ast.getStart( variableTree ) ) ); | ||
| 111 | break; | ||
| 112 | } | ||
| 113 | } | ||
| 114 | 107 | ||
| 115 | return entry; | 108 | return entry; |
| 116 | } | 109 | } |
| @@ -136,13 +129,13 @@ class TreeVisitor extends TreeScanner<CompilationUnitTree, SourcedAst> | |||
| 136 | MethodEntry entry = new MethodEntry( classEntry, methodTree.getName().toString(), signature.toString() ); | 129 | MethodEntry entry = new MethodEntry( classEntry, methodTree.getName().toString(), signature.toString() ); |
| 137 | 130 | ||
| 138 | // lex the source at this tree node | 131 | // lex the source at this tree node |
| 139 | Lexer lexer = new Lexer( ast.getSource( methodTree ).toString() ); | 132 | Lexer lexer = new Lexer( ast.getSource( methodTree ) ); |
| 140 | for( Token token : lexer ) | 133 | for( Token token : lexer ) |
| 141 | { | 134 | { |
| 142 | // scan until we find an identifier that matches the method name | 135 | // scan until we find an identifier that matches the method name |
| 143 | if( token.type == TokenType.IDENTIFIER && lexer.getText( token ).equals( entry.getName() ) ) | 136 | if( token.type == TokenType.IDENTIFIER && lexer.getText( token ).equals( entry.getName() ) ) |
| 144 | { | 137 | { |
| 145 | m_index.add( entry, offsetToken( token, ast.getStart( methodTree ) ) ); | 138 | addToken( entry, token, methodTree, ast ); |
| 146 | break; | 139 | break; |
| 147 | } | 140 | } |
| 148 | } | 141 | } |
| @@ -152,27 +145,47 @@ class TreeVisitor extends TreeScanner<CompilationUnitTree, SourcedAst> | |||
| 152 | 145 | ||
| 153 | private void indexArgument( VariableTree variableTree, SourcedAst ast, MethodEntry methodEntry, int index ) | 146 | private void indexArgument( VariableTree variableTree, SourcedAst ast, MethodEntry methodEntry, int index ) |
| 154 | { | 147 | { |
| 155 | // build the entry | 148 | // index argument name |
| 156 | ArgumentEntry entry = new ArgumentEntry( methodEntry, index, variableTree.getName().toString() ); | 149 | ArgumentEntry entry = new ArgumentEntry( methodEntry, index, variableTree.getName().toString() ); |
| 150 | Token token = new Lexer( ast.getSource( variableTree ) ).getLastIdentifier(); | ||
| 151 | addToken( entry, token, variableTree, ast ); | ||
| 157 | 152 | ||
| 158 | // lex the source at this tree node | 153 | // index argument type |
| 159 | Lexer lexer = new Lexer( ast.getSource( variableTree ).toString() ); | 154 | indexClassIdentifier( variableTree.getType(), ast ); |
| 160 | for( Token token : lexer ) | 155 | } |
| 156 | |||
| 157 | private ClassEntry indexClassIdentifier( Tree tree, SourcedAst ast ) | ||
| 158 | { | ||
| 159 | if( tree == null ) | ||
| 161 | { | 160 | { |
| 162 | // scan until we find an identifier that matches the variable name | 161 | return null; |
| 163 | if( token.type == TokenType.IDENTIFIER && lexer.getText( token ).equals( entry.getName() ) ) | 162 | } |
| 164 | { | 163 | |
| 165 | m_index.add( entry, offsetToken( token, ast.getStart( variableTree ) ) ); | 164 | Lexer lexer = new Lexer( ast.getSource( tree ) ); |
| 166 | break; | 165 | Token token = lexer.getFirstIdentifier(); |
| 167 | } | 166 | if( token == null ) |
| 167 | { | ||
| 168 | return null; | ||
| 168 | } | 169 | } |
| 170 | |||
| 171 | ClassEntry classEntry = new ClassEntry( ast.getFullClassName( lexer.getText( token ) ) ); | ||
| 172 | addToken( classEntry, token, tree, ast ); | ||
| 173 | return classEntry; | ||
| 169 | } | 174 | } |
| 170 | 175 | ||
| 171 | private Token offsetToken( Token in, int offset ) | 176 | private void addToken( Entry entry, Token token, Tree tree, SourcedAst ast ) |
| 172 | { | 177 | { |
| 173 | return new Token( in.type, in.start + offset, in.length ); | 178 | if( token == null ) |
| 179 | { | ||
| 180 | throw new IllegalArgumentException( "token cannot be null!" ); | ||
| 181 | } | ||
| 182 | |||
| 183 | // offset the token by the tree | ||
| 184 | Token offsetToken = new Token( token.type, token.start + ast.getStart( tree ), token.length ); | ||
| 185 | |||
| 186 | m_index.add( entry, offsetToken ); | ||
| 174 | } | 187 | } |
| 175 | 188 | ||
| 176 | private String toJvmType( Tree tree, SourcedAst ast ) | 189 | private String toJvmType( Tree tree, SourcedAst ast ) |
| 177 | { | 190 | { |
| 178 | switch( tree.getKind() ) | 191 | switch( tree.getKind() ) |
diff --git a/src/cuchaz/enigma/analysis/Lexer.java b/src/cuchaz/enigma/analysis/Lexer.java index acb52bf8..602e3a9b 100644 --- a/src/cuchaz/enigma/analysis/Lexer.java +++ b/src/cuchaz/enigma/analysis/Lexer.java | |||
| @@ -14,6 +14,7 @@ import java.util.Iterator; | |||
| 14 | 14 | ||
| 15 | import jsyntaxpane.SyntaxDocument; | 15 | import jsyntaxpane.SyntaxDocument; |
| 16 | import jsyntaxpane.Token; | 16 | import jsyntaxpane.Token; |
| 17 | import jsyntaxpane.TokenType; | ||
| 17 | import jsyntaxpane.lexers.JavaLexer; | 18 | import jsyntaxpane.lexers.JavaLexer; |
| 18 | 19 | ||
| 19 | public class Lexer implements Iterable<Token> | 20 | public class Lexer implements Iterable<Token> |
| @@ -21,10 +22,10 @@ public class Lexer implements Iterable<Token> | |||
| 21 | private SyntaxDocument m_doc; | 22 | private SyntaxDocument m_doc; |
| 22 | private Iterator<Token> m_iter; | 23 | private Iterator<Token> m_iter; |
| 23 | 24 | ||
| 24 | public Lexer( String source ) | 25 | public Lexer( CharSequence source ) |
| 25 | { | 26 | { |
| 26 | m_doc = new SyntaxDocument( new JavaLexer() ); | 27 | m_doc = new SyntaxDocument( new JavaLexer() ); |
| 27 | m_doc.append( source ); | 28 | m_doc.append( source.toString() ); |
| 28 | m_iter = m_doc.getTokens( 0, m_doc.getLength() ); | 29 | m_iter = m_doc.getTokens( 0, m_doc.getLength() ); |
| 29 | } | 30 | } |
| 30 | 31 | ||
| @@ -38,4 +39,41 @@ public class Lexer implements Iterable<Token> | |||
| 38 | { | 39 | { |
| 39 | return token.getString( m_doc ); | 40 | return token.getString( m_doc ); |
| 40 | } | 41 | } |
| 42 | |||
| 43 | public Token getFirstIdentifier( ) | ||
| 44 | { | ||
| 45 | for( Token token : this ) | ||
| 46 | { | ||
| 47 | if( token.type == TokenType.IDENTIFIER ) | ||
| 48 | { | ||
| 49 | return token; | ||
| 50 | } | ||
| 51 | } | ||
| 52 | return null; | ||
| 53 | } | ||
| 54 | |||
| 55 | public Token getFirstIdentifierMatching( CharSequence val ) | ||
| 56 | { | ||
| 57 | for( Token token : this ) | ||
| 58 | { | ||
| 59 | if( token.type == TokenType.IDENTIFIER && getText( token ).equals( val.toString() ) ) | ||
| 60 | { | ||
| 61 | return token; | ||
| 62 | } | ||
| 63 | } | ||
| 64 | return null; | ||
| 65 | } | ||
| 66 | |||
| 67 | public Token getLastIdentifier( ) | ||
| 68 | { | ||
| 69 | Token lastToken = null; | ||
| 70 | for( Token token : this ) | ||
| 71 | { | ||
| 72 | if( token.type == TokenType.IDENTIFIER ) | ||
| 73 | { | ||
| 74 | lastToken = token; | ||
| 75 | } | ||
| 76 | } | ||
| 77 | return lastToken; | ||
| 78 | } | ||
| 41 | } | 79 | } |
diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java index 61c833ce..de163087 100644 --- a/src/cuchaz/enigma/analysis/SourceIndex.java +++ b/src/cuchaz/enigma/analysis/SourceIndex.java | |||
| @@ -10,46 +10,52 @@ | |||
| 10 | ******************************************************************************/ | 10 | ******************************************************************************/ |
| 11 | package cuchaz.enigma.analysis; | 11 | package cuchaz.enigma.analysis; |
| 12 | 12 | ||
| 13 | import java.util.Collection; | ||
| 13 | import java.util.Iterator; | 14 | import java.util.Iterator; |
| 14 | import java.util.Map; | 15 | import java.util.Map; |
| 15 | import java.util.Set; | ||
| 16 | 16 | ||
| 17 | import jsyntaxpane.Token; | 17 | import jsyntaxpane.Token; |
| 18 | 18 | ||
| 19 | import com.google.common.collect.BiMap; | 19 | import com.google.common.collect.HashMultimap; |
| 20 | import com.google.common.collect.HashBiMap; | 20 | import com.google.common.collect.Multimap; |
| 21 | 21 | ||
| 22 | import cuchaz.enigma.mapping.Entry; | 22 | import cuchaz.enigma.mapping.Entry; |
| 23 | 23 | ||
| 24 | public class SourceIndex implements Iterable<Map.Entry<Entry,Token>> | 24 | public class SourceIndex implements Iterable<Map.Entry<Entry,Token>> |
| 25 | { | 25 | { |
| 26 | private BiMap<Entry,Token> m_entryToToken; | 26 | private Multimap<Entry,Token> m_entryToTokens; |
| 27 | private BiMap<Token,Entry> m_tokenToEntry; | ||
| 28 | 27 | ||
| 29 | public SourceIndex( ) | 28 | public SourceIndex( ) |
| 30 | { | 29 | { |
| 31 | m_entryToToken = HashBiMap.create(); | 30 | m_entryToTokens = HashMultimap.create(); |
| 32 | m_tokenToEntry = m_entryToToken.inverse(); | ||
| 33 | } | 31 | } |
| 34 | 32 | ||
| 35 | public void add( Entry entry, Token token ) | 33 | public void add( Entry entry, Token token ) |
| 36 | { | 34 | { |
| 37 | m_entryToToken.put( entry, token ); | 35 | m_entryToTokens.put( entry, token ); |
| 38 | } | 36 | } |
| 39 | 37 | ||
| 40 | public Iterator<Map.Entry<Entry,Token>> iterator( ) | 38 | public Iterator<Map.Entry<Entry,Token>> iterator( ) |
| 41 | { | 39 | { |
| 42 | return m_entryToToken.entrySet().iterator(); | 40 | return m_entryToTokens.entries().iterator(); |
| 43 | } | 41 | } |
| 44 | 42 | ||
| 45 | public Set<Token> tokens( ) | 43 | public Collection<Token> tokens( ) |
| 46 | { | 44 | { |
| 47 | return m_entryToToken.values(); | 45 | return m_entryToTokens.values(); |
| 48 | } | 46 | } |
| 49 | 47 | ||
| 50 | public Entry getEntry( Token token ) | 48 | public Entry getEntry( Token token ) |
| 51 | { | 49 | { |
| 52 | return m_tokenToEntry.get( token ); | 50 | // linear search is fast enough for now |
| 51 | for( Map.Entry<Entry,Token> entry : this ) | ||
| 52 | { | ||
| 53 | if( entry.getValue().equals( token ) ) | ||
| 54 | { | ||
| 55 | return entry.getKey(); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | return null; | ||
| 53 | } | 59 | } |
| 54 | 60 | ||
| 55 | public Map.Entry<Entry,Token> getEntry( int pos ) | 61 | public Map.Entry<Entry,Token> getEntry( int pos ) |
| @@ -66,8 +72,8 @@ public class SourceIndex implements Iterable<Map.Entry<Entry,Token>> | |||
| 66 | return null; | 72 | return null; |
| 67 | } | 73 | } |
| 68 | 74 | ||
| 69 | public Token getToken( Entry entry ) | 75 | public Collection<Token> getTokens( Entry entry ) |
| 70 | { | 76 | { |
| 71 | return m_entryToToken.get( entry ); | 77 | return m_entryToTokens.get( entry ); |
| 72 | } | 78 | } |
| 73 | } | 79 | } |
diff --git a/src/cuchaz/enigma/analysis/SourcedAst.java b/src/cuchaz/enigma/analysis/SourcedAst.java index 968c8804..a88cc754 100644 --- a/src/cuchaz/enigma/analysis/SourcedAst.java +++ b/src/cuchaz/enigma/analysis/SourcedAst.java | |||
| @@ -16,7 +16,6 @@ import java.util.HashMap; | |||
| 16 | import javassist.bytecode.Descriptor; | 16 | import javassist.bytecode.Descriptor; |
| 17 | 17 | ||
| 18 | import com.google.common.collect.Maps; | 18 | import com.google.common.collect.Maps; |
| 19 | import com.sun.source.tree.ClassTree; | ||
| 20 | import com.sun.source.tree.CompilationUnitTree; | 19 | import com.sun.source.tree.CompilationUnitTree; |
| 21 | import com.sun.source.tree.ImportTree; | 20 | import com.sun.source.tree.ImportTree; |
| 22 | import com.sun.source.tree.Tree; | 21 | import com.sun.source.tree.Tree; |
| @@ -29,6 +28,7 @@ public class SourcedAst | |||
| 29 | private Trees m_trees; | 28 | private Trees m_trees; |
| 30 | private SourcePositions m_positions; | 29 | private SourcePositions m_positions; |
| 31 | private HashMap<String,String> m_classNameIndex; | 30 | private HashMap<String,String> m_classNameIndex; |
| 31 | private String m_packageName; | ||
| 32 | 32 | ||
| 33 | public SourcedAst( CompilationUnitTree tree, Trees trees ) | 33 | public SourcedAst( CompilationUnitTree tree, Trees trees ) |
| 34 | { | 34 | { |
| @@ -49,6 +49,13 @@ public class SourcedAst | |||
| 49 | // get the full and simple class names | 49 | // get the full and simple class names |
| 50 | String fullName = Descriptor.toJvmName( importTree.getQualifiedIdentifier().toString() ); | 50 | String fullName = Descriptor.toJvmName( importTree.getQualifiedIdentifier().toString() ); |
| 51 | String simpleName = fullName; | 51 | String simpleName = fullName; |
| 52 | |||
| 53 | if( fullName.startsWith( "__DEFAULT__/" ) ) | ||
| 54 | { | ||
| 55 | // remove the default package flag | ||
| 56 | fullName = fullName.substring( 12 ); | ||
| 57 | } | ||
| 58 | |||
| 52 | String[] parts = fullName.split( "/" ); | 59 | String[] parts = fullName.split( "/" ); |
| 53 | if( parts.length > 0 ) | 60 | if( parts.length > 0 ) |
| 54 | { | 61 | { |
| @@ -58,30 +65,26 @@ public class SourcedAst | |||
| 58 | m_classNameIndex.put( simpleName, fullName ); | 65 | m_classNameIndex.put( simpleName, fullName ); |
| 59 | } | 66 | } |
| 60 | 67 | ||
| 61 | // index the self class using the package name | 68 | // get the package name |
| 69 | m_packageName = null; | ||
| 62 | if( m_tree.getPackageName() != null ) | 70 | if( m_tree.getPackageName() != null ) |
| 63 | { | 71 | { |
| 64 | String packageName = Descriptor.toJvmName( m_tree.getPackageName().toString() ); | 72 | m_packageName = Descriptor.toJvmName( m_tree.getPackageName().toString() ); |
| 65 | for( Tree typeTree : m_tree.getTypeDecls() ) | ||
| 66 | { | ||
| 67 | if( typeTree instanceof ClassTree ) | ||
| 68 | { | ||
| 69 | ClassTree classTree = (ClassTree)typeTree; | ||
| 70 | String className = classTree.getSimpleName().toString(); | ||
| 71 | m_classNameIndex.put( className, packageName + "/" + className ); | ||
| 72 | } | ||
| 73 | } | ||
| 74 | } | 73 | } |
| 75 | } | 74 | } |
| 76 | 75 | ||
| 77 | public int getStart( Tree node ) | 76 | public int getStart( Tree node ) |
| 78 | { | 77 | { |
| 79 | return (int)m_positions.getStartPosition( m_tree, node ); | 78 | int pos = (int)m_positions.getStartPosition( m_tree, node ); |
| 79 | assert( pos >= 0 ); | ||
| 80 | return pos; | ||
| 80 | } | 81 | } |
| 81 | 82 | ||
| 82 | public int getEnd( Tree node ) | 83 | public int getEnd( Tree node ) |
| 83 | { | 84 | { |
| 84 | return (int)m_positions.getEndPosition( m_tree, node ); | 85 | int pos = (int)m_positions.getEndPosition( m_tree, node ); |
| 86 | assert( pos >= 0 ); | ||
| 87 | return pos; | ||
| 85 | } | 88 | } |
| 86 | 89 | ||
| 87 | public int getLine( Tree node ) | 90 | public int getLine( Tree node ) |
| @@ -121,8 +124,16 @@ public class SourcedAst | |||
| 121 | String fullClassName = m_classNameIndex.get( simpleClassName ); | 124 | String fullClassName = m_classNameIndex.get( simpleClassName ); |
| 122 | if( fullClassName == null ) | 125 | if( fullClassName == null ) |
| 123 | { | 126 | { |
| 124 | // no mapping was found, the name is probably already fully-qualified | 127 | if( m_packageName != null ) |
| 125 | fullClassName = simpleClassName; | 128 | { |
| 129 | // no mapping was found, assume it's in the package | ||
| 130 | fullClassName = m_packageName + "/" + simpleClassName; | ||
| 131 | } | ||
| 132 | else | ||
| 133 | { | ||
| 134 | // this must be in the default package | ||
| 135 | fullClassName = simpleClassName; | ||
| 136 | } | ||
| 126 | } | 137 | } |
| 127 | return fullClassName; | 138 | return fullClassName; |
| 128 | } | 139 | } |
diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index 7d37febf..2219e05b 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java | |||
| @@ -132,6 +132,16 @@ public class GuiController | |||
| 132 | return m_deobfuscator.hasMapping( pair.obf ); | 132 | return m_deobfuscator.hasMapping( pair.obf ); |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | public boolean entryIsObfuscatedIdenfitier( int pos ) | ||
| 136 | { | ||
| 137 | EntryPair<Entry> pair = getEntryPair( pos ); | ||
| 138 | if( pair == null || pair.obf == null ) | ||
| 139 | { | ||
| 140 | return false; | ||
| 141 | } | ||
| 142 | return m_deobfuscator.entryIsObfuscatedIdenfitier( pair.obf ); | ||
| 143 | } | ||
| 144 | |||
| 135 | public ClassInheritanceTreeNode getClassInheritance( ClassEntry classEntry ) | 145 | public ClassInheritanceTreeNode getClassInheritance( ClassEntry classEntry ) |
| 136 | { | 146 | { |
| 137 | Translator deobfuscatingTranslator = m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ); | 147 | Translator deobfuscatingTranslator = m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ); |
| @@ -216,7 +226,7 @@ public class GuiController | |||
| 216 | { | 226 | { |
| 217 | deobfuscatedTokens.add( token ); | 227 | deobfuscatedTokens.add( token ); |
| 218 | } | 228 | } |
| 219 | else | 229 | else if( entryIsObfuscatedIdenfitier( token.start ) ) |
| 220 | { | 230 | { |
| 221 | obfuscatedTokens.add( token ); | 231 | obfuscatedTokens.add( token ); |
| 222 | } | 232 | } |
diff --git a/src/cuchaz/enigma/gui/SourceFormatter.java b/src/cuchaz/enigma/gui/SourceFormatter.java deleted file mode 100644 index f3878405..00000000 --- a/src/cuchaz/enigma/gui/SourceFormatter.java +++ /dev/null | |||
| @@ -1,62 +0,0 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | * Copyright (c) 2014 Jeff Martin. | ||
| 3 | * All rights reserved. This program and the accompanying materials | ||
| 4 | * are made available under the terms of the GNU Public License v3.0 | ||
| 5 | * which accompanies this distribution, and is available at | ||
| 6 | * http://www.gnu.org/licenses/gpl.html | ||
| 7 | * | ||
| 8 | * Contributors: | ||
| 9 | * Jeff Martin - initial API and implementation | ||
| 10 | ******************************************************************************/ | ||
| 11 | package cuchaz.enigma.gui; | ||
| 12 | |||
| 13 | import java.io.BufferedReader; | ||
| 14 | import java.io.IOException; | ||
| 15 | import java.io.StringReader; | ||
| 16 | |||
| 17 | public class SourceFormatter | ||
| 18 | { | ||
| 19 | public static String format( String in ) | ||
| 20 | { | ||
| 21 | return collapseNewlines( in ); | ||
| 22 | } | ||
| 23 | |||
| 24 | private static String collapseNewlines( String in ) | ||
| 25 | { | ||
| 26 | StringBuffer buf = new StringBuffer(); | ||
| 27 | int numBlankLines = 0; | ||
| 28 | |||
| 29 | BufferedReader reader = new BufferedReader( new StringReader( in ) ); | ||
| 30 | String line = null; | ||
| 31 | try | ||
| 32 | { | ||
| 33 | while( ( line = reader.readLine() ) != null ) | ||
| 34 | { | ||
| 35 | // how blank lines is this? | ||
| 36 | boolean isBlank = line.trim().length() == 0; | ||
| 37 | if( isBlank ) | ||
| 38 | { | ||
| 39 | numBlankLines++; | ||
| 40 | |||
| 41 | // stop printing blank lines after the first one | ||
| 42 | if( numBlankLines < 2 ) | ||
| 43 | { | ||
| 44 | buf.append( line ); | ||
| 45 | buf.append( "\n" ); | ||
| 46 | } | ||
| 47 | } | ||
| 48 | else | ||
| 49 | { | ||
| 50 | numBlankLines = 0; | ||
| 51 | buf.append( line ); | ||
| 52 | buf.append( "\n" ); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | } | ||
| 56 | catch( IOException ex ) | ||
| 57 | { | ||
| 58 | // StringReader will never throw an IOExecption here... | ||
| 59 | } | ||
| 60 | return buf.toString(); | ||
| 61 | } | ||
| 62 | } | ||