summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cuchaz/enigma/TranslatingTypeLoader.java5
-rw-r--r--src/cuchaz/enigma/analysis/Ancestries.java89
-rw-r--r--src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java92
-rw-r--r--src/cuchaz/enigma/analysis/JarIndex.java107
-rw-r--r--src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java111
-rw-r--r--src/cuchaz/enigma/gui/Gui.java104
-rw-r--r--src/cuchaz/enigma/gui/GuiController.java25
-rw-r--r--src/cuchaz/enigma/mapping/Renamer.java21
8 files changed, 524 insertions, 30 deletions
diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java
index 83f0baa4..1e0e95a2 100644
--- a/src/cuchaz/enigma/TranslatingTypeLoader.java
+++ b/src/cuchaz/enigma/TranslatingTypeLoader.java
@@ -13,7 +13,6 @@ package cuchaz.enigma;
13import java.io.ByteArrayOutputStream; 13import java.io.ByteArrayOutputStream;
14import java.io.IOException; 14import java.io.IOException;
15import java.io.InputStream; 15import java.io.InputStream;
16import java.util.Arrays;
17import java.util.Map; 16import java.util.Map;
18import java.util.jar.JarEntry; 17import java.util.jar.JarEntry;
19import java.util.jar.JarFile; 18import java.util.jar.JarFile;
@@ -105,12 +104,12 @@ public class TranslatingTypeLoader implements ITypeLoader
105 return null; 104 return null;
106 } 105 }
107 106
108 // DEBUG 107 /* DEBUG
109 if( !Arrays.asList( "java", "org", "io" ).contains( deobfClassName.split( "/" )[0] ) ) 108 if( !Arrays.asList( "java", "org", "io" ).contains( deobfClassName.split( "/" )[0] ) )
110 { 109 {
111 System.out.println( String.format( "Looking for %s (%s)", deobfClassEntry.getName(), obfClassEntry.getName() ) ); 110 System.out.println( String.format( "Looking for %s (%s)", deobfClassEntry.getName(), obfClassEntry.getName() ) );
112 } 111 }
113 // 112 */
114 113
115 // get the jar entry 114 // get the jar entry
116 String classFileName; 115 String classFileName;
diff --git a/src/cuchaz/enigma/analysis/Ancestries.java b/src/cuchaz/enigma/analysis/Ancestries.java
index b9d8cbf4..97241084 100644
--- a/src/cuchaz/enigma/analysis/Ancestries.java
+++ b/src/cuchaz/enigma/analysis/Ancestries.java
@@ -11,24 +11,32 @@
11package cuchaz.enigma.analysis; 11package cuchaz.enigma.analysis;
12 12
13import java.io.Serializable; 13import java.io.Serializable;
14import java.util.AbstractMap;
14import java.util.ArrayList; 15import java.util.ArrayList;
16import java.util.HashSet;
15import java.util.List; 17import java.util.List;
16import java.util.Map; 18import java.util.Map;
19import java.util.Set;
17 20
18import javassist.bytecode.Descriptor; 21import javassist.bytecode.Descriptor;
19 22
23import com.google.common.collect.HashMultimap;
20import com.google.common.collect.Lists; 24import com.google.common.collect.Lists;
21import com.google.common.collect.Maps; 25import com.google.common.collect.Maps;
26import com.google.common.collect.Multimap;
27import com.google.common.collect.Sets;
22 28
23public class Ancestries implements Serializable 29public class Ancestries implements Serializable
24{ 30{
25 private static final long serialVersionUID = 738687982126844179L; 31 private static final long serialVersionUID = 738687982126844179L;
26 32
27 private Map<String,String> m_superclasses; 33 private Map<String,String> m_superclasses;
34 private Multimap<String,String> m_interfaces;
28 35
29 public Ancestries( ) 36 public Ancestries( )
30 { 37 {
31 m_superclasses = Maps.newHashMap(); 38 m_superclasses = Maps.newHashMap();
39 m_interfaces = HashMultimap.create();
32 } 40 }
33 41
34 public void addSuperclass( String className, String superclassName ) 42 public void addSuperclass( String className, String superclassName )
@@ -47,8 +55,25 @@ public class Ancestries implements Serializable
47 } 55 }
48 } 56 }
49 57
58 public void addInterface( String className, String interfaceName )
59 {
60 className = Descriptor.toJvmName( className );
61 interfaceName = Descriptor.toJvmName( interfaceName );
62
63 if( className.equals( interfaceName ) )
64 {
65 throw new IllegalArgumentException( "Class cannot be its own interface! " + className );
66 }
67
68 if( !isJre( className ) && !isJre( interfaceName ) )
69 {
70 m_interfaces.put( className, interfaceName );
71 }
72 }
73
50 public void renameClasses( Map<String,String> renames ) 74 public void renameClasses( Map<String,String> renames )
51 { 75 {
76 // rename superclasses
52 Map<String,String> newSuperclasses = Maps.newHashMap(); 77 Map<String,String> newSuperclasses = Maps.newHashMap();
53 for( Map.Entry<String,String> entry : m_superclasses.entrySet() ) 78 for( Map.Entry<String,String> entry : m_superclasses.entrySet() )
54 { 79 {
@@ -65,6 +90,28 @@ public class Ancestries implements Serializable
65 newSuperclasses.put( subclass, superclass ); 90 newSuperclasses.put( subclass, superclass );
66 } 91 }
67 m_superclasses = newSuperclasses; 92 m_superclasses = newSuperclasses;
93
94 // rename interfaces
95 Set<Map.Entry<String,String>> entriesToAdd = Sets.newHashSet();
96 for( Map.Entry<String,String> entry : m_interfaces.entries() )
97 {
98 String className = renames.get( entry.getKey() );
99 if( className == null )
100 {
101 className = entry.getKey();
102 }
103 String interfaceName = renames.get( entry.getValue() );
104 if( interfaceName == null )
105 {
106 interfaceName = entry.getValue();
107 }
108 entriesToAdd.add( new AbstractMap.SimpleEntry<String,String>( className, interfaceName ) );
109 }
110 m_interfaces.clear();
111 for( Map.Entry<String,String> entry : entriesToAdd )
112 {
113 m_interfaces.put( entry.getKey(), entry.getValue() );
114 }
68 } 115 }
69 116
70 public String getSuperclassName( String className ) 117 public String getSuperclassName( String className )
@@ -86,6 +133,17 @@ public class Ancestries implements Serializable
86 return ancestors; 133 return ancestors;
87 } 134 }
88 135
136 public Set<String> getInterfaces( String className )
137 {
138 Set<String> interfaceNames = new HashSet<String>();
139 interfaceNames.addAll( m_interfaces.get( className ) );
140 for( String ancestor : getAncestry( className ) )
141 {
142 interfaceNames.addAll( m_interfaces.get( ancestor ) );
143 }
144 return interfaceNames;
145 }
146
89 public List<String> getSubclasses( String className ) 147 public List<String> getSubclasses( String className )
90 { 148 {
91 // linear search is fast enough for now 149 // linear search is fast enough for now
@@ -102,6 +160,37 @@ public class Ancestries implements Serializable
102 return subclasses; 160 return subclasses;
103 } 161 }
104 162
163 public Set<String> getImplementingClasses( String targetInterfaceName )
164 {
165 // linear search is fast enough for now
166 Set<String> classNames = Sets.newHashSet();
167 for( Map.Entry<String,String> entry : m_interfaces.entries() )
168 {
169 String className = entry.getKey();
170 String interfaceName = entry.getValue();
171 if( interfaceName.equals( targetInterfaceName ) )
172 {
173 classNames.add( className );
174 collectSubclasses( classNames, className );
175 }
176 }
177 return classNames;
178 }
179
180 public boolean isInterface( String className )
181 {
182 return m_interfaces.containsValue( className );
183 }
184
185 private void collectSubclasses( Set<String> classNames, String className )
186 {
187 for( String subclassName : getSubclasses( className ) )
188 {
189 classNames.add( subclassName );
190 collectSubclasses( classNames, subclassName );
191 }
192 }
193
105 private boolean isJre( String className ) 194 private boolean isJre( String className )
106 { 195 {
107 return className.startsWith( "java/" ) 196 return className.startsWith( "java/" )
diff --git a/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java
new file mode 100644
index 00000000..98648305
--- /dev/null
+++ b/src/cuchaz/enigma/analysis/ClassImplementationsTreeNode.java
@@ -0,0 +1,92 @@
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.List;
14
15import javax.swing.tree.DefaultMutableTreeNode;
16
17import com.google.common.collect.Lists;
18
19import cuchaz.enigma.mapping.ClassEntry;
20import cuchaz.enigma.mapping.MethodEntry;
21import cuchaz.enigma.mapping.Translator;
22
23public class ClassImplementationsTreeNode extends DefaultMutableTreeNode
24{
25 private static final long serialVersionUID = 3112703459157851912L;
26
27 private Translator m_deobfuscatingTranslator;
28 private ClassEntry m_entry;
29
30 public ClassImplementationsTreeNode( Translator deobfuscatingTranslator, ClassEntry entry )
31 {
32 m_deobfuscatingTranslator = deobfuscatingTranslator;
33 m_entry = entry;
34 }
35
36 public ClassEntry getClassEntry( )
37 {
38 return m_entry;
39 }
40
41 public String getDeobfClassName( )
42 {
43 return m_deobfuscatingTranslator.translateClass( m_entry.getClassName() );
44 }
45
46 @Override
47 public String toString( )
48 {
49 String className = getDeobfClassName();
50 if( className == null )
51 {
52 className = m_entry.getClassName();
53 }
54 return className;
55 }
56
57 public void load( Ancestries ancestries )
58 {
59 // get all method implementations
60 List<ClassImplementationsTreeNode> nodes = Lists.newArrayList();
61 for( String implementingClassName : ancestries.getImplementingClasses( m_entry.getClassName() ) )
62 {
63 nodes.add( new ClassImplementationsTreeNode( m_deobfuscatingTranslator, new ClassEntry( implementingClassName ) ) );
64 }
65
66 // add them to this node
67 for( ClassImplementationsTreeNode node : nodes )
68 {
69 this.add( node );
70 }
71 }
72
73 public static ClassImplementationsTreeNode findNode( ClassImplementationsTreeNode node, MethodEntry entry )
74 {
75 // is this the node?
76 if( node.m_entry.equals( entry ) )
77 {
78 return node;
79 }
80
81 // recurse
82 for( int i=0; i<node.getChildCount(); i++ )
83 {
84 ClassImplementationsTreeNode foundNode = findNode( (ClassImplementationsTreeNode)node.getChildAt( i ), entry );
85 if( foundNode != null )
86 {
87 return foundNode;
88 }
89 }
90 return null;
91 }
92}
diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java
index cb7508e1..eaf63528 100644
--- a/src/cuchaz/enigma/analysis/JarIndex.java
+++ b/src/cuchaz/enigma/analysis/JarIndex.java
@@ -93,7 +93,12 @@ public class JarIndex
93 for( CtClass c : JarClassIterator.classes( jar ) ) 93 for( CtClass c : JarClassIterator.classes( jar ) )
94 { 94 {
95 fixClass( c ); 95 fixClass( c );
96 m_ancestries.addSuperclass( c.getName(), c.getClassFile().getSuperclass() ); 96 String className = Descriptor.toJvmName( c.getName() );
97 m_ancestries.addSuperclass( className, Descriptor.toJvmName( c.getClassFile().getSuperclass() ) );
98 for( String interfaceName : c.getClassFile().getInterfaces() )
99 {
100 m_ancestries.addInterface( className, Descriptor.toJvmName( interfaceName ) );
101 }
97 for( CtBehavior behavior : c.getDeclaredBehaviors() ) 102 for( CtBehavior behavior : c.getDeclaredBehaviors() )
98 { 103 {
99 indexBehavior( behavior ); 104 indexBehavior( behavior );
@@ -354,7 +359,6 @@ public class JarIndex
354 } 359 }
355 else if( callerClasses.size() > 1 ) 360 else if( callerClasses.size() > 1 )
356 { 361 {
357 // TEMP
358 System.out.println( "WARNING: Illegal constructor called by more than one class!" + callerClasses ); 362 System.out.println( "WARNING: Illegal constructor called by more than one class!" + callerClasses );
359 } 363 }
360 } 364 }
@@ -542,6 +546,13 @@ public class JarIndex
542 return rootNode; 546 return rootNode;
543 } 547 }
544 548
549 public ClassImplementationsTreeNode getClassImplementations( Translator deobfuscatingTranslator, ClassEntry obfClassEntry )
550 {
551 ClassImplementationsTreeNode node = new ClassImplementationsTreeNode( deobfuscatingTranslator, obfClassEntry );
552 node.load( m_ancestries );
553 return node;
554 }
555
545 public MethodInheritanceTreeNode getMethodInheritance( Translator deobfuscatingTranslator, MethodEntry obfMethodEntry ) 556 public MethodInheritanceTreeNode getMethodInheritance( Translator deobfuscatingTranslator, MethodEntry obfMethodEntry )
546 { 557 {
547 // travel to the ancestor implementation 558 // travel to the ancestor implementation
@@ -577,6 +588,90 @@ public class JarIndex
577 return rootNode; 588 return rootNode;
578 } 589 }
579 590
591 public MethodImplementationsTreeNode getMethodImplementations( Translator deobfuscatingTranslator, MethodEntry obfMethodEntry )
592 {
593 MethodEntry interfaceMethodEntry;
594
595 // is this method on an interface?
596 if( m_ancestries.isInterface( obfMethodEntry.getClassName() ) )
597 {
598 interfaceMethodEntry = obfMethodEntry;
599 }
600 else
601 {
602 // get the interface class
603 List<MethodEntry> methodInterfaces = Lists.newArrayList();
604 for( String interfaceName : m_ancestries.getInterfaces( obfMethodEntry.getClassName() ) )
605 {
606 // is this method defined in this interface?
607 MethodEntry methodInterface = new MethodEntry(
608 new ClassEntry( interfaceName ),
609 obfMethodEntry.getName(),
610 obfMethodEntry.getSignature()
611 );
612 if( isMethodImplemented( methodInterface ) )
613 {
614 methodInterfaces.add( methodInterface );
615 }
616 }
617 if( methodInterfaces.isEmpty() )
618 {
619 return null;
620 }
621 if( methodInterfaces.size() > 1 )
622 {
623 throw new Error( "Too many interfaces define this method! This is not yet supported by Enigma!" );
624 }
625 interfaceMethodEntry = methodInterfaces.get( 0 );
626 }
627
628 MethodImplementationsTreeNode rootNode = new MethodImplementationsTreeNode( deobfuscatingTranslator, interfaceMethodEntry );
629 rootNode.load( this );
630 return rootNode;
631 }
632
633 public Set<MethodEntry> getRelatedMethodImplementations( MethodEntry obfMethodEntry )
634 {
635 Set<MethodEntry> methodEntries = Sets.newHashSet();
636 getRelatedMethodImplementations( methodEntries, getMethodInheritance( null, obfMethodEntry ) );
637 return methodEntries;
638 }
639
640 private void getRelatedMethodImplementations( Set<MethodEntry> methodEntries, MethodInheritanceTreeNode node )
641 {
642 MethodEntry methodEntry = node.getMethodEntry();
643 if( isMethodImplemented( methodEntry ) )
644 {
645 // collect the entry
646 methodEntries.add( methodEntry );
647 }
648
649 // look at interface methods too
650 getRelatedMethodImplementations( methodEntries, getMethodImplementations( null, methodEntry ) );
651
652 // recurse
653 for( int i=0; i<node.getChildCount(); i++ )
654 {
655 getRelatedMethodImplementations( methodEntries, (MethodInheritanceTreeNode)node.getChildAt( i ) );
656 }
657 }
658
659 private void getRelatedMethodImplementations( Set<MethodEntry> methodEntries, MethodImplementationsTreeNode node )
660 {
661 MethodEntry methodEntry = node.getMethodEntry();
662 if( isMethodImplemented( methodEntry ) )
663 {
664 // collect the entry
665 methodEntries.add( methodEntry );
666 }
667
668 // recurse
669 for( int i=0; i<node.getChildCount(); i++ )
670 {
671 getRelatedMethodImplementations( methodEntries, (MethodImplementationsTreeNode)node.getChildAt( i ) );
672 }
673 }
674
580 public Collection<EntryReference<FieldEntry,BehaviorEntry>> getFieldReferences( FieldEntry fieldEntry ) 675 public Collection<EntryReference<FieldEntry,BehaviorEntry>> getFieldReferences( FieldEntry fieldEntry )
581 { 676 {
582 return m_fieldReferences.get( fieldEntry ); 677 return m_fieldReferences.get( fieldEntry );
@@ -626,16 +721,14 @@ public class JarIndex
626 { 721 {
627 // for each key/value pair... 722 // for each key/value pair...
628 Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet(); 723 Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet();
629 Iterator<Map.Entry<Key,Val>> iter = map.entries().iterator(); 724 for( Map.Entry<Key,Val> entry : map.entries() )
630 while( iter.hasNext() )
631 { 725 {
632 Map.Entry<Key,Val> entry = iter.next();
633 iter.remove();
634 entriesToAdd.add( new AbstractMap.SimpleEntry<Key,Val>( 726 entriesToAdd.add( new AbstractMap.SimpleEntry<Key,Val>(
635 renameClassesInThing( renames, entry.getKey() ), 727 renameClassesInThing( renames, entry.getKey() ),
636 renameClassesInThing( renames, entry.getValue() ) 728 renameClassesInThing( renames, entry.getValue() )
637 ) ); 729 ) );
638 } 730 }
731 map.clear();
639 for( Map.Entry<Key,Val> entry : entriesToAdd ) 732 for( Map.Entry<Key,Val> entry : entriesToAdd )
640 { 733 {
641 map.put( entry.getKey(), entry.getValue() ); 734 map.put( entry.getKey(), entry.getValue() );
@@ -761,5 +854,5 @@ public class JarIndex
761 return thing; 854 return thing;
762 } 855 }
763 return thing; 856 return thing;
764 } 857 }
765} 858}
diff --git a/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.java
new file mode 100644
index 00000000..b529f3f6
--- /dev/null
+++ b/src/cuchaz/enigma/analysis/MethodImplementationsTreeNode.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.util.List;
14
15import javax.swing.tree.DefaultMutableTreeNode;
16
17import com.google.common.collect.Lists;
18
19import cuchaz.enigma.mapping.ClassEntry;
20import cuchaz.enigma.mapping.MethodEntry;
21import cuchaz.enigma.mapping.Translator;
22
23public class MethodImplementationsTreeNode extends DefaultMutableTreeNode
24{
25 private static final long serialVersionUID = 3781080657461899915L;
26
27 private Translator m_deobfuscatingTranslator;
28 private MethodEntry m_entry;
29
30 public MethodImplementationsTreeNode( Translator deobfuscatingTranslator, MethodEntry entry )
31 {
32 m_deobfuscatingTranslator = deobfuscatingTranslator;
33 m_entry = entry;
34 }
35
36 public MethodEntry getMethodEntry( )
37 {
38 return m_entry;
39 }
40
41 public String getDeobfClassName( )
42 {
43 return m_deobfuscatingTranslator.translateClass( m_entry.getClassName() );
44 }
45
46 public String getDeobfMethodName( )
47 {
48 return m_deobfuscatingTranslator.translate( m_entry );
49 }
50
51 @Override
52 public String toString( )
53 {
54 String className = getDeobfClassName();
55 if( className == null )
56 {
57 className = m_entry.getClassName();
58 }
59
60 String methodName = getDeobfMethodName();
61 if( methodName == null )
62 {
63 methodName = m_entry.getName();
64 }
65 return className + "." + methodName + "()";
66 }
67
68 public void load( JarIndex index )
69 {
70 // get all method implementations
71 List<MethodImplementationsTreeNode> nodes = Lists.newArrayList();
72 for( String implementingClassName : index.getAncestries().getImplementingClasses( m_entry.getClassName() ) )
73 {
74 MethodEntry methodEntry = new MethodEntry(
75 new ClassEntry( implementingClassName ),
76 m_entry.getName(),
77 m_entry.getSignature()
78 );
79 if( index.isMethodImplemented( methodEntry ) )
80 {
81 nodes.add( new MethodImplementationsTreeNode( m_deobfuscatingTranslator, methodEntry ) );
82 }
83 }
84
85 // add them to this node
86 for( MethodImplementationsTreeNode node : nodes )
87 {
88 this.add( node );
89 }
90 }
91
92 public static MethodImplementationsTreeNode findNode( MethodImplementationsTreeNode node, MethodEntry entry )
93 {
94 // is this the node?
95 if( node.getMethodEntry().equals( entry ) )
96 {
97 return node;
98 }
99
100 // recurse
101 for( int i=0; i<node.getChildCount(); i++ )
102 {
103 MethodImplementationsTreeNode foundNode = findNode( (MethodImplementationsTreeNode)node.getChildAt( i ), entry );
104 if( foundNode != null )
105 {
106 return foundNode;
107 }
108 }
109 return null;
110 }
111}
diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java
index 4e636064..3dcb4e24 100644
--- a/src/cuchaz/enigma/gui/Gui.java
+++ b/src/cuchaz/enigma/gui/Gui.java
@@ -70,9 +70,11 @@ import com.google.common.collect.Lists;
70 70
71import cuchaz.enigma.Constants; 71import cuchaz.enigma.Constants;
72import cuchaz.enigma.analysis.BehaviorReferenceTreeNode; 72import cuchaz.enigma.analysis.BehaviorReferenceTreeNode;
73import cuchaz.enigma.analysis.ClassImplementationsTreeNode;
73import cuchaz.enigma.analysis.ClassInheritanceTreeNode; 74import cuchaz.enigma.analysis.ClassInheritanceTreeNode;
74import cuchaz.enigma.analysis.EntryReference; 75import cuchaz.enigma.analysis.EntryReference;
75import cuchaz.enigma.analysis.FieldReferenceTreeNode; 76import cuchaz.enigma.analysis.FieldReferenceTreeNode;
77import cuchaz.enigma.analysis.MethodImplementationsTreeNode;
76import cuchaz.enigma.analysis.MethodInheritanceTreeNode; 78import cuchaz.enigma.analysis.MethodInheritanceTreeNode;
77import cuchaz.enigma.analysis.ReferenceTreeNode; 79import cuchaz.enigma.analysis.ReferenceTreeNode;
78import cuchaz.enigma.analysis.Token; 80import cuchaz.enigma.analysis.Token;
@@ -148,6 +150,7 @@ public class Gui
148 private DeobfuscatedHighlightPainter m_deobfuscatedHighlightPainter; 150 private DeobfuscatedHighlightPainter m_deobfuscatedHighlightPainter;
149 private SelectionHighlightPainter m_selectionHighlightPainter; 151 private SelectionHighlightPainter m_selectionHighlightPainter;
150 private JTree m_inheritanceTree; 152 private JTree m_inheritanceTree;
153 private JTree m_implementationsTree;
151 private JTree m_callsTree; 154 private JTree m_callsTree;
152 private JList<Token> m_tokens; 155 private JList<Token> m_tokens;
153 private JTabbedPane m_tabs; 156 private JTabbedPane m_tabs;
@@ -163,6 +166,7 @@ public class Gui
163 private JMenuItem m_openEntryMenu; 166 private JMenuItem m_openEntryMenu;
164 private JMenuItem m_openPreviousMenu; 167 private JMenuItem m_openPreviousMenu;
165 private JMenuItem m_showCallsMenu; 168 private JMenuItem m_showCallsMenu;
169 private JMenuItem m_showImplementationsMenu;
166 170
167 // state 171 // state
168 private EntryReference<Entry,Entry> m_reference; 172 private EntryReference<Entry,Entry> m_reference;
@@ -285,6 +289,10 @@ public class Gui
285 showInheritance(); 289 showInheritance();
286 break; 290 break;
287 291
292 case KeyEvent.VK_M:
293 showImplementations();
294 break;
295
288 case KeyEvent.VK_N: 296 case KeyEvent.VK_N:
289 openDeclaration(); 297 openDeclaration();
290 break; 298 break;
@@ -338,6 +346,21 @@ public class Gui
338 m_showInheritanceMenu = menu; 346 m_showInheritanceMenu = menu;
339 } 347 }
340 { 348 {
349 JMenuItem menu = new JMenuItem( "Show Implementations" );
350 menu.addActionListener( new ActionListener( )
351 {
352 @Override
353 public void actionPerformed( ActionEvent event )
354 {
355 showImplementations();
356 }
357 } );
358 menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_M, 0 ) );
359 menu.setEnabled( false );
360 popupMenu.add( menu );
361 m_showImplementationsMenu = menu;
362 }
363 {
341 JMenuItem menu = new JMenuItem( "Show Calls" ); 364 JMenuItem menu = new JMenuItem( "Show Calls" );
342 menu.addActionListener( new ActionListener( ) 365 menu.addActionListener( new ActionListener( )
343 { 366 {
@@ -428,6 +451,41 @@ public class Gui
428 inheritancePanel.setLayout( new BorderLayout() ); 451 inheritancePanel.setLayout( new BorderLayout() );
429 inheritancePanel.add( new JScrollPane( m_inheritanceTree ) ); 452 inheritancePanel.add( new JScrollPane( m_inheritanceTree ) );
430 453
454 // init implementations panel
455 m_implementationsTree = new JTree();
456 m_implementationsTree.setModel( null );
457 m_implementationsTree.addMouseListener( new MouseAdapter( )
458 {
459 @Override
460 public void mouseClicked( MouseEvent event )
461 {
462 if( event.getClickCount() == 2 )
463 {
464 // get the selected node
465 TreePath path = m_implementationsTree.getSelectionPath();
466 if( path == null )
467 {
468 return;
469 }
470
471 Object node = path.getLastPathComponent();
472 if( node instanceof ClassImplementationsTreeNode )
473 {
474 ClassImplementationsTreeNode classNode = (ClassImplementationsTreeNode)node;
475 m_controller.openDeclaration( classNode.getClassEntry() );
476 }
477 else if( node instanceof MethodImplementationsTreeNode )
478 {
479 MethodImplementationsTreeNode methodNode = (MethodImplementationsTreeNode)node;
480 m_controller.openDeclaration( methodNode.getMethodEntry() );
481 }
482 }
483 }
484 } );
485 JPanel implementationsPanel = new JPanel();
486 implementationsPanel.setLayout( new BorderLayout() );
487 implementationsPanel.add( new JScrollPane( m_implementationsTree ) );
488
431 // init call panel 489 // init call panel
432 m_callsTree = new JTree(); 490 m_callsTree = new JTree();
433 m_callsTree.setModel( null ); 491 m_callsTree.setModel( null );
@@ -501,6 +559,7 @@ public class Gui
501 m_tabs = new JTabbedPane(); 559 m_tabs = new JTabbedPane();
502 m_tabs.setPreferredSize( new Dimension( 250, 0 ) ); 560 m_tabs.setPreferredSize( new Dimension( 250, 0 ) );
503 m_tabs.addTab( "Inheritance", inheritancePanel ); 561 m_tabs.addTab( "Inheritance", inheritancePanel );
562 m_tabs.addTab( "Implementations", implementationsPanel );
504 m_tabs.addTab( "Call Graph", callPanel ); 563 m_tabs.addTab( "Call Graph", callPanel );
505 JSplitPane splitRight = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, m_tabs ); 564 JSplitPane splitRight = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, m_tabs );
506 splitRight.setResizeWeight( 1 ); // let the left side take all the slack 565 splitRight.setResizeWeight( 1 ); // let the left side take all the slack
@@ -1023,6 +1082,7 @@ public class Gui
1023 1082
1024 m_renameMenu.setEnabled( isToken ); 1083 m_renameMenu.setEnabled( isToken );
1025 m_showInheritanceMenu.setEnabled( isClassEntry || isMethodEntry || isConstructorEntry ); 1084 m_showInheritanceMenu.setEnabled( isClassEntry || isMethodEntry || isConstructorEntry );
1085 m_showImplementationsMenu.setEnabled( isClassEntry || isMethodEntry );
1026 m_showCallsMenu.setEnabled( isFieldEntry || isMethodEntry || isConstructorEntry ); 1086 m_showCallsMenu.setEnabled( isFieldEntry || isMethodEntry || isConstructorEntry );
1027 m_openEntryMenu.setEnabled( isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry ); 1087 m_openEntryMenu.setEnabled( isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry );
1028 m_openPreviousMenu.setEnabled( m_controller.hasPreviousLocation() ); 1088 m_openPreviousMenu.setEnabled( m_controller.hasPreviousLocation() );
@@ -1097,6 +1157,8 @@ public class Gui
1097 return; 1157 return;
1098 } 1158 }
1099 1159
1160 m_inheritanceTree.setModel( null );
1161
1100 if( m_reference.entry instanceof ClassEntry ) 1162 if( m_reference.entry instanceof ClassEntry )
1101 { 1163 {
1102 // get the class inheritance 1164 // get the class inheritance
@@ -1124,6 +1186,46 @@ public class Gui
1124 redraw(); 1186 redraw();
1125 } 1187 }
1126 1188
1189 private void showImplementations( )
1190 {
1191 if( m_reference == null )
1192 {
1193 return;
1194 }
1195
1196 m_implementationsTree.setModel( null );
1197
1198 if( m_reference.entry instanceof ClassEntry )
1199 {
1200 // get the class implementations
1201 ClassImplementationsTreeNode node = m_controller.getClassImplementations( (ClassEntry)m_reference.entry );
1202 if( node != null )
1203 {
1204 // show the tree at the root
1205 TreePath path = getPathToRoot( node );
1206 m_implementationsTree.setModel( new DefaultTreeModel( (TreeNode)path.getPathComponent( 0 ) ) );
1207 m_implementationsTree.expandPath( path );
1208 m_implementationsTree.setSelectionRow( m_implementationsTree.getRowForPath( path ) );
1209 }
1210 }
1211 else if( m_reference.entry instanceof MethodEntry )
1212 {
1213 // get the method implementations
1214 MethodImplementationsTreeNode node = m_controller.getMethodImplementations( (MethodEntry)m_reference.entry );
1215 if( node != null )
1216 {
1217 // show the tree at the root
1218 TreePath path = getPathToRoot( node );
1219 m_implementationsTree.setModel( new DefaultTreeModel( (TreeNode)path.getPathComponent( 0 ) ) );
1220 m_implementationsTree.expandPath( path );
1221 m_implementationsTree.setSelectionRow( m_implementationsTree.getRowForPath( path ) );
1222 }
1223 }
1224
1225 m_tabs.setSelectedIndex( 1 );
1226 redraw();
1227 }
1228
1127 private void showCalls( ) 1229 private void showCalls( )
1128 { 1230 {
1129 if( m_reference == null ) 1231 if( m_reference == null )
@@ -1147,7 +1249,7 @@ public class Gui
1147 m_callsTree.setModel( new DefaultTreeModel( node ) ); 1249 m_callsTree.setModel( new DefaultTreeModel( node ) );
1148 } 1250 }
1149 1251
1150 m_tabs.setSelectedIndex( 1 ); 1252 m_tabs.setSelectedIndex( 2 );
1151 redraw(); 1253 redraw();
1152 } 1254 }
1153 1255
diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java
index 90bce520..bd79e480 100644
--- a/src/cuchaz/enigma/gui/GuiController.java
+++ b/src/cuchaz/enigma/gui/GuiController.java
@@ -24,9 +24,11 @@ import com.strobel.decompiler.languages.java.ast.CompilationUnit;
24 24
25import cuchaz.enigma.Deobfuscator; 25import cuchaz.enigma.Deobfuscator;
26import cuchaz.enigma.analysis.BehaviorReferenceTreeNode; 26import cuchaz.enigma.analysis.BehaviorReferenceTreeNode;
27import cuchaz.enigma.analysis.ClassImplementationsTreeNode;
27import cuchaz.enigma.analysis.ClassInheritanceTreeNode; 28import cuchaz.enigma.analysis.ClassInheritanceTreeNode;
28import cuchaz.enigma.analysis.EntryReference; 29import cuchaz.enigma.analysis.EntryReference;
29import cuchaz.enigma.analysis.FieldReferenceTreeNode; 30import cuchaz.enigma.analysis.FieldReferenceTreeNode;
31import cuchaz.enigma.analysis.MethodImplementationsTreeNode;
30import cuchaz.enigma.analysis.MethodInheritanceTreeNode; 32import cuchaz.enigma.analysis.MethodInheritanceTreeNode;
31import cuchaz.enigma.analysis.SourceIndex; 33import cuchaz.enigma.analysis.SourceIndex;
32import cuchaz.enigma.analysis.Token; 34import cuchaz.enigma.analysis.Token;
@@ -182,6 +184,15 @@ public class GuiController
182 return ClassInheritanceTreeNode.findNode( rootNode, obfClassEntry ); 184 return ClassInheritanceTreeNode.findNode( rootNode, obfClassEntry );
183 } 185 }
184 186
187 public ClassImplementationsTreeNode getClassImplementations( ClassEntry deobfClassEntry )
188 {
189 ClassEntry obfClassEntry = m_deobfuscator.obfuscateEntry( deobfClassEntry );
190 return m_deobfuscator.getJarIndex().getClassImplementations(
191 m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ),
192 obfClassEntry
193 );
194 }
195
185 public MethodInheritanceTreeNode getMethodInheritance( MethodEntry deobfMethodEntry ) 196 public MethodInheritanceTreeNode getMethodInheritance( MethodEntry deobfMethodEntry )
186 { 197 {
187 MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry( deobfMethodEntry ); 198 MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry( deobfMethodEntry );
@@ -192,6 +203,20 @@ public class GuiController
192 return MethodInheritanceTreeNode.findNode( rootNode, obfMethodEntry ); 203 return MethodInheritanceTreeNode.findNode( rootNode, obfMethodEntry );
193 } 204 }
194 205
206 public MethodImplementationsTreeNode getMethodImplementations( MethodEntry deobfMethodEntry )
207 {
208 MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry( deobfMethodEntry );
209 MethodImplementationsTreeNode rootNode = m_deobfuscator.getJarIndex().getMethodImplementations(
210 m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ),
211 obfMethodEntry
212 );
213 if( rootNode == null )
214 {
215 return null;
216 }
217 return MethodImplementationsTreeNode.findNode( rootNode, obfMethodEntry );
218 }
219
195 public FieldReferenceTreeNode getFieldReferences( FieldEntry deobfFieldEntry ) 220 public FieldReferenceTreeNode getFieldReferences( FieldEntry deobfFieldEntry )
196 { 221 {
197 FieldEntry obfFieldEntry = m_deobfuscator.obfuscateEntry( deobfFieldEntry ); 222 FieldEntry obfFieldEntry = m_deobfuscator.obfuscateEntry( deobfFieldEntry );
diff --git a/src/cuchaz/enigma/mapping/Renamer.java b/src/cuchaz/enigma/mapping/Renamer.java
index 0bb8dc12..79cbd30d 100644
--- a/src/cuchaz/enigma/mapping/Renamer.java
+++ b/src/cuchaz/enigma/mapping/Renamer.java
@@ -16,7 +16,6 @@ import java.io.OutputStream;
16import java.util.zip.GZIPOutputStream; 16import java.util.zip.GZIPOutputStream;
17 17
18import cuchaz.enigma.analysis.JarIndex; 18import cuchaz.enigma.analysis.JarIndex;
19import cuchaz.enigma.analysis.MethodInheritanceTreeNode;
20 19
21public class Renamer 20public class Renamer
22{ 21{
@@ -57,25 +56,9 @@ public class Renamer
57 56
58 public void setMethodTreeName( MethodEntry obf, String deobfName ) 57 public void setMethodTreeName( MethodEntry obf, String deobfName )
59 { 58 {
60 // get the method tree 59 for( MethodEntry entry : m_index.getRelatedMethodImplementations( obf ) )
61 setMethodTreeName(
62 m_index.getMethodInheritance( m_mappings.getTranslator( m_index.getAncestries(), TranslationDirection.Deobfuscating ), obf ),
63 deobfName
64 );
65 }
66
67 private void setMethodTreeName( MethodInheritanceTreeNode node, String deobfName )
68 {
69 if( node.isImplemented() )
70 {
71 // apply the name here
72 setMethodName( node.getMethodEntry(), deobfName );
73 }
74
75 // recurse
76 for( int i=0; i<node.getChildCount(); i++ )
77 { 60 {
78 setMethodTreeName( (MethodInheritanceTreeNode)node.getChildAt( i ), deobfName ); 61 setMethodName( entry, deobfName );
79 } 62 }
80 } 63 }
81 64