summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar jeff2014-08-13 00:22:12 -0400
committerGravatar jeff2014-08-13 00:22:12 -0400
commitcc74d0e62cfdcf14c5918234f69d587d264807ed (patch)
tree7a11bd6af9b7cd2f28c3dbd43a281b4036464f77 /src
parentgot simple method call graph working! (diff)
downloadenigma-cc74d0e62cfdcf14c5918234f69d587d264807ed.tar.gz
enigma-cc74d0e62cfdcf14c5918234f69d587d264807ed.tar.xz
enigma-cc74d0e62cfdcf14c5918234f69d587d264807ed.zip
added support for field access searches
added proper detection/handling for constructors
Diffstat (limited to 'src')
-rw-r--r--src/cuchaz/enigma/Deobfuscator.java30
-rw-r--r--src/cuchaz/enigma/analysis/FieldCallsTreeNode.java82
-rw-r--r--src/cuchaz/enigma/analysis/JarIndex.java107
-rw-r--r--src/cuchaz/enigma/analysis/MethodCallsTreeNode.java114
-rw-r--r--src/cuchaz/enigma/analysis/SourceIndexVisitor.java5
-rw-r--r--src/cuchaz/enigma/gui/Gui.java60
-rw-r--r--src/cuchaz/enigma/gui/GuiController.java38
-rw-r--r--src/cuchaz/enigma/mapping/ConstructorEntry.java94
-rw-r--r--src/cuchaz/enigma/mapping/Translator.java8
9 files changed, 460 insertions, 78 deletions
diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java
index 33eef08a..770172e3 100644
--- a/src/cuchaz/enigma/Deobfuscator.java
+++ b/src/cuchaz/enigma/Deobfuscator.java
@@ -34,6 +34,7 @@ import cuchaz.enigma.analysis.SourceIndexVisitor;
34import cuchaz.enigma.mapping.ArgumentEntry; 34import cuchaz.enigma.mapping.ArgumentEntry;
35import cuchaz.enigma.mapping.ClassEntry; 35import cuchaz.enigma.mapping.ClassEntry;
36import cuchaz.enigma.mapping.ClassMapping; 36import cuchaz.enigma.mapping.ClassMapping;
37import cuchaz.enigma.mapping.ConstructorEntry;
37import cuchaz.enigma.mapping.Entry; 38import cuchaz.enigma.mapping.Entry;
38import cuchaz.enigma.mapping.FieldEntry; 39import cuchaz.enigma.mapping.FieldEntry;
39import cuchaz.enigma.mapping.Mappings; 40import cuchaz.enigma.mapping.Mappings;
@@ -185,6 +186,10 @@ public class Deobfuscator
185 { 186 {
186 m_renamer.setMethodTreeName( (MethodEntry)obfEntry, newName ); 187 m_renamer.setMethodTreeName( (MethodEntry)obfEntry, newName );
187 } 188 }
189 else if( obfEntry instanceof ConstructorEntry )
190 {
191 m_renamer.setClassName( obfEntry.getClassEntry(), newName );
192 }
188 else if( obfEntry instanceof ArgumentEntry ) 193 else if( obfEntry instanceof ArgumentEntry )
189 { 194 {
190 m_renamer.setArgumentName( (ArgumentEntry)obfEntry, newName ); 195 m_renamer.setArgumentName( (ArgumentEntry)obfEntry, newName );
@@ -210,6 +215,10 @@ public class Deobfuscator
210 { 215 {
211 return translator.translateEntry( (MethodEntry)deobfEntry ); 216 return translator.translateEntry( (MethodEntry)deobfEntry );
212 } 217 }
218 else if( deobfEntry instanceof ConstructorEntry )
219 {
220 return translator.translateEntry( (ConstructorEntry)deobfEntry );
221 }
213 else if( deobfEntry instanceof ArgumentEntry ) 222 else if( deobfEntry instanceof ArgumentEntry )
214 { 223 {
215 return translator.translateEntry( (ArgumentEntry)deobfEntry ); 224 return translator.translateEntry( (ArgumentEntry)deobfEntry );
@@ -235,6 +244,10 @@ public class Deobfuscator
235 { 244 {
236 return translator.translateEntry( (MethodEntry)obfEntry ); 245 return translator.translateEntry( (MethodEntry)obfEntry );
237 } 246 }
247 else if( obfEntry instanceof ConstructorEntry )
248 {
249 return translator.translateEntry( (ConstructorEntry)obfEntry );
250 }
238 else if( obfEntry instanceof ArgumentEntry ) 251 else if( obfEntry instanceof ArgumentEntry )
239 { 252 {
240 return translator.translateEntry( (ArgumentEntry)obfEntry ); 253 return translator.translateEntry( (ArgumentEntry)obfEntry );
@@ -263,6 +276,11 @@ public class Deobfuscator
263 String deobfName = translator.translate( (MethodEntry)obfEntry ); 276 String deobfName = translator.translate( (MethodEntry)obfEntry );
264 return deobfName != null && !deobfName.equals( obfEntry.getName() ); 277 return deobfName != null && !deobfName.equals( obfEntry.getName() );
265 } 278 }
279 else if( obfEntry instanceof ConstructorEntry )
280 {
281 String deobfName = translator.translate( obfEntry.getClassEntry() );
282 return deobfName != null && !deobfName.equals( obfEntry.getClassName() );
283 }
266 else if( obfEntry instanceof ArgumentEntry ) 284 else if( obfEntry instanceof ArgumentEntry )
267 { 285 {
268 return translator.translate( (ArgumentEntry)obfEntry ) != null; 286 return translator.translate( (ArgumentEntry)obfEntry ) != null;
@@ -282,16 +300,20 @@ public class Deobfuscator
282 } 300 }
283 else if( obfEntry instanceof FieldEntry ) 301 else if( obfEntry instanceof FieldEntry )
284 { 302 {
285 return m_jarIndex.getObfClassNames().contains( ((FieldEntry)obfEntry).getClassName() ); 303 return m_jarIndex.getObfClassNames().contains( obfEntry.getClassName() );
286 } 304 }
287 else if( obfEntry instanceof MethodEntry ) 305 else if( obfEntry instanceof MethodEntry )
288 { 306 {
289 return m_jarIndex.getObfClassNames().contains( ((MethodEntry)obfEntry).getClassName() ); 307 return m_jarIndex.getObfClassNames().contains( obfEntry.getClassName() );
308 }
309 else if( obfEntry instanceof ConstructorEntry )
310 {
311 return m_jarIndex.getObfClassNames().contains( obfEntry.getClassName() );
290 } 312 }
291 else if( obfEntry instanceof ArgumentEntry ) 313 else if( obfEntry instanceof ArgumentEntry )
292 { 314 {
293 // arguments only appear in method delcarations 315 // arguments only appear in method declarations
294 // since we only show declrations for obf classes, these are always obfuscated 316 // since we only show declarations for obf classes, these are always obfuscated
295 return true; 317 return true;
296 } 318 }
297 319
diff --git a/src/cuchaz/enigma/analysis/FieldCallsTreeNode.java b/src/cuchaz/enigma/analysis/FieldCallsTreeNode.java
new file mode 100644
index 00000000..0427b3be
--- /dev/null
+++ b/src/cuchaz/enigma/analysis/FieldCallsTreeNode.java
@@ -0,0 +1,82 @@
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 javax.swing.tree.DefaultMutableTreeNode;
14
15import cuchaz.enigma.mapping.ConstructorEntry;
16import cuchaz.enigma.mapping.Entry;
17import cuchaz.enigma.mapping.FieldEntry;
18import cuchaz.enigma.mapping.MethodEntry;
19import cuchaz.enigma.mapping.Translator;
20
21public class FieldCallsTreeNode extends DefaultMutableTreeNode
22{
23 private static final long serialVersionUID = -7934108091928699835L;
24
25 private Translator m_deobfuscatingTranslator;
26 private FieldEntry m_entry;
27
28 public FieldCallsTreeNode( Translator deobfuscatingTranslator, FieldEntry fieldEntry )
29 {
30 m_deobfuscatingTranslator = deobfuscatingTranslator;
31 m_entry = fieldEntry;
32 }
33
34 public FieldEntry getFieldEntry( )
35 {
36 return m_entry;
37 }
38
39 @Override
40 public String toString( )
41 {
42 String className = m_deobfuscatingTranslator.translateClass( m_entry.getClassName() );
43 if( className == null )
44 {
45 className = m_entry.getClassName();
46 }
47
48 String targetName = m_deobfuscatingTranslator.translate( m_entry );
49 if( targetName == null )
50 {
51 targetName = m_entry.getName();
52 }
53 return className + "." + targetName;
54 }
55
56 public void load( JarIndex index, boolean recurse )
57 {
58 // get all the child nodes
59 for( Entry entry : index.getFieldCallers( m_entry ) )
60 {
61 if( entry instanceof MethodEntry )
62 {
63 add( new MethodCallsTreeNode( m_deobfuscatingTranslator, (MethodEntry)entry ) );
64 }
65 else if( entry instanceof ConstructorEntry )
66 {
67 add( new MethodCallsTreeNode( m_deobfuscatingTranslator, (ConstructorEntry)entry ) );
68 }
69 }
70
71 if( recurse && children != null )
72 {
73 for( Object node : children )
74 {
75 if( node instanceof MethodCallsTreeNode )
76 {
77 ((MethodCallsTreeNode)node).load( index, true );
78 }
79 }
80 }
81 }
82}
diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java
index 06b01736..96bddc17 100644
--- a/src/cuchaz/enigma/analysis/JarIndex.java
+++ b/src/cuchaz/enigma/analysis/JarIndex.java
@@ -27,17 +27,26 @@ import javassist.CannotCompileException;
27import javassist.ClassPool; 27import javassist.ClassPool;
28import javassist.CtBehavior; 28import javassist.CtBehavior;
29import javassist.CtClass; 29import javassist.CtClass;
30import javassist.CtConstructor;
31import javassist.CtMethod;
30import javassist.NotFoundException; 32import javassist.NotFoundException;
31import javassist.bytecode.Descriptor; 33import javassist.bytecode.Descriptor;
34import javassist.expr.ConstructorCall;
32import javassist.expr.ExprEditor; 35import javassist.expr.ExprEditor;
36import javassist.expr.FieldAccess;
33import javassist.expr.MethodCall; 37import javassist.expr.MethodCall;
38import javassist.expr.NewExpr;
34 39
35import com.google.common.collect.HashMultimap; 40import com.google.common.collect.HashMultimap;
41import com.google.common.collect.Lists;
36import com.google.common.collect.Multimap; 42import com.google.common.collect.Multimap;
37import com.google.common.collect.Sets; 43import com.google.common.collect.Sets;
38 44
39import cuchaz.enigma.Constants; 45import cuchaz.enigma.Constants;
40import cuchaz.enigma.mapping.ClassEntry; 46import cuchaz.enigma.mapping.ClassEntry;
47import cuchaz.enigma.mapping.ConstructorEntry;
48import cuchaz.enigma.mapping.Entry;
49import cuchaz.enigma.mapping.FieldEntry;
41import cuchaz.enigma.mapping.MethodEntry; 50import cuchaz.enigma.mapping.MethodEntry;
42import cuchaz.enigma.mapping.Translator; 51import cuchaz.enigma.mapping.Translator;
43 52
@@ -46,7 +55,8 @@ public class JarIndex
46 private Set<String> m_obfClassNames; 55 private Set<String> m_obfClassNames;
47 private Ancestries m_ancestries; 56 private Ancestries m_ancestries;
48 private Multimap<String,MethodEntry> m_methodImplementations; 57 private Multimap<String,MethodEntry> m_methodImplementations;
49 private Multimap<MethodEntry,MethodEntry> m_methodCalls; 58 private Multimap<Entry,Entry> m_methodCalls;
59 private Multimap<FieldEntry,Entry> m_fieldCalls;
50 60
51 public JarIndex( JarFile jar ) 61 public JarIndex( JarFile jar )
52 { 62 {
@@ -54,6 +64,7 @@ public class JarIndex
54 m_ancestries = new Ancestries(); 64 m_ancestries = new Ancestries();
55 m_methodImplementations = HashMultimap.create(); 65 m_methodImplementations = HashMultimap.create();
56 m_methodCalls = HashMultimap.create(); 66 m_methodCalls = HashMultimap.create();
67 m_fieldCalls = HashMultimap.create();
57 68
58 // read the class names 69 // read the class names
59 Enumeration<JarEntry> enumeration = jar.entries(); 70 Enumeration<JarEntry> enumeration = jar.entries();
@@ -133,14 +144,30 @@ public class JarIndex
133 { 144 {
134 // get the method entry 145 // get the method entry
135 String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() ); 146 String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() );
136 final MethodEntry methodEntry = new MethodEntry( 147 final Entry thisEntry;
137 new ClassEntry( className ), 148 if( behavior instanceof CtMethod )
138 behavior.getName(), 149 {
139 behavior.getSignature() 150 MethodEntry methodEntry = new MethodEntry(
140 ); 151 new ClassEntry( className ),
141 152 behavior.getName(),
142 // index implementation 153 behavior.getSignature()
143 m_methodImplementations.put( className, methodEntry ); 154 );
155 thisEntry = methodEntry;
156
157 // index implementation
158 m_methodImplementations.put( className, methodEntry );
159 }
160 else if( behavior instanceof CtConstructor )
161 {
162 thisEntry = new ConstructorEntry(
163 new ClassEntry( className ),
164 behavior.getSignature()
165 );
166 }
167 else
168 {
169 throw new IllegalArgumentException( "behavior must be a method or a constructor!" );
170 }
144 171
145 // index method calls 172 // index method calls
146 try 173 try
@@ -150,20 +177,53 @@ public class JarIndex
150 @Override 177 @Override
151 public void edit( MethodCall call ) 178 public void edit( MethodCall call )
152 { 179 {
153 // is this a jar class?
154 String className = Descriptor.toJvmName( call.getClassName() ); 180 String className = Descriptor.toJvmName( call.getClassName() );
155 if( !m_obfClassNames.contains( className ) )
156 {
157 return;
158 }
159
160 // make entry for the called method
161 MethodEntry calledMethodEntry = new MethodEntry( 181 MethodEntry calledMethodEntry = new MethodEntry(
162 new ClassEntry( className ), 182 new ClassEntry( className ),
163 call.getMethodName(), 183 call.getMethodName(),
164 call.getSignature() 184 call.getSignature()
165 ); 185 );
166 m_methodCalls.put( calledMethodEntry, methodEntry ); 186 m_methodCalls.put( calledMethodEntry, thisEntry );
187 }
188
189 @Override
190 public void edit( FieldAccess call )
191 {
192 String className = Descriptor.toJvmName( call.getClassName() );
193 FieldEntry calledFieldEntry = new FieldEntry(
194 new ClassEntry( className ),
195 call.getFieldName()
196 );
197 m_fieldCalls.put( calledFieldEntry, thisEntry );
198 }
199
200 @Override
201 public void edit( ConstructorCall call )
202 {
203 String className = Descriptor.toJvmName( call.getClassName() );
204 ConstructorEntry calledConstructorEntry = new ConstructorEntry(
205 new ClassEntry( className ),
206 call.getSignature()
207 );
208 m_methodCalls.put( calledConstructorEntry, thisEntry );
209 }
210
211 @Override
212 public void edit( NewExpr call )
213 {
214 String className = Descriptor.toJvmName( call.getClassName() );
215 ConstructorEntry calledConstructorEntry = new ConstructorEntry(
216 new ClassEntry( className ),
217 call.getSignature()
218 );
219
220 // TEMP
221 if( className.equals( "bgw" ) )
222 {
223 System.out.println( calledConstructorEntry + " called by " + thisEntry );
224 }
225
226 m_methodCalls.put( calledConstructorEntry, thisEntry );
167 } 227 }
168 } ); 228 } );
169 } 229 }
@@ -202,7 +262,9 @@ public class JarIndex
202 public ClassInheritanceTreeNode getClassInheritance( Translator deobfuscatingTranslator, ClassEntry obfClassEntry ) 262 public ClassInheritanceTreeNode getClassInheritance( Translator deobfuscatingTranslator, ClassEntry obfClassEntry )
203 { 263 {
204 // get the root node 264 // get the root node
205 List<String> ancestry = m_ancestries.getAncestry( obfClassEntry.getName() ); 265 List<String> ancestry = Lists.newArrayList();
266 ancestry.add( obfClassEntry.getName() );
267 ancestry.addAll( m_ancestries.getAncestry( obfClassEntry.getName() ) );
206 ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode( deobfuscatingTranslator, ancestry.get( ancestry.size() - 1 ) ); 268 ClassInheritanceTreeNode rootNode = new ClassInheritanceTreeNode( deobfuscatingTranslator, ancestry.get( ancestry.size() - 1 ) );
207 269
208 // expand all children recursively 270 // expand all children recursively
@@ -241,9 +303,14 @@ public class JarIndex
241 return rootNode; 303 return rootNode;
242 } 304 }
243 305
244 public Collection<MethodEntry> getMethodCallers( MethodEntry methodEntry ) 306 public Collection<Entry> getFieldCallers( FieldEntry fieldEntry )
307 {
308 return m_fieldCalls.get( fieldEntry );
309 }
310
311 public Collection<Entry> getMethodCallers( Entry entry )
245 { 312 {
246 return m_methodCalls.get( methodEntry ); 313 return m_methodCalls.get( entry );
247 } 314 }
248 315
249 private String getMethodKey( String name, String signature ) 316 private String getMethodKey( String name, String signature )
diff --git a/src/cuchaz/enigma/analysis/MethodCallsTreeNode.java b/src/cuchaz/enigma/analysis/MethodCallsTreeNode.java
index dedfb2e7..b5cf4c33 100644
--- a/src/cuchaz/enigma/analysis/MethodCallsTreeNode.java
+++ b/src/cuchaz/enigma/analysis/MethodCallsTreeNode.java
@@ -10,12 +10,15 @@
10 ******************************************************************************/ 10 ******************************************************************************/
11package cuchaz.enigma.analysis; 11package cuchaz.enigma.analysis;
12 12
13import java.util.List; 13import java.util.Set;
14 14
15import javax.swing.tree.DefaultMutableTreeNode; 15import javax.swing.tree.DefaultMutableTreeNode;
16import javax.swing.tree.TreeNode;
16 17
17import com.google.common.collect.Lists; 18import com.google.common.collect.Sets;
18 19
20import cuchaz.enigma.mapping.ConstructorEntry;
21import cuchaz.enigma.mapping.Entry;
19import cuchaz.enigma.mapping.MethodEntry; 22import cuchaz.enigma.mapping.MethodEntry;
20import cuchaz.enigma.mapping.Translator; 23import cuchaz.enigma.mapping.Translator;
21 24
@@ -24,72 +27,117 @@ public class MethodCallsTreeNode extends DefaultMutableTreeNode
24 private static final long serialVersionUID = -3658163700783307520L; 27 private static final long serialVersionUID = -3658163700783307520L;
25 28
26 private Translator m_deobfuscatingTranslator; 29 private Translator m_deobfuscatingTranslator;
27 private MethodEntry m_entry; 30 private MethodEntry m_methodEntry;
31 private ConstructorEntry m_constructorEntry;
28 32
29 public MethodCallsTreeNode( Translator deobfuscatingTranslator, MethodEntry entry ) 33 public MethodCallsTreeNode( Translator deobfuscatingTranslator, MethodEntry entry )
30 { 34 {
31 m_deobfuscatingTranslator = deobfuscatingTranslator; 35 m_deobfuscatingTranslator = deobfuscatingTranslator;
32 m_entry = entry; 36 m_methodEntry = entry;
37 m_constructorEntry = null;
38 }
39
40 public MethodCallsTreeNode( Translator deobfuscatingTranslator, ConstructorEntry entry )
41 {
42 m_deobfuscatingTranslator = deobfuscatingTranslator;
43 m_methodEntry = null;
44 m_constructorEntry = entry;
33 } 45 }
34 46
35 public MethodEntry getMethodEntry( ) 47 public MethodEntry getMethodEntry( )
36 { 48 {
37 return m_entry; 49 return m_methodEntry;
38 } 50 }
39 51
40 public String getDeobfClassName( ) 52 public ConstructorEntry getConstructorEntry( )
41 { 53 {
42 return m_deobfuscatingTranslator.translateClass( m_entry.getClassName() ); 54 return m_constructorEntry;
43 } 55 }
44 56
45 public String getDeobfMethodName( ) 57 public Entry getEntry( )
46 { 58 {
47 return m_deobfuscatingTranslator.translate( m_entry ); 59 if( m_methodEntry != null )
60 {
61 return m_methodEntry;
62 }
63 else if( m_constructorEntry != null )
64 {
65 return m_constructorEntry;
66 }
67 throw new Error( "Illegal state!" );
48 } 68 }
49 69
50 @Override 70 @Override
51 public String toString( ) 71 public String toString( )
52 { 72 {
53 String className = getDeobfClassName(); 73 if( m_methodEntry != null )
54 if( className == null )
55 { 74 {
56 className = m_entry.getClassName(); 75 String className = m_deobfuscatingTranslator.translateClass( m_methodEntry.getClassName() );
76 if( className == null )
77 {
78 className = m_methodEntry.getClassName();
79 }
80
81 String methodName = m_deobfuscatingTranslator.translate( m_methodEntry );
82 if( methodName == null )
83 {
84 methodName = m_methodEntry.getName();
85 }
86 return className + "." + methodName + "()";
57 } 87 }
58 88 else if( m_constructorEntry != null )
59 String methodName = getDeobfMethodName();
60 if( methodName == null )
61 { 89 {
62 methodName = m_entry.getName(); 90 String className = m_deobfuscatingTranslator.translateClass( m_constructorEntry.getClassName() );
91 if( className == null )
92 {
93 className = m_constructorEntry.getClassName();
94 }
95 return className + "()";
63 } 96 }
64 return className + "." + methodName + "()"; 97 throw new Error( "Illegal state!" );
65 } 98 }
66 99
67 public void load( JarIndex index, boolean recurse ) 100 public void load( JarIndex index, boolean recurse )
68 { 101 {
69 // get all the child nodes 102 // get all the child nodes
70 List<MethodCallsTreeNode> nodes = Lists.newArrayList(); 103 for( Entry entry : index.getMethodCallers( getEntry() ) )
71 for( MethodEntry entry : index.getMethodCallers( m_entry ) )
72 { 104 {
73 nodes.add( new MethodCallsTreeNode( m_deobfuscatingTranslator, entry ) ); 105 if( entry instanceof MethodEntry )
74 } 106 {
75 107 add( new MethodCallsTreeNode( m_deobfuscatingTranslator, (MethodEntry)entry ) );
76 // add them to this node 108 }
77 for( MethodCallsTreeNode node : nodes ) 109 else if( entry instanceof ConstructorEntry )
78 { 110 {
79 this.add( node ); 111 add( new MethodCallsTreeNode( m_deobfuscatingTranslator, (ConstructorEntry)entry ) );
112 }
80 } 113 }
81 114
82 if( recurse ) 115 if( recurse && children != null )
83 { 116 {
84 for( MethodCallsTreeNode node : nodes ) 117 for( Object child : children )
85 { 118 {
86 // don't recurse into self 119 if( child instanceof MethodCallsTreeNode )
87 if( node.getMethodEntry().equals( m_entry ) )
88 { 120 {
89 continue; 121 MethodCallsTreeNode node = (MethodCallsTreeNode)child;
122
123 // don't recurse into ancestor
124 Set<Entry> ancestors = Sets.newHashSet();
125 TreeNode n = (TreeNode)node;
126 while( n.getParent() != null )
127 {
128 n = n.getParent();
129 if( n instanceof MethodCallsTreeNode )
130 {
131 ancestors.add( ((MethodCallsTreeNode)n).getEntry() );
132 }
133 }
134 if( ancestors.contains( node.getEntry() ) )
135 {
136 continue;
137 }
138
139 node.load( index, true );
90 } 140 }
91
92 node.load( index, true );
93 } 141 }
94 } 142 }
95 } 143 }
diff --git a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java
index 0ba5996c..6c14ee99 100644
--- a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java
+++ b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java
@@ -93,6 +93,7 @@ import com.strobel.decompiler.patterns.Pattern;
93 93
94import cuchaz.enigma.mapping.ArgumentEntry; 94import cuchaz.enigma.mapping.ArgumentEntry;
95import cuchaz.enigma.mapping.ClassEntry; 95import cuchaz.enigma.mapping.ClassEntry;
96import cuchaz.enigma.mapping.ConstructorEntry;
96import cuchaz.enigma.mapping.FieldEntry; 97import cuchaz.enigma.mapping.FieldEntry;
97import cuchaz.enigma.mapping.MethodEntry; 98import cuchaz.enigma.mapping.MethodEntry;
98 99
@@ -158,7 +159,9 @@ public class SourceIndexVisitor implements IAstVisitor<SourceIndex, Void>
158 public Void visitConstructorDeclaration( ConstructorDeclaration node, SourceIndex index ) 159 public Void visitConstructorDeclaration( ConstructorDeclaration node, SourceIndex index )
159 { 160 {
160 MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION ); 161 MethodDefinition def = node.getUserData( Keys.METHOD_DEFINITION );
161 index.add( node.getNameToken(), new ClassEntry( def.getDeclaringType().getInternalName() ) ); 162 ClassEntry classEntry = new ClassEntry( def.getDeclaringType().getInternalName() );
163 ConstructorEntry constructorEntry = new ConstructorEntry( classEntry, def.getSignature() );
164 index.addDeclaration( node.getNameToken(), constructorEntry );
162 165
163 return recurse( node, index ); 166 return recurse( node, index );
164 } 167 }
diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java
index 072fb3a5..1d2d3ab1 100644
--- a/src/cuchaz/enigma/gui/Gui.java
+++ b/src/cuchaz/enigma/gui/Gui.java
@@ -67,11 +67,13 @@ import com.google.common.collect.Lists;
67 67
68import cuchaz.enigma.Constants; 68import cuchaz.enigma.Constants;
69import cuchaz.enigma.analysis.ClassInheritanceTreeNode; 69import cuchaz.enigma.analysis.ClassInheritanceTreeNode;
70import cuchaz.enigma.analysis.FieldCallsTreeNode;
70import cuchaz.enigma.analysis.MethodCallsTreeNode; 71import cuchaz.enigma.analysis.MethodCallsTreeNode;
71import cuchaz.enigma.analysis.MethodInheritanceTreeNode; 72import cuchaz.enigma.analysis.MethodInheritanceTreeNode;
72import cuchaz.enigma.analysis.Token; 73import cuchaz.enigma.analysis.Token;
73import cuchaz.enigma.mapping.ArgumentEntry; 74import cuchaz.enigma.mapping.ArgumentEntry;
74import cuchaz.enigma.mapping.ClassEntry; 75import cuchaz.enigma.mapping.ClassEntry;
76import cuchaz.enigma.mapping.ConstructorEntry;
75import cuchaz.enigma.mapping.Entry; 77import cuchaz.enigma.mapping.Entry;
76import cuchaz.enigma.mapping.EntryPair; 78import cuchaz.enigma.mapping.EntryPair;
77import cuchaz.enigma.mapping.FieldEntry; 79import cuchaz.enigma.mapping.FieldEntry;
@@ -419,7 +421,7 @@ public class Gui
419 Object node = path.getLastPathComponent(); 421 Object node = path.getLastPathComponent();
420 if( node instanceof MethodCallsTreeNode ) 422 if( node instanceof MethodCallsTreeNode )
421 { 423 {
422 m_controller.openEntry( ((MethodCallsTreeNode)node).getMethodEntry() ); 424 m_controller.openEntry( ((MethodCallsTreeNode)node).getEntry() );
423 } 425 }
424 } 426 }
425 } 427 }
@@ -438,7 +440,7 @@ public class Gui
438 m_tabs = new JTabbedPane(); 440 m_tabs = new JTabbedPane();
439 m_tabs.setPreferredSize( new Dimension( 250, 0 ) ); 441 m_tabs.setPreferredSize( new Dimension( 250, 0 ) );
440 m_tabs.addTab( "Inheritance", inheritancePanel ); 442 m_tabs.addTab( "Inheritance", inheritancePanel );
441 m_tabs.addTab( "Method Calls", callPanel ); 443 m_tabs.addTab( "Call Graph", callPanel );
442 JSplitPane splitRight = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, m_tabs ); 444 JSplitPane splitRight = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, m_tabs );
443 splitRight.setResizeWeight( 1 ); // let the left side take all the slack 445 splitRight.setResizeWeight( 1 ); // let the left side take all the slack
444 splitRight.resetToPreferredSizes(); 446 splitRight.resetToPreferredSizes();
@@ -770,6 +772,10 @@ public class Gui
770 { 772 {
771 showMethodEntryPair( (EntryPair<? extends MethodEntry>)pair ); 773 showMethodEntryPair( (EntryPair<? extends MethodEntry>)pair );
772 } 774 }
775 else if( pair.deobf instanceof ConstructorEntry )
776 {
777 showConstructorEntryPair( (EntryPair<? extends ConstructorEntry>)pair );
778 }
773 else if( pair.deobf instanceof ArgumentEntry ) 779 else if( pair.deobf instanceof ArgumentEntry )
774 { 780 {
775 showArgumentEntryPair( (EntryPair<? extends ArgumentEntry>)pair ); 781 showArgumentEntryPair( (EntryPair<? extends ArgumentEntry>)pair );
@@ -800,6 +806,12 @@ public class Gui
800 addNameValue( m_infoPanel, "Signature", pair.deobf.getSignature() ); 806 addNameValue( m_infoPanel, "Signature", pair.deobf.getSignature() );
801 } 807 }
802 808
809 private void showConstructorEntryPair( EntryPair<? extends ConstructorEntry> pair )
810 {
811 addNameValue( m_infoPanel, "Constructor", pair.deobf.getClassEntry().getName() );
812 addNameValue( m_infoPanel, "Signature", pair.deobf.getSignature() );
813 }
814
803 private void showArgumentEntryPair( EntryPair<? extends ArgumentEntry> pair ) 815 private void showArgumentEntryPair( EntryPair<? extends ArgumentEntry> pair )
804 { 816 {
805 addNameValue( m_infoPanel, "Argument", pair.deobf.getName() ); 817 addNameValue( m_infoPanel, "Argument", pair.deobf.getName() );
@@ -815,7 +827,7 @@ public class Gui
815 container.add( panel ); 827 container.add( panel );
816 828
817 JLabel label = new JLabel( name + ":", JLabel.RIGHT ); 829 JLabel label = new JLabel( name + ":", JLabel.RIGHT );
818 label.setPreferredSize( new Dimension( 80, label.getPreferredSize().height ) ); 830 label.setPreferredSize( new Dimension( 100, label.getPreferredSize().height ) );
819 panel.add( label ); 831 panel.add( label );
820 832
821 panel.add( unboldLabel( new JLabel( value, JLabel.LEFT ) ) ); 833 panel.add( unboldLabel( new JLabel( value, JLabel.LEFT ) ) );
@@ -824,23 +836,27 @@ public class Gui
824 private void onCaretMove( int pos ) 836 private void onCaretMove( int pos )
825 { 837 {
826 Token token = m_controller.getToken( pos ); 838 Token token = m_controller.getToken( pos );
827 m_renameMenu.setEnabled( token != null ); 839 boolean isToken = token != null;
828 if( token == null )
829 {
830 clearEntryPair();
831 return;
832 }
833 840
834 m_selectedEntryPair = m_controller.getEntryPair( token ); 841 m_selectedEntryPair = m_controller.getEntryPair( token );
835 boolean isClassEntry = m_selectedEntryPair.obf instanceof ClassEntry; 842 boolean isClassEntry = isToken && m_selectedEntryPair.obf instanceof ClassEntry;
836 boolean isFieldEntry = m_selectedEntryPair.obf instanceof FieldEntry; 843 boolean isFieldEntry = isToken && m_selectedEntryPair.obf instanceof FieldEntry;
837 boolean isMethodEntry = m_selectedEntryPair.obf instanceof MethodEntry; 844 boolean isMethodEntry = isToken && m_selectedEntryPair.obf instanceof MethodEntry;
845 boolean isConstructorEntry = isToken && m_selectedEntryPair.obf instanceof ConstructorEntry;
838 846
839 showEntryPair( m_selectedEntryPair ); 847 if( isToken )
848 {
849 showEntryPair( m_selectedEntryPair );
850 }
851 else
852 {
853 clearEntryPair();
854 }
840 855
841 m_showInheritanceMenu.setEnabled( isClassEntry || isMethodEntry ); 856 m_renameMenu.setEnabled( isToken );
842 m_showCallsMenu.setEnabled( isMethodEntry ); 857 m_showInheritanceMenu.setEnabled( isClassEntry || isMethodEntry || isConstructorEntry );
843 m_openEntryMenu.setEnabled( isClassEntry || isFieldEntry || isMethodEntry ); 858 m_showCallsMenu.setEnabled( isFieldEntry || isMethodEntry || isConstructorEntry );
859 m_openEntryMenu.setEnabled( isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry );
844 m_openPreviousMenu.setEnabled( m_controller.hasPreviousEntry() ); 860 m_openPreviousMenu.setEnabled( m_controller.hasPreviousEntry() );
845 } 861 }
846 862
@@ -945,11 +961,21 @@ public class Gui
945 return; 961 return;
946 } 962 }
947 963
948 if( m_selectedEntryPair.obf instanceof MethodEntry ) 964 if( m_selectedEntryPair.obf instanceof FieldEntry )
965 {
966 FieldCallsTreeNode node = m_controller.getFieldCalls( (FieldEntry)m_selectedEntryPair.obf );
967 m_callsTree.setModel( new DefaultTreeModel( node ) );
968 }
969 else if( m_selectedEntryPair.obf instanceof MethodEntry )
949 { 970 {
950 MethodCallsTreeNode node = m_controller.getMethodCalls( (MethodEntry)m_selectedEntryPair.obf ); 971 MethodCallsTreeNode node = m_controller.getMethodCalls( (MethodEntry)m_selectedEntryPair.obf );
951 m_callsTree.setModel( new DefaultTreeModel( node ) ); 972 m_callsTree.setModel( new DefaultTreeModel( node ) );
952 } 973 }
974 else if( m_selectedEntryPair.obf instanceof ConstructorEntry )
975 {
976 MethodCallsTreeNode node = m_controller.getMethodCalls( (ConstructorEntry)m_selectedEntryPair.obf );
977 m_callsTree.setModel( new DefaultTreeModel( node ) );
978 }
953 979
954 m_tabs.setSelectedIndex( 1 ); 980 m_tabs.setSelectedIndex( 1 );
955 redraw(); 981 redraw();
diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java
index b54aeba3..534b0cc5 100644
--- a/src/cuchaz/enigma/gui/GuiController.java
+++ b/src/cuchaz/enigma/gui/GuiController.java
@@ -21,13 +21,16 @@ import com.google.common.collect.Lists;
21 21
22import cuchaz.enigma.Deobfuscator; 22import cuchaz.enigma.Deobfuscator;
23import cuchaz.enigma.analysis.ClassInheritanceTreeNode; 23import cuchaz.enigma.analysis.ClassInheritanceTreeNode;
24import cuchaz.enigma.analysis.FieldCallsTreeNode;
24import cuchaz.enigma.analysis.MethodCallsTreeNode; 25import cuchaz.enigma.analysis.MethodCallsTreeNode;
25import cuchaz.enigma.analysis.MethodInheritanceTreeNode; 26import cuchaz.enigma.analysis.MethodInheritanceTreeNode;
26import cuchaz.enigma.analysis.SourceIndex; 27import cuchaz.enigma.analysis.SourceIndex;
27import cuchaz.enigma.analysis.Token; 28import cuchaz.enigma.analysis.Token;
28import cuchaz.enigma.mapping.ClassEntry; 29import cuchaz.enigma.mapping.ClassEntry;
30import cuchaz.enigma.mapping.ConstructorEntry;
29import cuchaz.enigma.mapping.Entry; 31import cuchaz.enigma.mapping.Entry;
30import cuchaz.enigma.mapping.EntryPair; 32import cuchaz.enigma.mapping.EntryPair;
33import cuchaz.enigma.mapping.FieldEntry;
31import cuchaz.enigma.mapping.MappingsReader; 34import cuchaz.enigma.mapping.MappingsReader;
32import cuchaz.enigma.mapping.MappingsWriter; 35import cuchaz.enigma.mapping.MappingsWriter;
33import cuchaz.enigma.mapping.MethodEntry; 36import cuchaz.enigma.mapping.MethodEntry;
@@ -118,6 +121,10 @@ public class GuiController
118 } 121 }
119 122
120 Entry deobfEntry = m_index.getEntry( token ); 123 Entry deobfEntry = m_index.getEntry( token );
124 if( deobfEntry == null )
125 {
126 return null;
127 }
121 return new EntryPair<Entry>( m_deobfuscator.obfuscateEntry( deobfEntry ), deobfEntry ); 128 return new EntryPair<Entry>( m_deobfuscator.obfuscateEntry( deobfEntry ), deobfEntry );
122 } 129 }
123 130
@@ -149,16 +156,41 @@ public class GuiController
149 return MethodInheritanceTreeNode.findNode( rootNode, obfMethodEntry ); 156 return MethodInheritanceTreeNode.findNode( rootNode, obfMethodEntry );
150 } 157 }
151 158
152 public MethodCallsTreeNode getMethodCalls( MethodEntry obfMethodEntry ) 159 public FieldCallsTreeNode getFieldCalls( FieldEntry obfFieldEntry )
153 { 160 {
154 MethodCallsTreeNode rootNode = new MethodCallsTreeNode( 161 FieldCallsTreeNode rootNode = new FieldCallsTreeNode(
155 m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), 162 m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ),
156 obfMethodEntry 163 obfFieldEntry
157 ); 164 );
158 rootNode.load( m_deobfuscator.getJarIndex(), true ); 165 rootNode.load( m_deobfuscator.getJarIndex(), true );
159 return rootNode; 166 return rootNode;
160 } 167 }
161 168
169 public MethodCallsTreeNode getMethodCalls( Entry obfEntry )
170 {
171 MethodCallsTreeNode rootNode;
172 if( obfEntry instanceof MethodEntry )
173 {
174 rootNode = new MethodCallsTreeNode(
175 m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ),
176 (MethodEntry)obfEntry
177 );
178 }
179 else if( obfEntry instanceof ConstructorEntry )
180 {
181 rootNode = new MethodCallsTreeNode(
182 m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ),
183 (ConstructorEntry)obfEntry
184 );
185 }
186 else
187 {
188 throw new IllegalArgumentException( "entry must be a MethodEntry or a ConstructorEntry!" );
189 }
190 rootNode.load( m_deobfuscator.getJarIndex(), true );
191 return rootNode;
192 }
193
162 public void rename( Entry obfEntry, String newName ) 194 public void rename( Entry obfEntry, String newName )
163 { 195 {
164 m_deobfuscator.rename( obfEntry, newName ); 196 m_deobfuscator.rename( obfEntry, newName );
diff --git a/src/cuchaz/enigma/mapping/ConstructorEntry.java b/src/cuchaz/enigma/mapping/ConstructorEntry.java
new file mode 100644
index 00000000..e0fa7cf6
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/ConstructorEntry.java
@@ -0,0 +1,94 @@
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 ConstructorEntry implements Entry, Serializable
18{
19 private static final long serialVersionUID = -868346075317366758L;
20
21 private ClassEntry m_classEntry;
22 private String m_signature;
23
24 public ConstructorEntry( ClassEntry classEntry, String signature )
25 {
26 if( classEntry == null )
27 {
28 throw new IllegalArgumentException( "Class cannot be null!" );
29 }
30 if( signature == null )
31 {
32 throw new IllegalArgumentException( "Method signature cannot be null!" );
33 }
34
35 m_classEntry = classEntry;
36 m_signature = signature;
37 }
38
39 public ConstructorEntry( ConstructorEntry other )
40 {
41 m_classEntry = new ClassEntry( other.m_classEntry );
42 m_signature = other.m_signature;
43 }
44
45 @Override
46 public ClassEntry getClassEntry( )
47 {
48 return m_classEntry;
49 }
50
51 @Override
52 public String getName( )
53 {
54 return m_classEntry.getName();
55 }
56
57 public String getSignature( )
58 {
59 return m_signature;
60 }
61
62 @Override
63 public String getClassName( )
64 {
65 return m_classEntry.getName();
66 }
67
68 @Override
69 public int hashCode( )
70 {
71 return Util.combineHashesOrdered( m_classEntry, m_signature );
72 }
73
74 @Override
75 public boolean equals( Object other )
76 {
77 if( other instanceof ConstructorEntry )
78 {
79 return equals( (ConstructorEntry)other );
80 }
81 return false;
82 }
83
84 public boolean equals( ConstructorEntry other )
85 {
86 return m_classEntry.equals( other.m_classEntry ) && m_signature.equals( other.m_signature );
87 }
88
89 @Override
90 public String toString( )
91 {
92 return m_classEntry.getName() + m_signature;
93 }
94}
diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java
index 02565c94..50433214 100644
--- a/src/cuchaz/enigma/mapping/Translator.java
+++ b/src/cuchaz/enigma/mapping/Translator.java
@@ -135,6 +135,14 @@ public class Translator
135 ); 135 );
136 } 136 }
137 137
138 public ConstructorEntry translateEntry( ConstructorEntry in )
139 {
140 return new ConstructorEntry(
141 translateEntry( in.getClassEntry() ),
142 translateSignature( in.getSignature() )
143 );
144 }
145
138 public String translate( ArgumentEntry in ) 146 public String translate( ArgumentEntry in )
139 { 147 {
140 for( String className : getSelfAndAncestors( in.getClassName() ) ) 148 for( String className : getSelfAndAncestors( in.getClassName() ) )