From 85b3ea9beb5934012280dc0efa475f334dd9a93a Mon Sep 17 00:00:00 2001 From: jeff Date: Tue, 29 Jul 2014 23:12:30 -0400 Subject: added gui/cli loading of jars/mappings gui can save mappings too --- src/cuchaz/enigma/Controller.java | 114 ------------- src/cuchaz/enigma/Deobfuscator.java | 31 +++- src/cuchaz/enigma/Main.java | 36 +++- src/cuchaz/enigma/gui/Gui.java | 278 ++++++++++++++++++++++++------- src/cuchaz/enigma/gui/GuiController.java | 147 ++++++++++++++++ 5 files changed, 420 insertions(+), 186 deletions(-) delete mode 100644 src/cuchaz/enigma/Controller.java create mode 100644 src/cuchaz/enigma/gui/GuiController.java (limited to 'src') diff --git a/src/cuchaz/enigma/Controller.java b/src/cuchaz/enigma/Controller.java deleted file mode 100644 index 3af139e..0000000 --- a/src/cuchaz/enigma/Controller.java +++ /dev/null @@ -1,114 +0,0 @@ -/******************************************************************************* - * 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; - -import javax.swing.event.CaretEvent; -import javax.swing.event.CaretListener; - -import cuchaz.enigma.analysis.Analyzer; -import cuchaz.enigma.analysis.SourceIndex; -import cuchaz.enigma.gui.ClassSelectionListener; -import cuchaz.enigma.gui.Gui; -import cuchaz.enigma.gui.RenameListener; -import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.Entry; -import cuchaz.enigma.mapping.EntryPair; - -public class Controller implements ClassSelectionListener, CaretListener, RenameListener -{ - private Deobfuscator m_deobfuscator; - private Gui m_gui; - private SourceIndex m_index; - private ClassFile m_currentFile; - - public Controller( Deobfuscator deobfuscator, Gui gui ) - { - m_deobfuscator = deobfuscator; - m_gui = gui; - m_index = null; - m_currentFile = null; - - // update GUI - gui.setTitle( deobfuscator.getJarName() ); - gui.setObfClasses( deobfuscator.getObfuscatedClasses() ); - - // handle events - gui.setClassSelectionListener( this ); - gui.setCaretListener( this ); - gui.setRenameListener( this ); - } - - @Override - public void classSelected( ClassFile classFile ) - { - m_currentFile = classFile; - deobfuscate( m_currentFile ); - } - - @Override - public void caretUpdate( CaretEvent event ) - { - if( m_index != null ) - { - int pos = event.getDot(); - Entry deobfEntry = m_index.getEntry( pos ); - if( deobfEntry != null ) - { - m_gui.showEntryPair( new EntryPair( m_deobfuscator.obfuscate( deobfEntry ), deobfEntry ) ); - } - else - { - m_gui.clearEntryPair(); - } - } - } - - @Override - public void rename( Entry obfsEntry, String newName ) - { - m_deobfuscator.rename( obfsEntry, newName ); - - // did we rename the current file? - if( obfsEntry instanceof ClassEntry ) - { - ClassEntry classEntry = (ClassEntry)obfsEntry; - - // update the current file - if( classEntry.getName().equals( m_currentFile.getName() ) ) - { - m_currentFile = new ClassFile( newName ); - } - } - - deobfuscate( m_currentFile ); - } - - private void deobfuscate( final ClassFile classFile ) - { - m_gui.setSource( "(deobfuscating...)" ); - - // run the deobfuscator in a separate thread so we don't block the GUI event queue - new Thread( ) - { - @Override - public void run( ) - { - // deobfuscate the bytecode - String source = m_deobfuscator.getSource( classFile ); - m_gui.setSource( source ); - - // index the source file - m_index = Analyzer.analyze( classFile.getName(), source ); - m_gui.highlightTokens( m_index.tokens() ); - } - }.start(); - } -} diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java index b1abd9e..bc7065f 100644 --- a/src/cuchaz/enigma/Deobfuscator.java +++ b/src/cuchaz/enigma/Deobfuscator.java @@ -83,18 +83,13 @@ public class Deobfuscator Util.closeQuietly( jarIn ); } - // init mappings - m_mappings = new TranslationMappings( m_ancestries ); - // config the decompiler m_settings = DecompilerSettings.javaDefaults(); - m_settings.setTypeLoader( new TranslatingTypeLoader( - m_jar, - m_mappings.getTranslator( TranslationDirection.Deobfuscating ), - m_mappings.getTranslator( TranslationDirection.Obfuscating ) - ) ); m_settings.setForceExplicitImports( true ); m_settings.setShowSyntheticMembers( true ); + + // init mappings + setMappings( new TranslationMappings( m_ancestries ) ); } public String getJarName( ) @@ -102,6 +97,26 @@ public class Deobfuscator return m_file.getName(); } + public TranslationMappings getMappings( ) + { + return m_mappings; + } + public void setMappings( TranslationMappings val ) + { + if( val == null ) + { + val = new TranslationMappings( m_ancestries ); + } + m_mappings = val; + + // update decompiler options + m_settings.setTypeLoader( new TranslatingTypeLoader( + m_jar, + m_mappings.getTranslator( TranslationDirection.Deobfuscating ), + m_mappings.getTranslator( TranslationDirection.Obfuscating ) + ) ); + } + public List getObfuscatedClasses( ) { List classes = new ArrayList(); diff --git a/src/cuchaz/enigma/Main.java b/src/cuchaz/enigma/Main.java index 4842e20..6a300ed 100644 --- a/src/cuchaz/enigma/Main.java +++ b/src/cuchaz/enigma/Main.java @@ -19,16 +19,38 @@ public class Main public static void main( String[] args ) throws Exception { - startGui(); + Gui gui = new Gui(); + + // parse command-line args + if( args.length >= 1 ) + { + gui.getController().openJar( getFile( args[0] ) ); + } + if( args.length >= 2 ) + { + gui.getController().openMappings( getFile( args[1] ) ); + } } - private static void startGui( ) - throws Exception + private static File getFile( String path ) { - // settings - final File jarFile = new File( "/home/jeff/.minecraft/versions/1.7.10/1.7.10.jar" ); + // expand ~ to the home dir + if( path.startsWith( "~" ) ) + { + // get the home dir + File dirHome = new File( System.getProperty( "user.home" ) ); + + // is the path just ~/ or is it ~user/ ? + if( path.startsWith( "~/" ) ) + { + return new File( dirHome, path.substring( 2 ) ); + } + else + { + return new File( dirHome.getParentFile(), path.substring( 1 ) ); + } + } - // start the GUI and tie it to the deobfuscator - new Controller( new Deobfuscator( jarFile ), new Gui() ); + return new File( path ); } } diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 631089c..a86ff9b 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -20,6 +20,7 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.io.IOException; import java.util.List; import java.util.Vector; @@ -27,6 +28,7 @@ import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JEditorPane; +import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; @@ -39,6 +41,7 @@ import javax.swing.JSplitPane; import javax.swing.JTextField; import javax.swing.ListSelectionModel; import javax.swing.WindowConstants; +import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import javax.swing.text.BadLocationException; @@ -55,6 +58,8 @@ import cuchaz.enigma.mapping.MethodEntry; public class Gui { + private GuiController m_controller; + // controls private JFrame m_frame; private JList m_obfClasses; @@ -65,16 +70,28 @@ public class Gui private JLabel m_typeLabel; private JTextField m_nameField; private JButton m_renameButton; + private BoxHighlightPainter m_highlightPainter; - // listeners - private ClassSelectionListener m_classSelectionListener; - private RenameListener m_renameListener; + // dynamic menu items + private JMenuItem m_closeJarMenu; + private JMenuItem m_openMappingsMenu; + private JMenuItem m_saveMappingsMenu; + private JMenuItem m_saveMappingsAsMenu; + private JMenuItem m_closeMappingsMenu; - private BoxHighlightPainter m_highlightPainter; + // state private EntryPair m_selectedEntryPair; + private JFileChooser m_jarFileChooser; + private JFileChooser m_mappingFileChooser; public Gui( ) { + m_controller = new GuiController( this ); + + // init file choosers + m_jarFileChooser = new JFileChooser(); + m_mappingFileChooser = new JFileChooser(); + // init frame m_frame = new JFrame( Constants.Name ); final Container pane = m_frame.getContentPane(); @@ -91,13 +108,10 @@ public class Gui { if( event.getClickCount() == 2 ) { - if( m_classSelectionListener != null ) + ClassFile selected = m_obfClasses.getSelectedValue(); + if( selected != null ) { - ClassFile selected = m_obfClasses.getSelectedValue(); - if( selected != null ) - { - m_classSelectionListener.classSelected( selected ); - } + m_controller.deobfuscateClass( selected ); } } } @@ -130,9 +144,9 @@ public class Gui @Override public void actionPerformed( ActionEvent event ) { - if( m_renameListener != null && m_selectedEntryPair != null ) + if( m_selectedEntryPair != null ) { - m_renameListener.rename( m_selectedEntryPair.obf, m_nameField.getText() ); + m_controller.rename( m_selectedEntryPair.obf, m_nameField.getText() ); } } } ); @@ -148,10 +162,27 @@ public class Gui // init editor DefaultSyntaxKit.initKit(); + m_highlightPainter = new BoxHighlightPainter(); m_editor = new JEditorPane(); m_editor.setEditable( false ); JScrollPane sourceScroller = new JScrollPane( m_editor ); m_editor.setContentType( "text/java" ); + m_editor.addCaretListener( new CaretListener( ) + { + @Override + public void caretUpdate( CaretEvent event ) + { + m_selectedEntryPair = m_controller.getEntryPair( event.getDot() ); + if( m_selectedEntryPair != null ) + { + showEntryPair( m_selectedEntryPair ); + } + else + { + clearEntryPair(); + } + } + } ); // layout controls JSplitPane splitLeft = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, obfPanel, deobfPanel ); @@ -164,21 +195,147 @@ public class Gui // init menus JMenuBar menuBar = new JMenuBar(); - JMenu menu = new JMenu( "Help" ); - menu.setMnemonic( 'h' ); - JMenuItem item = new JMenuItem( "About" ); - item.setMnemonic( 'a' ); - item.addActionListener( new ActionListener( ) + m_frame.setJMenuBar( menuBar ); + { + JMenu menu = new JMenu( "File" ); + menuBar.add( menu ); + { + JMenuItem item = new JMenuItem( "Open Jar..." ); + menu.add( item ); + item.addActionListener( new ActionListener( ) + { + @Override + public void actionPerformed( ActionEvent event ) + { + if( m_jarFileChooser.showOpenDialog( m_frame ) == JFileChooser.APPROVE_OPTION ) + { + try + { + m_controller.openJar( m_jarFileChooser.getSelectedFile() ); + } + catch( IOException ex ) + { + throw new Error( ex ); + } + } + } + } ); + } + { + JMenuItem item = new JMenuItem( "Close Jar" ); + menu.add( item ); + item.addActionListener( new ActionListener( ) + { + @Override + public void actionPerformed( ActionEvent event ) + { + m_controller.closeJar(); + } + } ); + m_closeJarMenu = item; + } + menu.addSeparator(); + { + JMenuItem item = new JMenuItem( "Open Mappings..." ); + menu.add( item ); + item.addActionListener( new ActionListener( ) + { + @Override + public void actionPerformed( ActionEvent event ) + { + if( m_mappingFileChooser.showOpenDialog( m_frame ) == JFileChooser.APPROVE_OPTION ) + { + try + { + m_controller.openMappings( m_mappingFileChooser.getSelectedFile() ); + m_saveMappingsMenu.setEnabled( true ); + } + catch( IOException ex ) + { + throw new Error( ex ); + } + } + } + } ); + m_openMappingsMenu = item; + } + { + JMenuItem item = new JMenuItem( "Save Mappings" ); + menu.add( item ); + item.addActionListener( new ActionListener( ) + { + @Override + public void actionPerformed( ActionEvent event ) + { + try + { + m_controller.saveMappings( m_mappingFileChooser.getSelectedFile() ); + } + catch( IOException ex ) + { + throw new Error( ex ); + } + } + } ); + m_saveMappingsMenu = item; + } + { + JMenuItem item = new JMenuItem( "Save Mappings As..." ); + menu.add( item ); + item.addActionListener( new ActionListener( ) + { + @Override + public void actionPerformed( ActionEvent event ) { - @Override - public void actionPerformed( ActionEvent event ) + if( m_mappingFileChooser.showSaveDialog( m_frame ) == JFileChooser.APPROVE_OPTION ) { - AboutDialog.show( m_frame ); + try + { + m_controller.saveMappings( m_mappingFileChooser.getSelectedFile() ); + m_saveMappingsMenu.setEnabled( true ); + } + catch( IOException ex ) + { + throw new Error( ex ); + } } - } ); + } + } ); + m_saveMappingsAsMenu = item; + } + { + JMenuItem item = new JMenuItem( "Close Mapppings" ); menu.add( item ); + item.addActionListener( new ActionListener( ) + { + @Override + public void actionPerformed( ActionEvent event ) + { + m_controller.closeMappings(); + } + } ); + m_closeMappingsMenu = item; + } + } + { + JMenu menu = new JMenu( "Help" ); menuBar.add( menu ); - m_frame.setJMenuBar( menuBar ); + { + JMenuItem item = new JMenuItem( "About" ); + menu.add( item ); + item.addActionListener( new ActionListener( ) + { + @Override + public void actionPerformed( ActionEvent event ) + { + AboutDialog.show( m_frame ); + } + } ); + } + } + + // init state + onCloseJar(); // show the frame pane.doLayout(); @@ -186,22 +343,52 @@ public class Gui m_frame.setMinimumSize( new Dimension( 640, 480 ) ); m_frame.setVisible( true ); m_frame.setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE ); + } + + public GuiController getController( ) + { + return m_controller; + } + + public void onOpenJar( String jarName ) + { + // update gui + m_frame.setTitle( Constants.Name + " - " + jarName ); + setSource( null ); - // init listeners - m_classSelectionListener = null; - m_renameListener = null; - - m_highlightPainter = new BoxHighlightPainter(); + // update menu + m_closeJarMenu.setEnabled( true ); + m_openMappingsMenu.setEnabled( true ); + m_saveMappingsMenu.setEnabled( false ); + m_saveMappingsAsMenu.setEnabled( true ); + m_closeMappingsMenu.setEnabled( true ); } - public void setTitle( String title ) + public void onCloseJar( ) { - m_frame.setTitle( Constants.Name + " - " + title ); + // update gui + m_frame.setTitle( Constants.Name ); + setObfClasses( null ); + setSource( null ); + + // update menu + m_closeJarMenu.setEnabled( false ); + m_openMappingsMenu.setEnabled( false ); + m_saveMappingsMenu.setEnabled( false ); + m_saveMappingsAsMenu.setEnabled( false ); + m_closeMappingsMenu.setEnabled( false ); } public void setObfClasses( List classes ) { - m_obfClasses.setListData( new Vector( classes ) ); + if( classes != null ) + { + m_obfClasses.setListData( new Vector( classes ) ); + } + else + { + m_obfClasses.setListData( new Vector() ); + } } public void setSource( String source ) @@ -212,9 +399,10 @@ public class Gui public void setSource( String source, SourceIndex index ) { m_editor.setText( source ); + setHighlightedTokens( null ); } - public void highlightTokens( Iterable tokens ) + public void setHighlightedTokens( Iterable tokens ) { // remove any old highlighters m_editor.getHighlighter().removeAllHighlights(); @@ -240,28 +428,7 @@ public class Gui redraw(); } - public void setClassSelectionListener( ClassSelectionListener val ) - { - m_classSelectionListener = val; - } - - public void setRenameListener( RenameListener val ) - { - m_renameListener = val; - } - - public void setCaretListener( CaretListener listener ) - { - // remove any old listeners - for( CaretListener oldListener : m_editor.getCaretListeners() ) - { - m_editor.removeCaretListener( oldListener ); - } - - m_editor.addCaretListener( listener ); - } - - public void clearEntryPair( ) + private void clearEntryPair( ) { m_actionPanel.removeAll(); JLabel label = new JLabel( "No identifier selected" ); @@ -272,7 +439,7 @@ public class Gui redraw(); } - public void showEntryPair( EntryPair pair ) + private void showEntryPair( EntryPair pair ) { if( pair == null ) { @@ -280,9 +447,6 @@ public class Gui return; } - // TEMP - System.out.println( "Pair:\n" + pair.obf + "\n" + pair.deobf ); - m_selectedEntryPair = pair; // layout the action panel diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java new file mode 100644 index 0000000..5df2d43 --- /dev/null +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * 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.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; + +import cuchaz.enigma.ClassFile; +import cuchaz.enigma.Deobfuscator; +import cuchaz.enigma.analysis.Analyzer; +import cuchaz.enigma.analysis.SourceIndex; +import cuchaz.enigma.mapping.ClassEntry; +import cuchaz.enigma.mapping.Entry; +import cuchaz.enigma.mapping.EntryPair; +import cuchaz.enigma.mapping.TranslationMappings; + +public class GuiController +{ + private Deobfuscator m_deobfuscator; + private Gui m_gui; + private SourceIndex m_index; + private ClassFile m_currentFile; + + public GuiController( Gui gui ) + { + m_gui = gui; + m_deobfuscator = null; + m_index = null; + m_currentFile = null; + } + + public void openJar( File file ) + throws IOException + { + m_deobfuscator = new Deobfuscator( file ); + m_gui.onOpenJar( m_deobfuscator.getJarName() ); + m_gui.setObfClasses( m_deobfuscator.getObfuscatedClasses() ); + } + + public void closeJar( ) + { + m_deobfuscator = null; + m_gui.onCloseJar(); + } + + public void openMappings( File file ) + throws IOException + { + FileInputStream in = new FileInputStream( file ); + m_deobfuscator.setMappings( TranslationMappings.newFromStream( in ) ); + in.close(); + refreshOpenFiles(); + } + + public void saveMappings( File file ) + throws IOException + { + FileOutputStream out = new FileOutputStream( file ); + m_deobfuscator.getMappings().write( out ); + out.close(); + } + + public void closeMappings( ) + { + m_deobfuscator.setMappings( null ); + refreshOpenFiles(); + } + + public void deobfuscateClass( ClassFile classFile ) + { + m_currentFile = classFile; + deobfuscate( m_currentFile ); + } + + public EntryPair getEntryPair( int pos ) + { + if( m_index == null ) + { + return null; + } + + Entry deobfEntry = m_index.getEntry( pos ); + if( deobfEntry == null ) + { + return null; + } + return new EntryPair( m_deobfuscator.obfuscate( deobfEntry ), deobfEntry ); + } + + public void rename( Entry obfsEntry, String newName ) + { + m_deobfuscator.rename( obfsEntry, newName ); + + // did we rename the current file? + if( obfsEntry instanceof ClassEntry ) + { + ClassEntry classEntry = (ClassEntry)obfsEntry; + + // update the current file + if( classEntry.getName().equals( m_currentFile.getName() ) ) + { + m_currentFile = new ClassFile( newName ); + } + } + + refreshOpenFiles(); + } + + private void refreshOpenFiles( ) + { + if( m_currentFile != null ) + { + deobfuscate( m_currentFile ); + } + } + + private void deobfuscate( final ClassFile classFile ) + { + m_gui.setSource( "(deobfuscating...)" ); + + // run the deobfuscator in a separate thread so we don't block the GUI event queue + new Thread( ) + { + @Override + public void run( ) + { + // deobfuscate the bytecode + String source = m_deobfuscator.getSource( classFile ); + m_gui.setSource( source ); + + // index the source file + m_index = Analyzer.analyze( classFile.getName(), source ); + m_gui.setHighlightedTokens( m_index.tokens() ); + } + }.start(); + } +} -- cgit v1.2.3