summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cuchaz/enigma/Deobfuscator.java87
-rw-r--r--src/cuchaz/enigma/analysis/Analyzer.java91
-rw-r--r--src/cuchaz/enigma/analysis/Lexer.java42
-rw-r--r--src/cuchaz/enigma/analysis/SourceIndex.java34
-rw-r--r--src/cuchaz/enigma/analysis/SourcedAst.java43
-rw-r--r--src/cuchaz/enigma/gui/GuiController.java12
-rw-r--r--src/cuchaz/enigma/gui/SourceFormatter.java62
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 ******************************************************************************/
11package cuchaz.enigma; 11package cuchaz.enigma;
12 12
13import java.io.BufferedReader;
13import java.io.File; 14import java.io.File;
14import java.io.FileInputStream; 15import java.io.FileInputStream;
15import java.io.IOException; 16import java.io.IOException;
16import java.io.InputStream; 17import java.io.InputStream;
18import java.io.StringReader;
17import java.io.StringWriter; 19import java.io.StringWriter;
18import java.util.Enumeration; 20import java.util.Enumeration;
19import java.util.List; 21import java.util.List;
@@ -21,6 +23,7 @@ import java.util.Map;
21import java.util.jar.JarEntry; 23import java.util.jar.JarEntry;
22import java.util.jar.JarFile; 24import java.util.jar.JarFile;
23 25
26import com.beust.jcommander.internal.Lists;
24import com.strobel.decompiler.Decompiler; 27import com.strobel.decompiler.Decompiler;
25import com.strobel.decompiler.DecompilerSettings; 28import com.strobel.decompiler.DecompilerSettings;
26import com.strobel.decompiler.PlainTextOutput; 29import 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
36import cuchaz.enigma.mapping.ArgumentEntry; 36import cuchaz.enigma.mapping.ArgumentEntry;
37import cuchaz.enigma.mapping.ClassEntry; 37import cuchaz.enigma.mapping.ClassEntry;
38import cuchaz.enigma.mapping.Entry;
38import cuchaz.enigma.mapping.FieldEntry; 39import cuchaz.enigma.mapping.FieldEntry;
39import cuchaz.enigma.mapping.MethodEntry; 40import 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
15import jsyntaxpane.SyntaxDocument; 15import jsyntaxpane.SyntaxDocument;
16import jsyntaxpane.Token; 16import jsyntaxpane.Token;
17import jsyntaxpane.TokenType;
17import jsyntaxpane.lexers.JavaLexer; 18import jsyntaxpane.lexers.JavaLexer;
18 19
19public class Lexer implements Iterable<Token> 20public 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 ******************************************************************************/
11package cuchaz.enigma.analysis; 11package cuchaz.enigma.analysis;
12 12
13import java.util.Collection;
13import java.util.Iterator; 14import java.util.Iterator;
14import java.util.Map; 15import java.util.Map;
15import java.util.Set;
16 16
17import jsyntaxpane.Token; 17import jsyntaxpane.Token;
18 18
19import com.google.common.collect.BiMap; 19import com.google.common.collect.HashMultimap;
20import com.google.common.collect.HashBiMap; 20import com.google.common.collect.Multimap;
21 21
22import cuchaz.enigma.mapping.Entry; 22import cuchaz.enigma.mapping.Entry;
23 23
24public class SourceIndex implements Iterable<Map.Entry<Entry,Token>> 24public 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;
16import javassist.bytecode.Descriptor; 16import javassist.bytecode.Descriptor;
17 17
18import com.google.common.collect.Maps; 18import com.google.common.collect.Maps;
19import com.sun.source.tree.ClassTree;
20import com.sun.source.tree.CompilationUnitTree; 19import com.sun.source.tree.CompilationUnitTree;
21import com.sun.source.tree.ImportTree; 20import com.sun.source.tree.ImportTree;
22import com.sun.source.tree.Tree; 21import 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 ******************************************************************************/
11package cuchaz.enigma.gui;
12
13import java.io.BufferedReader;
14import java.io.IOException;
15import java.io.StringReader;
16
17public 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}