From a85529d1ce6ec533809575ec84572de855464b36 Mon Sep 17 00:00:00 2001 From: jeff Date: Wed, 20 Aug 2014 01:21:52 -0400 Subject: finished reference navigation system. Still need to debug and polish it, but the basic idea seems to work. =) --- src/cuchaz/enigma/gui/Gui.java | 158 ++++++++++++++++++------------- src/cuchaz/enigma/gui/GuiController.java | 106 +++++++++++---------- 2 files changed, 147 insertions(+), 117 deletions(-) (limited to 'src/cuchaz/enigma/gui') diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 43a0cda..341c149 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -68,6 +68,7 @@ import com.google.common.collect.Lists; import cuchaz.enigma.Constants; import cuchaz.enigma.analysis.BehaviorReferenceTreeNode; import cuchaz.enigma.analysis.ClassInheritanceTreeNode; +import cuchaz.enigma.analysis.EntryReference; import cuchaz.enigma.analysis.FieldReferenceTreeNode; import cuchaz.enigma.analysis.MethodInheritanceTreeNode; import cuchaz.enigma.analysis.ReferenceTreeNode; @@ -76,7 +77,6 @@ import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; -import cuchaz.enigma.mapping.EntryPair; import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.IllegalNameException; import cuchaz.enigma.mapping.MappingParseException; @@ -160,7 +160,7 @@ public class Gui private JMenuItem m_showCallsMenu; // state - private EntryPair m_selectedEntryPair; + private EntryReference m_reference; private JFileChooser m_jarFileChooser; private JFileChooser m_mappingsFileChooser; @@ -192,6 +192,10 @@ public class Gui String selected = m_obfClasses.getSelectedValue(); if( selected != null ) { + if( m_reference != null ) + { + m_controller.savePreviousReference( m_reference ); + } m_controller.openDeclaration( new ClassEntry( selected ) ); } } @@ -218,6 +222,10 @@ public class Gui String selected = m_deobfClasses.getSelectedValue(); if( selected != null ) { + if( m_reference != null ) + { + m_controller.savePreviousReference( m_reference ); + } m_controller.openDeclaration( new ClassEntry( selected ) ); } } @@ -234,7 +242,7 @@ public class Gui m_infoPanel.setLayout( new GridLayout( 4, 1, 0, 0 ) ); m_infoPanel.setPreferredSize( new Dimension( 0, 100 ) ); m_infoPanel.setBorder( BorderFactory.createTitledBorder( "Identifier Info" ) ); - clearEntryPair(); + clearReference(); // init editor DefaultSyntaxKit.initKit(); @@ -273,7 +281,7 @@ public class Gui break; case KeyEvent.VK_P: - m_controller.openPreviousLocation(); + m_controller.openPreviousReference(); break; case KeyEvent.VK_C: @@ -357,7 +365,7 @@ public class Gui @Override public void actionPerformed( ActionEvent event ) { - m_controller.openPreviousLocation(); + m_controller.openPreviousReference(); } } ); menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_P, 0 ) ); @@ -386,6 +394,10 @@ public class Gui Object node = path.getLastPathComponent(); if( node instanceof ClassInheritanceTreeNode ) { + if( m_reference != null ) + { + m_controller.savePreviousReference( m_reference ); + } m_controller.openDeclaration( new ClassEntry( ((ClassInheritanceTreeNode)node).getObfClassName() ) ); } else if( node instanceof MethodInheritanceTreeNode ) @@ -393,6 +405,10 @@ public class Gui MethodInheritanceTreeNode methodNode = (MethodInheritanceTreeNode)node; if( methodNode.isImplemented() ) { + if( m_reference != null ) + { + m_controller.savePreviousReference( m_reference ); + } m_controller.openDeclaration( methodNode.getMethodEntry() ); } } @@ -424,7 +440,11 @@ public class Gui Object node = path.getLastPathComponent(); if( node instanceof ReferenceTreeNode ) { - ReferenceTreeNode referenceNode = ((ReferenceTreeNode)node); + if( m_reference != null ) + { + m_controller.savePreviousReference( m_reference ); + } + ReferenceTreeNode referenceNode = ((ReferenceTreeNode)node); if( referenceNode.getReference() != null ) { m_controller.openReference( referenceNode.getReference() ); @@ -715,6 +735,10 @@ public class Gui public void showToken( Token token ) { + if( token == null ) + { + throw new IllegalArgumentException( "Token cannot be null!" ); + } m_editor.setCaretPosition( token.start ); m_editor.grabFocus(); } @@ -752,7 +776,7 @@ public class Gui } } - private void clearEntryPair( ) + private void clearReference( ) { m_infoPanel.removeAll(); JLabel label = new JLabel( "No identifier selected" ); @@ -763,76 +787,75 @@ public class Gui redraw(); } - @SuppressWarnings( "unchecked" ) - private void showEntryPair( EntryPair pair ) + private void showReference( EntryReference reference ) { - if( pair == null ) + if( reference == null ) { - clearEntryPair(); + clearReference(); return; } - m_selectedEntryPair = pair; + m_reference = reference; m_infoPanel.removeAll(); - if( pair.deobf instanceof ClassEntry ) + if( reference.entry instanceof ClassEntry ) { - showClassEntryPair( (EntryPair)pair ); + showClassEntry( (ClassEntry)m_reference.entry ); } - else if( pair.deobf instanceof FieldEntry ) + else if( m_reference.entry instanceof FieldEntry ) { - showFieldEntryPair( (EntryPair)pair ); + showFieldEntry( (FieldEntry)m_reference.entry ); } - else if( pair.deobf instanceof MethodEntry ) + else if( m_reference.entry instanceof MethodEntry ) { - showMethodEntryPair( (EntryPair)pair ); + showMethodEntry( (MethodEntry)m_reference.entry ); } - else if( pair.deobf instanceof ConstructorEntry ) + else if( m_reference.entry instanceof ConstructorEntry ) { - showConstructorEntryPair( (EntryPair)pair ); + showConstructorEntry( (ConstructorEntry)m_reference.entry ); } - else if( pair.deobf instanceof ArgumentEntry ) + else if( m_reference.entry instanceof ArgumentEntry ) { - showArgumentEntryPair( (EntryPair)pair ); + showArgumentEntry( (ArgumentEntry)m_reference.entry ); } else { - throw new Error( "Unknown entry type: " + pair.deobf.getClass().getName() ); + throw new Error( "Unknown entry type: " + m_reference.entry.getClass().getName() ); } redraw(); } - private void showClassEntryPair( EntryPair pair ) + private void showClassEntry( ClassEntry entry ) { - addNameValue( m_infoPanel, "Class", pair.deobf.getName() ); + addNameValue( m_infoPanel, "Class", entry.getName() ); } - private void showFieldEntryPair( EntryPair pair ) + private void showFieldEntry( FieldEntry entry ) { - addNameValue( m_infoPanel, "Field", pair.deobf.getName() ); - addNameValue( m_infoPanel, "Class", pair.deobf.getClassEntry().getName() ); + addNameValue( m_infoPanel, "Field", entry.getName() ); + addNameValue( m_infoPanel, "Class", entry.getClassEntry().getName() ); } - private void showMethodEntryPair( EntryPair pair ) + private void showMethodEntry( MethodEntry entry ) { - addNameValue( m_infoPanel, "Method", pair.deobf.getName() ); - addNameValue( m_infoPanel, "Class", pair.deobf.getClassEntry().getName() ); - addNameValue( m_infoPanel, "Signature", pair.deobf.getSignature() ); + addNameValue( m_infoPanel, "Method", entry.getName() ); + addNameValue( m_infoPanel, "Class", entry.getClassEntry().getName() ); + addNameValue( m_infoPanel, "Signature", entry.getSignature() ); } - private void showConstructorEntryPair( EntryPair pair ) + private void showConstructorEntry( ConstructorEntry entry ) { - addNameValue( m_infoPanel, "Constructor", pair.deobf.getClassEntry().getName() ); - addNameValue( m_infoPanel, "Signature", pair.deobf.getSignature() ); + addNameValue( m_infoPanel, "Constructor", entry.getClassEntry().getName() ); + addNameValue( m_infoPanel, "Signature", entry.getSignature() ); } - private void showArgumentEntryPair( EntryPair pair ) + private void showArgumentEntry( ArgumentEntry entry ) { - addNameValue( m_infoPanel, "Argument", pair.deobf.getName() ); - addNameValue( m_infoPanel, "Class", pair.deobf.getClassEntry().getName() ); - addNameValue( m_infoPanel, "Method", pair.deobf.getMethodEntry().getName() ); - addNameValue( m_infoPanel, "Index", Integer.toString( pair.deobf.getIndex() ) ); + addNameValue( m_infoPanel, "Argument", entry.getName() ); + addNameValue( m_infoPanel, "Class", entry.getClassEntry().getName() ); + addNameValue( m_infoPanel, "Method", entry.getMethodEntry().getName() ); + addNameValue( m_infoPanel, "Index", Integer.toString( entry.getIndex() ) ); } private void addNameValue( JPanel container, String name, String value ) @@ -853,19 +876,19 @@ public class Gui Token token = m_controller.getToken( pos ); boolean isToken = token != null; - m_selectedEntryPair = m_controller.getEntryPair( token ); - boolean isClassEntry = isToken && m_selectedEntryPair.obf instanceof ClassEntry; - boolean isFieldEntry = isToken && m_selectedEntryPair.obf instanceof FieldEntry; - boolean isMethodEntry = isToken && m_selectedEntryPair.obf instanceof MethodEntry; - boolean isConstructorEntry = isToken && m_selectedEntryPair.obf instanceof ConstructorEntry; + m_reference = m_controller.getDeobfReference( token ); + boolean isClassEntry = isToken && m_reference.entry instanceof ClassEntry; + boolean isFieldEntry = isToken && m_reference.entry instanceof FieldEntry; + boolean isMethodEntry = isToken && m_reference.entry instanceof MethodEntry; + boolean isConstructorEntry = isToken && m_reference.entry instanceof ConstructorEntry; if( isToken ) { - showEntryPair( m_selectedEntryPair ); + showReference( m_reference ); } else { - clearEntryPair(); + clearReference(); } m_renameMenu.setEnabled( isToken ); @@ -878,11 +901,11 @@ public class Gui private void startRename( ) { // get the class name - String className = m_selectedEntryPair.deobf.getName(); - int pos = className.lastIndexOf( '$' ); - if( pos >= 0 ) + ClassEntry classEntry = m_reference.entry.getClassEntry(); + String className = classEntry.getName(); + if( classEntry.isInnerClass() ) { - className = className.substring( pos + 1 ); + className = classEntry.getInnerClassName(); } // init the text box @@ -924,7 +947,7 @@ public class Gui { try { - m_controller.rename( m_selectedEntryPair.obf, newName ); + m_controller.rename( m_reference, newName ); } catch( IllegalNameException ex ) { @@ -937,7 +960,7 @@ public class Gui // abort the rename JPanel panel = (JPanel)m_infoPanel.getComponent( 0 ); panel.remove( panel.getComponentCount() - 1 ); - panel.add( unboldLabel( new JLabel( m_selectedEntryPair.deobf.getName(), JLabel.LEFT ) ) ); + panel.add( unboldLabel( new JLabel( m_reference.entry.getName(), JLabel.LEFT ) ) ); m_editor.grabFocus(); @@ -946,15 +969,15 @@ public class Gui private void showInheritance( ) { - if( m_selectedEntryPair == null ) + if( m_reference == null ) { return; } - if( m_selectedEntryPair.obf instanceof ClassEntry ) + if( m_reference.entry instanceof ClassEntry ) { // get the class inheritance - ClassInheritanceTreeNode classNode = m_controller.getClassInheritance( (ClassEntry)m_selectedEntryPair.obf ); + ClassInheritanceTreeNode classNode = m_controller.getClassInheritance( (ClassEntry)m_reference.entry ); // show the tree at the root TreePath path = getPathToRoot( classNode ); @@ -962,10 +985,10 @@ public class Gui m_inheritanceTree.expandPath( path ); m_inheritanceTree.setSelectionRow( m_inheritanceTree.getRowForPath( path ) ); } - else if( m_selectedEntryPair.obf instanceof MethodEntry ) + else if( m_reference.entry instanceof MethodEntry ) { // get the method inheritance - MethodInheritanceTreeNode classNode = m_controller.getMethodInheritance( (MethodEntry)m_selectedEntryPair.obf ); + MethodInheritanceTreeNode classNode = m_controller.getMethodInheritance( (MethodEntry)m_reference.entry ); // show the tree at the root TreePath path = getPathToRoot( classNode ); @@ -980,24 +1003,24 @@ public class Gui private void showCalls( ) { - if( m_selectedEntryPair == null ) + if( m_reference == null ) { return; } - if( m_selectedEntryPair.obf instanceof FieldEntry ) + if( m_reference.entry instanceof FieldEntry ) { - FieldReferenceTreeNode node = m_controller.getFieldReferences( (FieldEntry)m_selectedEntryPair.obf ); + FieldReferenceTreeNode node = m_controller.getFieldReferences( (FieldEntry)m_reference.entry ); m_callsTree.setModel( new DefaultTreeModel( node ) ); } - else if( m_selectedEntryPair.obf instanceof MethodEntry ) + else if( m_reference.entry instanceof MethodEntry ) { - BehaviorReferenceTreeNode node = m_controller.getMethodReferences( (MethodEntry)m_selectedEntryPair.obf ); + BehaviorReferenceTreeNode node = m_controller.getMethodReferences( (MethodEntry)m_reference.entry ); m_callsTree.setModel( new DefaultTreeModel( node ) ); } - else if( m_selectedEntryPair.obf instanceof ConstructorEntry ) + else if( m_reference.entry instanceof ConstructorEntry ) { - BehaviorReferenceTreeNode node = m_controller.getMethodReferences( (ConstructorEntry)m_selectedEntryPair.obf ); + BehaviorReferenceTreeNode node = m_controller.getMethodReferences( (ConstructorEntry)m_reference.entry ); m_callsTree.setModel( new DefaultTreeModel( node ) ); } @@ -1021,11 +1044,12 @@ public class Gui private void openDeclaration( ) { - if( m_selectedEntryPair == null ) + if( m_reference == null ) { return; } - m_controller.openDeclaration( m_selectedEntryPair.obf ); + m_controller.savePreviousReference( m_reference ); + m_controller.openDeclaration( m_reference.entry ); } private void close( ) diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index f80bec7..dfa2557 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -14,10 +14,11 @@ import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; +import java.util.Deque; import java.util.List; -import java.util.Stack; import com.google.common.collect.Lists; +import com.google.common.collect.Queues; import cuchaz.enigma.Deobfuscator; import cuchaz.enigma.analysis.BehaviorReferenceTreeNode; @@ -30,7 +31,6 @@ import cuchaz.enigma.analysis.Token; import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.Entry; -import cuchaz.enigma.mapping.EntryPair; import cuchaz.enigma.mapping.FieldEntry; import cuchaz.enigma.mapping.MappingParseException; import cuchaz.enigma.mapping.MappingsReader; @@ -43,18 +43,18 @@ public class GuiController private Deobfuscator m_deobfuscator; private Gui m_gui; private SourceIndex m_index; - private ClassEntry m_currentClass; + private ClassEntry m_currentObfClass; private boolean m_isDirty; - private Stack m_locationStack; // TODO: make a location class, can be either Entry or EntryReference + private Deque> m_referenceStack; // TODO: make a location class, can be either Entry or EntryReference public GuiController( Gui gui ) { m_gui = gui; m_deobfuscator = null; m_index = null; - m_currentClass = null; + m_currentObfClass = null; m_isDirty = false; - m_locationStack = new Stack(); + m_referenceStack = Queues.newArrayDeque(); } public boolean isDirty( ) @@ -112,22 +112,16 @@ public class GuiController return null; } - return m_index.getToken( pos ); + return m_index.getReferenceToken( pos ); } - public EntryPair getEntryPair( Token token ) + public EntryReference getDeobfReference( Token token ) { if( m_index == null ) { return null; } - - Entry deobfEntry = m_index.getEntry( token ); - if( deobfEntry == null ) - { - return null; - } - return new EntryPair( m_deobfuscator.obfuscateEntry( deobfEntry ), deobfEntry ); + return m_index.getDeobfReference( token ); } public boolean entryHasMapping( Entry deobfEntry ) @@ -178,54 +172,63 @@ public class GuiController return rootNode; } - public void rename( Entry obfEntry, String newName ) + public void rename( EntryReference deobfReference, String newName ) { - m_deobfuscator.rename( obfEntry, newName ); + EntryReference obfReference = m_deobfuscator.obfuscateReference( deobfReference ); + m_deobfuscator.rename( obfReference.entry, newName ); m_isDirty = true; refreshClasses(); - refreshCurrentClass( obfEntry ); + refreshCurrentClass( obfReference ); } public void openDeclaration( Entry entry ) { - // go to the entry - Entry obfEntry = m_deobfuscator.obfuscateEntry( entry ); - if( m_currentClass == null || !m_currentClass.equals( obfEntry.getClassEntry() ) ) + if( entry == null ) { - m_currentClass = new ClassEntry( obfEntry.getClassEntry() ); - deobfuscate( m_currentClass, obfEntry ); + throw new IllegalArgumentException( "Entry cannot be null!" ); } - else + openReference( new EntryReference( entry ) ); + } + + public void openReference( EntryReference deobfReference ) + { + if( deobfReference == null ) { - m_gui.showToken( m_index.getDeclarationToken( m_deobfuscator.deobfuscateEntry( obfEntry ) ) ); + throw new IllegalArgumentException( "Reference cannot be null!" ); } - if( m_locationStack.isEmpty() || !m_locationStack.peek().equals( obfEntry ) ) + // get the reference target class + EntryReference obfReference = m_deobfuscator.obfuscateReference( deobfReference ); + ClassEntry obfClassEntry = obfReference.getClassEntry().getOuterClassEntry(); + if( m_currentObfClass == null || !m_currentObfClass.equals( obfClassEntry ) ) + { + // deobfuscate the class, then navigate to the reference + m_currentObfClass = obfClassEntry; + deobfuscate( m_currentObfClass, obfReference ); + } + else { - // update the stack - m_locationStack.push( obfEntry ); + // the class file is already open, just navigate to the reference + m_gui.showToken( m_index.getReferenceToken( deobfReference ) ); } } - public void openReference( EntryReference reference ) + public void savePreviousReference( EntryReference deobfReference ) { - // TODO: find out how to load the n-th reference in a caller - // TEMP: just go to the caller for now - openDeclaration( reference.caller ); + m_referenceStack.push( m_deobfuscator.obfuscateReference( deobfReference ) ); } - public void openPreviousLocation( ) + public void openPreviousReference( ) { if( hasPreviousLocation() ) { - m_locationStack.pop(); - openDeclaration( m_locationStack.peek() ); + openReference( m_deobfuscator.deobfuscateReference( m_referenceStack.pop() ) ); } } public boolean hasPreviousLocation( ) { - return m_locationStack.size() > 1; + return !m_referenceStack.isEmpty(); } private void refreshClasses( ) @@ -242,15 +245,15 @@ public class GuiController refreshCurrentClass( null ); } - private void refreshCurrentClass( Entry obfEntryToShow ) + private void refreshCurrentClass( EntryReference obfReferenceToShow ) { - if( m_currentClass != null ) + if( m_currentObfClass != null ) { - deobfuscate( m_currentClass, obfEntryToShow ); + deobfuscate( m_currentObfClass, obfReferenceToShow ); } } - private void deobfuscate( final ClassEntry classEntry, final Entry obfEntryToShow ) + private void deobfuscate( final ClassEntry classEntry, final EntryReference obfReferenceToShow ) { m_gui.setSource( "(deobfuscating...)" ); @@ -263,29 +266,32 @@ public class GuiController // decompile,deobfuscate the bytecode m_index = m_deobfuscator.getSource( classEntry.getClassName() ); m_gui.setSource( m_index.getSource() ); - if( obfEntryToShow != null ) + if( obfReferenceToShow != null ) { - Entry deobfEntryToShow = m_deobfuscator.deobfuscateEntry( obfEntryToShow ); - Token token = m_index.getDeclarationToken( deobfEntryToShow ); + EntryReference deobfReferenceToShow = m_deobfuscator.deobfuscateReference( obfReferenceToShow ); + Token token = m_index.getReferenceToken( deobfReferenceToShow ); if( token == null ) { - // TEMP - System.out.println( "WARNING: can't find token for " + obfEntryToShow + " -> " + deobfEntryToShow ); + // DEBUG + System.out.println( "WARNING: can't find token for " + obfReferenceToShow + " -> " + deobfReferenceToShow ); + } + else + { + m_gui.showToken( token ); } - m_gui.showToken( token ); } // set the highlighted tokens List obfuscatedTokens = Lists.newArrayList(); List deobfuscatedTokens = Lists.newArrayList(); - for( Token token : m_index.tokens() ) + for( Token token : m_index.referenceTokens() ) { - Entry entry = m_index.getEntry( token ); - if( entryHasMapping( entry ) ) + EntryReference reference = m_index.getDeobfReference( token ); + if( entryHasMapping( reference.entry ) ) { deobfuscatedTokens.add( token ); } - else if( entryIsObfuscatedIdenfitier( entry ) ) + else if( entryIsObfuscatedIdenfitier( reference.entry ) ) { obfuscatedTokens.add( token ); } -- cgit v1.2.3