diff options
| author | 2014-08-07 00:55:43 -0400 | |
|---|---|---|
| committer | 2014-08-07 00:55:43 -0400 | |
| commit | 6aa7c6121a2ecbe78f14f8c3d7ddb55b8ddb10bd (patch) | |
| tree | 0b97553e42e2e3a52a1aab30914d885d143d5bf0 /src | |
| 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
Diffstat (limited to 'src')
| -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 | } | ||