From 237b2ed2a6b6f537cdbdf9fc9c6d0c7743f34375 Mon Sep 17 00:00:00 2001 From: jeff Date: Thu, 21 Aug 2014 01:10:37 -0400 Subject: fixed call graph searching added system to navigate multiple tokens for the same entry in a behavior --- src/cuchaz/enigma/gui/Gui.java | 53 +++++++++++++---- src/cuchaz/enigma/gui/GuiController.java | 75 +++++++++++++++--------- src/cuchaz/enigma/gui/ReadableToken.java | 38 ++++++++++++ src/cuchaz/enigma/gui/TokenListCellRenderer.java | 40 +++++++++++++ 4 files changed, 167 insertions(+), 39 deletions(-) create mode 100644 src/cuchaz/enigma/gui/ReadableToken.java create mode 100644 src/cuchaz/enigma/gui/TokenListCellRenderer.java (limited to 'src/cuchaz/enigma/gui') diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 341c149..a5471a7 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -28,6 +28,7 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.io.IOException; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -145,6 +146,7 @@ public class Gui private BoxHighlightPainter m_deobfuscatedHighlightPainter; private JTree m_inheritanceTree; private JTree m_callsTree; + private JList m_tokens; private JTabbedPane m_tabs; // dynamic menu items @@ -457,9 +459,29 @@ public class Gui } } } ); - JPanel callPanel = new JPanel(); - callPanel.setLayout( new BorderLayout() ); - callPanel.add( new JScrollPane( m_callsTree ) ); + m_tokens = new JList(); + m_tokens.setCellRenderer( new TokenListCellRenderer( m_controller ) ); + m_tokens.setSelectionMode( ListSelectionModel.SINGLE_SELECTION ); + m_tokens.setLayoutOrientation( JList.VERTICAL ); + m_tokens.addMouseListener( new MouseAdapter() + { + @Override + public void mouseClicked( MouseEvent event ) + { + if( event.getClickCount() == 2 ) + { + Token selected = m_tokens.getSelectedValue(); + if( selected != null ) + { + showToken( selected ); + } + } + } + } ); + m_tokens.setPreferredSize( new Dimension( 0, 200 ) ); + JSplitPane callPanel = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, new JScrollPane( m_callsTree ), new JScrollPane( m_tokens ) ); + callPanel.setResizeWeight( 1 ); // let the top side take all the slack + callPanel.resetToPreferredSizes(); // layout controls JSplitPane splitLeft = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, obfPanel, deobfPanel ); @@ -743,6 +765,21 @@ public class Gui m_editor.grabFocus(); } + public void showTokens( Collection tokens ) + { + Vector sortedTokens = new Vector( tokens ); + Collections.sort( sortedTokens ); + if( sortedTokens.size() > 1 ) + { + // sort the tokens and update the tokens panel + m_tokens.setListData( sortedTokens ); + m_tokens.setSelectedIndex( 0 ); + } + + // show the first token + showToken( sortedTokens.get( 0 ) ); + } + public void setHighlightedTokens( Iterable obfuscatedTokens, Iterable deobfuscatedTokens ) { // remove any old highlighters @@ -900,17 +937,9 @@ public class Gui private void startRename( ) { - // get the class name - ClassEntry classEntry = m_reference.entry.getClassEntry(); - String className = classEntry.getName(); - if( classEntry.isInnerClass() ) - { - className = classEntry.getInnerClassName(); - } - // init the text box final JTextField text = new JTextField(); - text.setText( className ); + text.setText( m_reference.entry.getName() ); text.setPreferredSize( new Dimension( 360, text.getPreferredSize().height ) ); text.addKeyListener( new KeyAdapter( ) { diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index dfa2557..a35db05 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -14,6 +14,7 @@ import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; +import java.util.Collection; import java.util.Deque; import java.util.List; @@ -45,7 +46,7 @@ public class GuiController private SourceIndex m_index; private ClassEntry m_currentObfClass; private boolean m_isDirty; - private Deque> m_referenceStack; // TODO: make a location class, can be either Entry or EntryReference + private Deque> m_referenceStack; public GuiController( Gui gui ) { @@ -111,7 +112,6 @@ public class GuiController { return null; } - return m_index.getReferenceToken( pos ); } @@ -124,6 +124,19 @@ public class GuiController return m_index.getDeobfReference( token ); } + public ReadableToken getReadableToken( Token token ) + { + if( m_index == null ) + { + return null; + } + return new ReadableToken( + m_index.getLineNumber( token.start ), + m_index.getColumnNumber( token.start ), + m_index.getColumnNumber( token.end ) + ); + } + public boolean entryHasMapping( Entry deobfEntry ) { return m_deobfuscator.hasMapping( m_deobfuscator.obfuscateEntry( deobfEntry ) ); @@ -134,8 +147,9 @@ public class GuiController return m_deobfuscator.isObfuscatedIdentifier( m_deobfuscator.obfuscateEntry( deobfEntry ) ); } - public ClassInheritanceTreeNode getClassInheritance( ClassEntry obfClassEntry ) + public ClassInheritanceTreeNode getClassInheritance( ClassEntry deobfClassEntry ) { + ClassEntry obfClassEntry = m_deobfuscator.obfuscateEntry( deobfClassEntry ); ClassInheritanceTreeNode rootNode = m_deobfuscator.getJarIndex().getClassInheritance( m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), obfClassEntry @@ -143,8 +157,9 @@ public class GuiController return ClassInheritanceTreeNode.findNode( rootNode, obfClassEntry ); } - public MethodInheritanceTreeNode getMethodInheritance( MethodEntry obfMethodEntry ) + public MethodInheritanceTreeNode getMethodInheritance( MethodEntry deobfMethodEntry ) { + MethodEntry obfMethodEntry = m_deobfuscator.obfuscateEntry( deobfMethodEntry ); MethodInheritanceTreeNode rootNode = m_deobfuscator.getJarIndex().getMethodInheritance( m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), obfMethodEntry @@ -152,8 +167,9 @@ public class GuiController return MethodInheritanceTreeNode.findNode( rootNode, obfMethodEntry ); } - public FieldReferenceTreeNode getFieldReferences( FieldEntry obfFieldEntry ) + public FieldReferenceTreeNode getFieldReferences( FieldEntry deobfFieldEntry ) { + FieldEntry obfFieldEntry = m_deobfuscator.obfuscateEntry( deobfFieldEntry ); FieldReferenceTreeNode rootNode = new FieldReferenceTreeNode( m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), obfFieldEntry @@ -162,11 +178,12 @@ public class GuiController return rootNode; } - public BehaviorReferenceTreeNode getMethodReferences( BehaviorEntry obfEntry ) + public BehaviorReferenceTreeNode getMethodReferences( BehaviorEntry deobfBehaviorEntry ) { + BehaviorEntry obfBehaviorEntry = m_deobfuscator.obfuscateEntry( deobfBehaviorEntry ); BehaviorReferenceTreeNode rootNode = new BehaviorReferenceTreeNode( m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), - obfEntry + obfBehaviorEntry ); rootNode.load( m_deobfuscator.getJarIndex(), true ); return rootNode; @@ -181,13 +198,13 @@ public class GuiController refreshCurrentClass( obfReference ); } - public void openDeclaration( Entry entry ) + public void openDeclaration( Entry deobfEntry ) { - if( entry == null ) + if( deobfEntry == null ) { throw new IllegalArgumentException( "Entry cannot be null!" ); } - openReference( new EntryReference( entry ) ); + openReference( new EntryReference( deobfEntry ) ); } public void openReference( EntryReference deobfReference ) @@ -208,8 +225,22 @@ public class GuiController } else { - // the class file is already open, just navigate to the reference - m_gui.showToken( m_index.getReferenceToken( deobfReference ) ); + showReference( obfReference ); + } + } + + private void showReference( EntryReference obfReference ) + { + EntryReference deobfReference = m_deobfuscator.deobfuscateReference( obfReference ); + Collection tokens = m_index.getReferenceTokens( deobfReference ); + if( tokens.isEmpty() ) + { + // DEBUG + System.err.println( String.format( "WARNING: no tokens found for %s in %s", deobfReference, m_currentObfClass ) ); + } + else + { + m_gui.showTokens( tokens ); } } @@ -245,15 +276,15 @@ public class GuiController refreshCurrentClass( null ); } - private void refreshCurrentClass( EntryReference obfReferenceToShow ) + private void refreshCurrentClass( EntryReference obfReference ) { if( m_currentObfClass != null ) { - deobfuscate( m_currentObfClass, obfReferenceToShow ); + deobfuscate( m_currentObfClass, obfReference ); } } - private void deobfuscate( final ClassEntry classEntry, final EntryReference obfReferenceToShow ) + private void deobfuscate( final ClassEntry classEntry, final EntryReference obfReference ) { m_gui.setSource( "(deobfuscating...)" ); @@ -266,19 +297,9 @@ public class GuiController // decompile,deobfuscate the bytecode m_index = m_deobfuscator.getSource( classEntry.getClassName() ); m_gui.setSource( m_index.getSource() ); - if( obfReferenceToShow != null ) + if( obfReference != null ) { - EntryReference deobfReferenceToShow = m_deobfuscator.deobfuscateReference( obfReferenceToShow ); - Token token = m_index.getReferenceToken( deobfReferenceToShow ); - if( token == null ) - { - // DEBUG - System.out.println( "WARNING: can't find token for " + obfReferenceToShow + " -> " + deobfReferenceToShow ); - } - else - { - m_gui.showToken( token ); - } + showReference( obfReference ); } // set the highlighted tokens diff --git a/src/cuchaz/enigma/gui/ReadableToken.java b/src/cuchaz/enigma/gui/ReadableToken.java new file mode 100644 index 0000000..3f43045 --- /dev/null +++ b/src/cuchaz/enigma/gui/ReadableToken.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2014 Jeff Martin. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + * + * Contributors: + * Jeff Martin - initial API and implementation + ******************************************************************************/ +package cuchaz.enigma.gui; + +public class ReadableToken +{ + public int line; + public int startColumn; + public int endColumn; + + public ReadableToken( int line, int startColumn, int endColumn ) + { + this.line = line; + this.startColumn = startColumn; + this.endColumn = endColumn; + } + + @Override + public String toString( ) + { + StringBuilder buf = new StringBuilder(); + buf.append( "line " ); + buf.append( line ); + buf.append( " columns " ); + buf.append( startColumn ); + buf.append( "-" ); + buf.append( endColumn ); + return buf.toString(); + } +} diff --git a/src/cuchaz/enigma/gui/TokenListCellRenderer.java b/src/cuchaz/enigma/gui/TokenListCellRenderer.java new file mode 100644 index 0000000..9247c06 --- /dev/null +++ b/src/cuchaz/enigma/gui/TokenListCellRenderer.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2014 Jeff Martin. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + * + * Contributors: + * Jeff Martin - initial API and implementation + ******************************************************************************/ +package cuchaz.enigma.gui; + +import java.awt.Component; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.ListCellRenderer; + +import cuchaz.enigma.analysis.Token; + +public class TokenListCellRenderer implements ListCellRenderer +{ + private GuiController m_controller; + private DefaultListCellRenderer m_defaultRenderer; + + public TokenListCellRenderer( GuiController controller ) + { + m_controller = controller; + m_defaultRenderer = new DefaultListCellRenderer(); + } + + @Override + public Component getListCellRendererComponent( JList list, Token token, int index, boolean isSelected, boolean hasFocus ) + { + JLabel label = (JLabel)m_defaultRenderer.getListCellRendererComponent( list, token, index, isSelected, hasFocus ); + label.setText( m_controller.getReadableToken( token ).toString() ); + return label; + } +} -- cgit v1.2.3