summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cuchaz/enigma/ClassFile.java45
-rw-r--r--src/cuchaz/enigma/Deobfuscator.java109
-rw-r--r--src/cuchaz/enigma/Main.java63
-rw-r--r--src/cuchaz/enigma/Util.java65
-rw-r--r--src/cuchaz/enigma/analysis/Analyzer.java252
-rw-r--r--src/cuchaz/enigma/analysis/ClassNameIndex.java19
-rw-r--r--src/cuchaz/enigma/analysis/JavaSourceFromString.java31
-rw-r--r--src/cuchaz/enigma/analysis/Lexer.java41
-rw-r--r--src/cuchaz/enigma/analysis/SourceIndex.java57
-rw-r--r--src/cuchaz/enigma/analysis/SourcedAst.java111
-rw-r--r--src/cuchaz/enigma/gui/BoxHighlightPainter.java54
-rw-r--r--src/cuchaz/enigma/gui/ClassSelectionHandler.java18
-rw-r--r--src/cuchaz/enigma/gui/Gui.java163
-rw-r--r--src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java40
-rw-r--r--src/cuchaz/enigma/gui/SourceFormatter.java62
-rw-r--r--src/cuchaz/enigma/mapping/ArgumentEntry.java88
-rw-r--r--src/cuchaz/enigma/mapping/ClassEntry.java67
-rw-r--r--src/cuchaz/enigma/mapping/FieldEntry.java76
-rw-r--r--src/cuchaz/enigma/mapping/MethodEntry.java88
19 files changed, 1449 insertions, 0 deletions
diff --git a/src/cuchaz/enigma/ClassFile.java b/src/cuchaz/enigma/ClassFile.java
new file mode 100644
index 00000000..221a119e
--- /dev/null
+++ b/src/cuchaz/enigma/ClassFile.java
@@ -0,0 +1,45 @@
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;
12
13import java.util.regex.Pattern;
14
15public class ClassFile
16{
17 private static Pattern m_obfuscatedClassPattern;
18
19 static
20 {
21 m_obfuscatedClassPattern = Pattern.compile( "^[a-z]+$" );
22 }
23
24 private String m_name;
25
26 public ClassFile( String name )
27 {
28 m_name = name;
29 }
30
31 public String getName( )
32 {
33 return m_name;
34 }
35
36 public boolean isObfuscated( )
37 {
38 return m_obfuscatedClassPattern.matcher( m_name ).matches();
39 }
40
41 public String getPath( )
42 {
43 return m_name.replace( ".", "/" ) + ".class";
44 }
45}
diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java
new file mode 100644
index 00000000..83a21719
--- /dev/null
+++ b/src/cuchaz/enigma/Deobfuscator.java
@@ -0,0 +1,109 @@
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;
12
13import java.io.File;
14import java.io.IOException;
15import java.io.StringWriter;
16import java.util.ArrayList;
17import java.util.Collections;
18import java.util.Comparator;
19import java.util.Enumeration;
20import java.util.List;
21import java.util.jar.JarEntry;
22import java.util.jar.JarFile;
23
24import com.strobel.assembler.metadata.JarTypeLoader;
25import com.strobel.decompiler.Decompiler;
26import com.strobel.decompiler.DecompilerSettings;
27import com.strobel.decompiler.PlainTextOutput;
28
29public class Deobfuscator
30{
31 private File m_file;
32 private JarFile m_jar;
33 private DecompilerSettings m_settings;
34
35 private static Comparator<ClassFile> m_obfuscatedClassSorter;
36
37 static
38 {
39 m_obfuscatedClassSorter = new Comparator<ClassFile>( )
40 {
41 @Override
42 public int compare( ClassFile a, ClassFile b )
43 {
44 if( a.getName().length() != b.getName().length() )
45 {
46 return a.getName().length() - b.getName().length();
47 }
48
49 return a.getName().compareTo( b.getName() );
50 }
51 };
52 }
53
54 public Deobfuscator( File file )
55 throws IOException
56 {
57 m_file = file;
58 m_jar = new JarFile( m_file );
59 m_settings = DecompilerSettings.javaDefaults();
60 m_settings.setTypeLoader( new JarTypeLoader( m_jar ) );
61 m_settings.setForceExplicitImports( true );
62 m_settings.setShowSyntheticMembers( true );
63 }
64
65 public List<ClassFile> getObfuscatedClasses( )
66 {
67 List<ClassFile> classes = new ArrayList<ClassFile>();
68 Enumeration<JarEntry> entries = m_jar.entries();
69 while( entries.hasMoreElements() )
70 {
71 JarEntry entry = entries.nextElement();
72
73 // get the class name
74 String className = toClassName( entry.getName() );
75 if( className == null )
76 {
77 continue;
78 }
79
80 ClassFile classFile = new ClassFile( className );
81 if( classFile.isObfuscated() )
82 {
83 classes.add( classFile );
84 }
85 }
86 Collections.sort( classes, m_obfuscatedClassSorter );
87 return classes;
88 }
89
90 // TODO: could go somewhere more generic
91 private static String toClassName( String fileName )
92 {
93 final String suffix = ".class";
94
95 if( !fileName.endsWith( suffix ) )
96 {
97 return null;
98 }
99
100 return fileName.substring( 0, fileName.length() - suffix.length() ).replace( "/", "." );
101 }
102
103 public String getSource( final ClassFile classFile )
104 {
105 StringWriter buf = new StringWriter();
106 Decompiler.decompile( classFile.getName(), new PlainTextOutput( buf ), m_settings );
107 return buf.toString();
108 }
109}
diff --git a/src/cuchaz/enigma/Main.java b/src/cuchaz/enigma/Main.java
new file mode 100644
index 00000000..e08c16ed
--- /dev/null
+++ b/src/cuchaz/enigma/Main.java
@@ -0,0 +1,63 @@
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;
12
13import java.io.File;
14
15import cuchaz.enigma.analysis.Analyzer;
16import cuchaz.enigma.analysis.SourceIndex;
17import cuchaz.enigma.gui.ClassSelectionHandler;
18import cuchaz.enigma.gui.Gui;
19
20public class Main
21{
22 public static void main( String[] args )
23 throws Exception
24 {
25 startGui();
26 }
27
28 private static void startGui( )
29 throws Exception
30 {
31 final Gui gui = new Gui();
32
33 // settings
34 final File jarFile = new File( "/home/jeff/.minecraft/versions/1.7.10/1.7.10.jar" );
35 gui.setTitle( jarFile.getName() );
36
37 // init the deobfuscator
38 final Deobfuscator deobfuscator = new Deobfuscator( jarFile );
39 gui.setObfClasses( deobfuscator.getObfuscatedClasses() );
40
41 // handle events
42 gui.setClassSelectionHandler( new ClassSelectionHandler( )
43 {
44 @Override
45 public void classSelected( final ClassFile classFile )
46 {
47 gui.setSource( "(deobfuscating...)" );
48
49 // run the deobfuscator in a separate thread so we don't block the GUI event queue
50 new Thread( )
51 {
52 @Override
53 public void run( )
54 {
55 String source = deobfuscator.getSource( classFile );
56 SourceIndex index = Analyzer.analyze( classFile.getName(), source );
57 gui.setSource( source, index );
58 }
59 }.start();
60 }
61 } );
62 }
63}
diff --git a/src/cuchaz/enigma/Util.java b/src/cuchaz/enigma/Util.java
new file mode 100644
index 00000000..c51eb621
--- /dev/null
+++ b/src/cuchaz/enigma/Util.java
@@ -0,0 +1,65 @@
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;
12
13import java.io.Closeable;
14import java.io.IOException;
15import java.util.jar.JarFile;
16
17
18public class Util
19{
20 public static int combineHashesOrdered( Object ... objs )
21 {
22 final int prime = 67;
23 int result = 1;
24 for( Object obj : objs )
25 {
26 result *= prime;
27 if( obj != null )
28 {
29 result += obj.hashCode();
30 }
31 }
32 return result;
33 }
34
35 public static void closeQuietly( Closeable closeable )
36 {
37 if( closeable != null )
38 {
39 try
40 {
41 closeable.close();
42 }
43 catch( IOException ex )
44 {
45 // just ignore any further exceptions
46 }
47 }
48 }
49
50 public static void closeQuietly( JarFile jarFile )
51 {
52 // silly library should implement Closeable...
53 if( jarFile != null )
54 {
55 try
56 {
57 jarFile.close();
58 }
59 catch( IOException ex )
60 {
61 // just ignore any further exceptions
62 }
63 }
64 }
65}
diff --git a/src/cuchaz/enigma/analysis/Analyzer.java b/src/cuchaz/enigma/analysis/Analyzer.java
new file mode 100644
index 00000000..1cdabe75
--- /dev/null
+++ b/src/cuchaz/enigma/analysis/Analyzer.java
@@ -0,0 +1,252 @@
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.analysis;
12
13import java.io.IOException;
14import java.util.Arrays;
15
16import javax.tools.JavaCompiler;
17import javax.tools.StandardJavaFileManager;
18import javax.tools.ToolProvider;
19
20import jsyntaxpane.Token;
21import jsyntaxpane.TokenType;
22
23import com.sun.source.tree.ArrayTypeTree;
24import com.sun.source.tree.ClassTree;
25import com.sun.source.tree.CompilationUnitTree;
26import com.sun.source.tree.IdentifierTree;
27import com.sun.source.tree.MethodTree;
28import com.sun.source.tree.PrimitiveTypeTree;
29import com.sun.source.tree.Tree;
30import com.sun.source.tree.Tree.Kind;
31import com.sun.source.tree.VariableTree;
32import com.sun.source.util.JavacTask;
33import com.sun.source.util.TreeScanner;
34import com.sun.source.util.Trees;
35
36import cuchaz.enigma.mapping.ArgumentEntry;
37import cuchaz.enigma.mapping.ClassEntry;
38import cuchaz.enigma.mapping.FieldEntry;
39import cuchaz.enigma.mapping.MethodEntry;
40
41class TreeVisitor extends TreeScanner<CompilationUnitTree, SourcedAst>
42{
43 private SourceIndex m_index;
44
45 public TreeVisitor( SourceIndex index )
46 {
47 m_index = index;
48 }
49
50 @Override
51 public CompilationUnitTree visitClass( ClassTree classTree, SourcedAst ast )
52 {
53 ClassEntry classEntry = indexClass( classTree, ast );
54
55 // look at the class members
56 for( Tree memberTree : classTree.getMembers() )
57 {
58 if( memberTree.getKind() == Kind.VARIABLE )
59 {
60 indexField( (VariableTree)memberTree, ast, classEntry );
61 }
62 else if( memberTree.getKind() == Kind.METHOD )
63 {
64 MethodTree methodTree = (MethodTree)memberTree;
65 MethodEntry methodEntry = indexMethod( methodTree, ast, classEntry );
66
67 // look at method arguments
68 int argNum = 0;
69 for( VariableTree variableTree : methodTree.getParameters() )
70 {
71 indexArgument( variableTree, ast, methodEntry, argNum++ );
72 }
73 }
74 }
75
76 return super.visitClass( classTree, ast );
77 }
78
79 private ClassEntry indexClass( ClassTree classTree, SourcedAst ast )
80 {
81 // build the entry
82 ClassEntry entry = new ClassEntry( ast.getFullClassName( classTree.getSimpleName().toString() ) );
83
84 // lex the source at this tree node
85 for( Token token : new Lexer( ast.getSource( classTree ).toString() ) )
86 {
87 // scan until we get the first identifier
88 if( token.type == TokenType.IDENTIFIER )
89 {
90 m_index.add( entry, offsetToken( token, ast.getStart( classTree ) ) );
91 break;
92 }
93 }
94
95 return entry;
96 }
97
98 private FieldEntry indexField( VariableTree variableTree, SourcedAst ast, ClassEntry classEntry )
99 {
100 // build the entry
101 FieldEntry entry = new FieldEntry( classEntry, variableTree.getName().toString() );
102
103 // lex the source at this tree node
104 Lexer lexer = new Lexer( ast.getSource( variableTree ).toString() );
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
115 return entry;
116 }
117
118 private MethodEntry indexMethod( MethodTree methodTree, SourcedAst ast, ClassEntry classEntry )
119 {
120 // build the entry
121 StringBuilder signature = new StringBuilder();
122 signature.append( "(" );
123 for( VariableTree variableTree : methodTree.getParameters() )
124 {
125 signature.append( toJvmType( variableTree.getType(), ast ) );
126 }
127 signature.append( ")" );
128 if( methodTree.getReturnType() != null )
129 {
130 signature.append( toJvmType( methodTree.getReturnType(), ast ) );
131 }
132 else
133 {
134 signature.append( "V" );
135 }
136 MethodEntry entry = new MethodEntry( classEntry, methodTree.getName().toString(), signature.toString() );
137
138 // lex the source at this tree node
139 Lexer lexer = new Lexer( ast.getSource( methodTree ).toString() );
140 for( Token token : lexer )
141 {
142 // scan until we find an identifier that matches the method name
143 if( token.type == TokenType.IDENTIFIER && lexer.getText( token ).equals( entry.getName() ) )
144 {
145 m_index.add( entry, offsetToken( token, ast.getStart( methodTree ) ) );
146 break;
147 }
148 }
149
150 return entry;
151 }
152
153 private void indexArgument( VariableTree variableTree, SourcedAst ast, MethodEntry methodEntry, int index )
154 {
155 System.out.println( "\tFound argument: " + variableTree.getName() );
156
157 // build the entry
158 ArgumentEntry entry = new ArgumentEntry( methodEntry, index, variableTree.getName().toString() );
159
160 // lex the source at this tree node
161 Lexer lexer = new Lexer( ast.getSource( variableTree ).toString() );
162 for( Token token : lexer )
163 {
164 // scan until we find an identifier that matches the variable name
165 if( token.type == TokenType.IDENTIFIER && lexer.getText( token ).equals( entry.getName() ) )
166 {
167 m_index.add( entry, offsetToken( token, ast.getStart( variableTree ) ) );
168 break;
169 }
170 }
171 }
172
173 private Token offsetToken( Token in, int offset )
174 {
175 return new Token( in.type, in.start + offset, in.length );
176 }
177
178 private String toJvmType( Tree tree, SourcedAst ast )
179 {
180 switch( tree.getKind() )
181 {
182 case PRIMITIVE_TYPE:
183 {
184 PrimitiveTypeTree primitiveTypeTree = (PrimitiveTypeTree)tree;
185 switch( primitiveTypeTree.getPrimitiveTypeKind() )
186 {
187 case BOOLEAN: return "Z";
188 case BYTE: return "B";
189 case CHAR: return "C";
190 case DOUBLE: return "D";
191 case FLOAT: return "F";
192 case INT: return "I";
193 case LONG: return "J";
194 case SHORT: return "S";
195 case VOID: return "V";
196
197 default:
198 throw new Error( "Unsupported primitive type: " + primitiveTypeTree.getPrimitiveTypeKind() );
199 }
200 }
201
202 case IDENTIFIER:
203 {
204 IdentifierTree identifierTree = (IdentifierTree)tree;
205 String className = identifierTree.getName().toString();
206 className = ast.getFullClassName( className );
207 return "L" + className.replace( ".", "/" ) + ";";
208 }
209
210 case ARRAY_TYPE:
211 {
212 ArrayTypeTree arrayTree = (ArrayTypeTree)tree;
213 return "[" + toJvmType( arrayTree.getType(), ast );
214 }
215
216
217 default:
218 throw new Error( "Unsupported type kind: " + tree.getKind() );
219 }
220 }
221}
222
223public class Analyzer
224{
225 public static SourceIndex analyze( String className, String source )
226 {
227 SourceIndex index = new SourceIndex();
228 SourcedAst ast = getAst( className, source );
229 ast.visit( new TreeVisitor( index ) );
230 return index;
231 }
232
233 private static SourcedAst getAst( String className, String source )
234 {
235 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
236 StandardJavaFileManager fileManager = compiler.getStandardFileManager( null, null, null );
237 JavaSourceFromString unit = new JavaSourceFromString( className, source );
238 JavacTask task = (JavacTask)compiler.getTask( null, fileManager, null, null, null, Arrays.asList( unit ) );
239
240 try
241 {
242 return new SourcedAst(
243 task.parse().iterator().next(),
244 Trees.instance( task )
245 );
246 }
247 catch( IOException ex )
248 {
249 throw new Error( ex );
250 }
251 }
252}
diff --git a/src/cuchaz/enigma/analysis/ClassNameIndex.java b/src/cuchaz/enigma/analysis/ClassNameIndex.java
new file mode 100644
index 00000000..ea3e2cae
--- /dev/null
+++ b/src/cuchaz/enigma/analysis/ClassNameIndex.java
@@ -0,0 +1,19 @@
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.analysis;
12
13import com.sun.source.tree.CompilationUnitTree;
14import com.sun.source.util.TreeScanner;
15
16public class ClassNameIndex extends TreeScanner<CompilationUnitTree, SourcedAst>
17{
18
19}
diff --git a/src/cuchaz/enigma/analysis/JavaSourceFromString.java b/src/cuchaz/enigma/analysis/JavaSourceFromString.java
new file mode 100644
index 00000000..cf5c4c27
--- /dev/null
+++ b/src/cuchaz/enigma/analysis/JavaSourceFromString.java
@@ -0,0 +1,31 @@
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.analysis;
12
13import java.net.URI;
14
15import javax.tools.SimpleJavaFileObject;
16
17public class JavaSourceFromString extends SimpleJavaFileObject
18{
19 private final String m_source;
20
21 JavaSourceFromString( String name, String source )
22 {
23 super( URI.create( "string:///" + name.replace( '.', '/' ) + Kind.SOURCE.extension ), Kind.SOURCE );
24 m_source = source;
25 }
26
27 public CharSequence getCharContent( boolean ignoreEncodingErrors )
28 {
29 return m_source;
30 }
31}
diff --git a/src/cuchaz/enigma/analysis/Lexer.java b/src/cuchaz/enigma/analysis/Lexer.java
new file mode 100644
index 00000000..acb52bf8
--- /dev/null
+++ b/src/cuchaz/enigma/analysis/Lexer.java
@@ -0,0 +1,41 @@
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.analysis;
12
13import java.util.Iterator;
14
15import jsyntaxpane.SyntaxDocument;
16import jsyntaxpane.Token;
17import jsyntaxpane.lexers.JavaLexer;
18
19public class Lexer implements Iterable<Token>
20{
21 private SyntaxDocument m_doc;
22 private Iterator<Token> m_iter;
23
24 public Lexer( String source )
25 {
26 m_doc = new SyntaxDocument( new JavaLexer() );
27 m_doc.append( source );
28 m_iter = m_doc.getTokens( 0, m_doc.getLength() );
29 }
30
31 @Override
32 public Iterator<Token> iterator( )
33 {
34 return m_iter;
35 }
36
37 public String getText( Token token )
38 {
39 return token.getString( m_doc );
40 }
41}
diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java
new file mode 100644
index 00000000..a4b5329b
--- /dev/null
+++ b/src/cuchaz/enigma/analysis/SourceIndex.java
@@ -0,0 +1,57 @@
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.analysis;
12
13import java.util.Iterator;
14import java.util.Map;
15import java.util.Set;
16
17import jsyntaxpane.Token;
18
19import com.google.common.collect.BiMap;
20import com.google.common.collect.HashBiMap;
21
22public class SourceIndex implements Iterable<Map.Entry<Object,Token>>
23{
24 private BiMap<Object,Token> m_entryToToken;
25 private BiMap<Token,Object> m_tokenToEntry;
26
27 public SourceIndex( )
28 {
29 m_entryToToken = HashBiMap.create();
30 m_tokenToEntry = m_entryToToken.inverse();
31 }
32
33 public void add( Object entry, Token token )
34 {
35 m_entryToToken.put( entry, token );
36 }
37
38 public Iterator<Map.Entry<Object,Token>> iterator( )
39 {
40 return m_entryToToken.entrySet().iterator();
41 }
42
43 public Set<Token> tokens( )
44 {
45 return m_entryToToken.values();
46 }
47
48 public Object getEntry( Token token )
49 {
50 return m_tokenToEntry.get( token );
51 }
52
53 public Object getToken( Object entry )
54 {
55 return m_entryToToken.get( entry );
56 }
57}
diff --git a/src/cuchaz/enigma/analysis/SourcedAst.java b/src/cuchaz/enigma/analysis/SourcedAst.java
new file mode 100644
index 00000000..04c6f03b
--- /dev/null
+++ b/src/cuchaz/enigma/analysis/SourcedAst.java
@@ -0,0 +1,111 @@
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.analysis;
12
13import java.io.IOException;
14import java.util.HashMap;
15
16import com.google.common.collect.Maps;
17import com.sun.source.tree.CompilationUnitTree;
18import com.sun.source.tree.ImportTree;
19import com.sun.source.tree.Tree;
20import com.sun.source.util.SourcePositions;
21import com.sun.source.util.Trees;
22
23public class SourcedAst
24{
25 private CompilationUnitTree m_tree;
26 private Trees m_trees;
27 private SourcePositions m_positions;
28 private HashMap<String,String> m_classNameIndex;
29
30 public SourcedAst( CompilationUnitTree tree, Trees trees )
31 {
32 m_tree = tree;
33 m_trees = trees;
34 m_positions = m_trees.getSourcePositions();
35 m_classNameIndex = Maps.newHashMap();
36
37 // index all the class names
38 for( ImportTree importTree : m_tree.getImports() )
39 {
40 // ignore static imports for now
41 if( importTree.isStatic() )
42 {
43 continue;
44 }
45
46 // get the full and simple class names
47 String fullName = importTree.getQualifiedIdentifier().toString();
48 String simpleName = fullName;
49 String[] parts = fullName.split( "\\." );
50 if( parts.length > 0 )
51 {
52 simpleName = parts[parts.length - 1];
53 }
54
55 m_classNameIndex.put( simpleName, fullName );
56 }
57 }
58
59 public int getStart( Tree node )
60 {
61 return (int)m_positions.getStartPosition( m_tree, node );
62 }
63
64 public int getEnd( Tree node )
65 {
66 return (int)m_positions.getEndPosition( m_tree, node );
67 }
68
69 public int getLine( Tree node )
70 {
71 return getLine( getStart( node ) );
72 }
73
74 public int getLine( int pos )
75 {
76 return (int)m_tree.getLineMap().getLineNumber( pos );
77 }
78
79 public CharSequence getSource( )
80 {
81 try
82 {
83 return m_tree.getSourceFile().getCharContent( true );
84 }
85 catch( IOException ex )
86 {
87 throw new Error( ex );
88 }
89 }
90
91 public CharSequence getSource( Tree node )
92 {
93 return getSource().subSequence( getStart( node ), getEnd( node ) );
94 }
95
96 public void visit( TreeVisitor visitor )
97 {
98 m_tree.accept( visitor, this );
99 }
100
101 public String getFullClassName( String simpleClassName )
102 {
103 String fullClassName = m_classNameIndex.get( simpleClassName );
104 if( fullClassName == null )
105 {
106 // no mapping was found, the name is probably already fully-qualified
107 fullClassName = simpleClassName;
108 }
109 return fullClassName;
110 }
111}
diff --git a/src/cuchaz/enigma/gui/BoxHighlightPainter.java b/src/cuchaz/enigma/gui/BoxHighlightPainter.java
new file mode 100644
index 00000000..22db28b7
--- /dev/null
+++ b/src/cuchaz/enigma/gui/BoxHighlightPainter.java
@@ -0,0 +1,54 @@
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.awt.Color;
14import java.awt.Graphics;
15import java.awt.Rectangle;
16import java.awt.Shape;
17
18import javax.swing.text.BadLocationException;
19import javax.swing.text.Highlighter;
20import javax.swing.text.JTextComponent;
21
22public class BoxHighlightPainter implements Highlighter.HighlightPainter
23{
24 private static final Color FillColor = new Color( 230, 230, 230 );
25 private static final Color BorderColor = new Color( 100, 100, 100 );
26
27 @Override
28 public void paint( Graphics g, int start, int end, Shape shape, JTextComponent text )
29 {
30 try
31 {
32 // determine the bounds of the text
33 Rectangle bounds = text.getUI().modelToView( text, start ).union( text.getUI().modelToView( text, end ) );
34
35 // adjust the box so it looks nice
36 bounds.x -= 2;
37 bounds.width += 2;
38 bounds.y += 1;
39 bounds.height -= 2;
40
41 // fill the area
42 g.setColor( FillColor );
43 g.fillRoundRect( bounds.x, bounds.y, bounds.width, bounds.height, 4, 4 );
44
45 // draw a box around the area
46 g.setColor( BorderColor );
47 g.drawRoundRect( bounds.x, bounds.y, bounds.width, bounds.height, 4, 4 );
48 }
49 catch( BadLocationException ex )
50 {
51 throw new Error( ex );
52 }
53 }
54}
diff --git a/src/cuchaz/enigma/gui/ClassSelectionHandler.java b/src/cuchaz/enigma/gui/ClassSelectionHandler.java
new file mode 100644
index 00000000..a50cf6a3
--- /dev/null
+++ b/src/cuchaz/enigma/gui/ClassSelectionHandler.java
@@ -0,0 +1,18 @@
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 cuchaz.enigma.ClassFile;
14
15public interface ClassSelectionHandler
16{
17 void classSelected( ClassFile classFile );
18}
diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java
new file mode 100644
index 00000000..e0d53d83
--- /dev/null
+++ b/src/cuchaz/enigma/gui/Gui.java
@@ -0,0 +1,163 @@
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.awt.BorderLayout;
14import java.awt.Container;
15import java.awt.event.MouseAdapter;
16import java.awt.event.MouseEvent;
17import java.util.List;
18import java.util.Vector;
19
20import javax.swing.JEditorPane;
21import javax.swing.JFrame;
22import javax.swing.JLabel;
23import javax.swing.JList;
24import javax.swing.JPanel;
25import javax.swing.JScrollPane;
26import javax.swing.JSplitPane;
27import javax.swing.ListSelectionModel;
28import javax.swing.WindowConstants;
29import javax.swing.text.BadLocationException;
30
31import jsyntaxpane.DefaultSyntaxKit;
32import jsyntaxpane.Token;
33import cuchaz.enigma.ClassFile;
34import cuchaz.enigma.analysis.SourceIndex;
35
36public class Gui
37{
38 private static final String Name = "Enigma";
39
40 // controls
41 private JFrame m_frame;
42 private JList<ClassFile> m_obfClasses;
43 private JList<ClassFile> m_deobfClasses;
44 private JEditorPane m_editor;
45
46 // handlers
47 private ClassSelectionHandler m_classSelectionHandler;
48
49 private BoxHighlightPainter m_highlightPainter;
50
51 public Gui( )
52 {
53 // init frame
54 m_frame = new JFrame( Name );
55 final Container pane = m_frame.getContentPane();
56 pane.setLayout( new BorderLayout() );
57
58 // init obfuscated classes list
59 m_obfClasses = new JList<ClassFile>();
60 m_obfClasses.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
61 m_obfClasses.setLayoutOrientation( JList.VERTICAL );
62 m_obfClasses.setCellRenderer( new ObfuscatedClassListCellRenderer() );
63 m_obfClasses.addMouseListener( new MouseAdapter()
64 {
65 public void mouseClicked( MouseEvent event )
66 {
67 if( event.getClickCount() == 2 )
68 {
69 if( m_classSelectionHandler != null )
70 {
71 ClassFile selected = m_obfClasses.getSelectedValue();
72 if( selected != null )
73 {
74 m_classSelectionHandler.classSelected( selected );
75 }
76 }
77 }
78 }
79 } );
80 JScrollPane obfScroller = new JScrollPane( m_obfClasses );
81 JPanel obfPanel = new JPanel();
82 obfPanel.setLayout( new BorderLayout() );
83 obfPanel.add( new JLabel( "Obfuscated Classes" ), BorderLayout.NORTH );
84 obfPanel.add( obfScroller, BorderLayout.CENTER );
85
86 // init deobfuscated classes list
87 m_deobfClasses = new JList<ClassFile>();
88 m_obfClasses.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
89 m_obfClasses.setLayoutOrientation( JList.VERTICAL );
90 JScrollPane deobfScroller = new JScrollPane( m_deobfClasses );
91 JPanel deobfPanel = new JPanel();
92 deobfPanel.setLayout( new BorderLayout() );
93 deobfPanel.add( new JLabel( "De-obfuscated Classes" ), BorderLayout.NORTH );
94 deobfPanel.add( deobfScroller, BorderLayout.CENTER );
95
96 // init editor
97 DefaultSyntaxKit.initKit();
98 m_editor = new JEditorPane();
99 m_editor.setEditable( false );
100 JScrollPane sourceScroller = new JScrollPane( m_editor );
101 m_editor.setContentType( "text/java" );
102
103 // layout controls
104 JSplitPane splitLeft = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, obfPanel, deobfPanel );
105 JSplitPane splitMain = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, splitLeft, sourceScroller );
106 pane.add( splitMain, BorderLayout.CENTER );
107
108 // show the frame
109 pane.doLayout();
110 m_frame.setSize( 800, 600 );
111 m_frame.setVisible( true );
112 m_frame.setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE );
113
114 // init handlers
115 m_classSelectionHandler = null;
116
117 m_highlightPainter = new BoxHighlightPainter();
118 }
119
120 public void setTitle( String title )
121 {
122 m_frame.setTitle( Name + " - " + title );
123 }
124
125 public void setObfClasses( List<ClassFile> classes )
126 {
127 m_obfClasses.setListData( new Vector<ClassFile>( classes ) );
128 }
129
130 public void setSource( String source )
131 {
132 setSource( source, null );
133 }
134
135 public void setSource( String source, SourceIndex index )
136 {
137 m_editor.setText( source );
138
139 // remove any old highlighters
140 m_editor.getHighlighter().removeAllHighlights();;
141
142 if( index != null )
143 {
144 // color things based on the index
145 for( Token token : index.tokens() )
146 {
147 try
148 {
149 m_editor.getHighlighter().addHighlight( token.start, token.end(), m_highlightPainter );
150 }
151 catch( BadLocationException ex )
152 {
153 throw new Error( ex );
154 }
155 }
156 }
157 }
158
159 public void setClassSelectionHandler( ClassSelectionHandler val )
160 {
161 m_classSelectionHandler = val;
162 }
163}
diff --git a/src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java b/src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java
new file mode 100644
index 00000000..0badb3b9
--- /dev/null
+++ b/src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java
@@ -0,0 +1,40 @@
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.awt.Component;
14
15import javax.swing.DefaultListCellRenderer;
16import javax.swing.JLabel;
17import javax.swing.JList;
18import javax.swing.ListCellRenderer;
19
20import cuchaz.enigma.ClassFile;
21
22public class ObfuscatedClassListCellRenderer implements ListCellRenderer<ClassFile>
23{
24 private DefaultListCellRenderer m_defaultRenderer;
25
26 public ObfuscatedClassListCellRenderer( )
27 {
28 m_defaultRenderer = new DefaultListCellRenderer();
29 }
30
31 @Override
32 public Component getListCellRendererComponent( JList<? extends ClassFile> list, ClassFile classFile, int index, boolean isSelected, boolean hasFocus )
33 {
34 JLabel label = (JLabel)m_defaultRenderer.getListCellRendererComponent( list, classFile, index, isSelected, hasFocus );
35
36 label.setText( classFile.getName() );
37
38 return label;
39 }
40}
diff --git a/src/cuchaz/enigma/gui/SourceFormatter.java b/src/cuchaz/enigma/gui/SourceFormatter.java
new file mode 100644
index 00000000..f3878405
--- /dev/null
+++ b/src/cuchaz/enigma/gui/SourceFormatter.java
@@ -0,0 +1,62 @@
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}
diff --git a/src/cuchaz/enigma/mapping/ArgumentEntry.java b/src/cuchaz/enigma/mapping/ArgumentEntry.java
new file mode 100644
index 00000000..6c108d7c
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/ArgumentEntry.java
@@ -0,0 +1,88 @@
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.mapping;
12
13import java.io.Serializable;
14
15import cuchaz.enigma.Util;
16
17public class ArgumentEntry implements Serializable
18{
19 private static final long serialVersionUID = 4472172468162696006L;
20
21 private MethodEntry m_methodEntry;
22 private int m_index;
23 private String m_name;
24
25 public ArgumentEntry( MethodEntry methodEntry, int index, String name )
26 {
27 if( methodEntry == null )
28 {
29 throw new IllegalArgumentException( "Method cannot be null!" );
30 }
31 if( index < 0 )
32 {
33 throw new IllegalArgumentException( "Index must be non-negative!" );
34 }
35 if( name == null )
36 {
37 throw new IllegalArgumentException( "Argument name cannot be null!" );
38 }
39
40 m_methodEntry = methodEntry;
41 m_index = index;
42 m_name = name;
43 }
44
45 public MethodEntry getMethodEntry( )
46 {
47 return m_methodEntry;
48 }
49
50 public int getIndex( )
51 {
52 return m_index;
53 }
54
55 public String getName( )
56 {
57 return m_name;
58 }
59
60 @Override
61 public int hashCode( )
62 {
63 return Util.combineHashesOrdered( m_methodEntry, Integer.valueOf( m_index ).hashCode(), m_name.hashCode() );
64 }
65
66 @Override
67 public boolean equals( Object other )
68 {
69 if( other instanceof ArgumentEntry )
70 {
71 return equals( (ArgumentEntry)other );
72 }
73 return false;
74 }
75
76 public boolean equals( ArgumentEntry other )
77 {
78 return m_methodEntry.equals( other.m_methodEntry )
79 && m_index == other.m_index
80 && m_name.equals( other.m_name );
81 }
82
83 @Override
84 public String toString( )
85 {
86 return m_methodEntry.toString() + "(" + m_index + ":" + m_name + ")";
87 }
88}
diff --git a/src/cuchaz/enigma/mapping/ClassEntry.java b/src/cuchaz/enigma/mapping/ClassEntry.java
new file mode 100644
index 00000000..7e78d4c0
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/ClassEntry.java
@@ -0,0 +1,67 @@
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.mapping;
12
13import java.io.Serializable;
14
15
16public class ClassEntry implements Serializable
17{
18 private static final long serialVersionUID = 4235460580973955811L;
19
20 private String m_name;
21
22 public ClassEntry( String className )
23 {
24 if( className == null )
25 {
26 throw new IllegalArgumentException( "Class name cannot be null!" );
27 }
28 if( className.contains( "." ) )
29 {
30 throw new IllegalArgumentException( "Class name must be in JVM format. ie, path/to/package/class$inner" );
31 }
32
33 m_name = className;
34 }
35
36 public String getName( )
37 {
38 return m_name;
39 }
40
41 @Override
42 public int hashCode( )
43 {
44 return m_name.hashCode();
45 }
46
47 @Override
48 public boolean equals( Object other )
49 {
50 if( other instanceof ClassEntry )
51 {
52 return equals( (ClassEntry)other );
53 }
54 return false;
55 }
56
57 public boolean equals( ClassEntry other )
58 {
59 return m_name.equals( other.m_name );
60 }
61
62 @Override
63 public String toString( )
64 {
65 return m_name;
66 }
67}
diff --git a/src/cuchaz/enigma/mapping/FieldEntry.java b/src/cuchaz/enigma/mapping/FieldEntry.java
new file mode 100644
index 00000000..15a93520
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/FieldEntry.java
@@ -0,0 +1,76 @@
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.mapping;
12
13import java.io.Serializable;
14
15import cuchaz.enigma.Util;
16
17public class FieldEntry implements Serializable
18{
19 private static final long serialVersionUID = 3004663582802885451L;
20
21 private ClassEntry m_classEntry;
22 private String m_name;
23
24 public FieldEntry( ClassEntry classEntry, String name )
25 {
26 if( classEntry == null )
27 {
28 throw new IllegalArgumentException( "Class cannot be null!" );
29 }
30 if( name == null )
31 {
32 throw new IllegalArgumentException( "Field name cannot be null!" );
33 }
34
35 m_classEntry = classEntry;
36 m_name = name;
37 }
38
39 public ClassEntry getClassEntry( )
40 {
41 return m_classEntry;
42 }
43
44 public String getName( )
45 {
46 return m_name;
47 }
48
49 @Override
50 public int hashCode( )
51 {
52 return Util.combineHashesOrdered( m_classEntry, m_name );
53 }
54
55 @Override
56 public boolean equals( Object other )
57 {
58 if( other instanceof FieldEntry )
59 {
60 return equals( (FieldEntry)other );
61 }
62 return false;
63 }
64
65 public boolean equals( FieldEntry other )
66 {
67 return m_classEntry.equals( other.m_classEntry )
68 && m_name.equals( other.m_name );
69 }
70
71 @Override
72 public String toString( )
73 {
74 return m_classEntry.getName() + "." + m_name;
75 }
76}
diff --git a/src/cuchaz/enigma/mapping/MethodEntry.java b/src/cuchaz/enigma/mapping/MethodEntry.java
new file mode 100644
index 00000000..e71a4664
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/MethodEntry.java
@@ -0,0 +1,88 @@
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.mapping;
12
13import java.io.Serializable;
14
15import cuchaz.enigma.Util;
16
17public class MethodEntry implements Serializable
18{
19 private static final long serialVersionUID = 4770915224467247458L;
20
21 private ClassEntry m_classEntry;
22 private String m_name;
23 private String m_signature;
24
25 public MethodEntry( ClassEntry classEntry, String name, String signature )
26 {
27 if( classEntry == null )
28 {
29 throw new IllegalArgumentException( "Class cannot be null!" );
30 }
31 if( name == null )
32 {
33 throw new IllegalArgumentException( "Method name cannot be null!" );
34 }
35 if( signature == null )
36 {
37 throw new IllegalArgumentException( "Method signature cannot be null!" );
38 }
39
40 m_classEntry = classEntry;
41 m_name = name;
42 m_signature = signature;
43 }
44
45 public ClassEntry getClassEntry( )
46 {
47 return m_classEntry;
48 }
49
50 public String getName( )
51 {
52 return m_name;
53 }
54
55 public String getSignature( )
56 {
57 return m_signature;
58 }
59
60 @Override
61 public int hashCode( )
62 {
63 return Util.combineHashesOrdered( m_classEntry, m_name, m_signature );
64 }
65
66 @Override
67 public boolean equals( Object other )
68 {
69 if( other instanceof MethodEntry )
70 {
71 return equals( (MethodEntry)other );
72 }
73 return false;
74 }
75
76 public boolean equals( MethodEntry other )
77 {
78 return m_classEntry.equals( other.m_classEntry )
79 && m_name.equals( other.m_name )
80 && m_signature.equals( other.m_signature );
81 }
82
83 @Override
84 public String toString( )
85 {
86 return m_classEntry.getName() + "." + m_name + ":" + m_signature;
87 }
88}