();
+ ancestry.add( className );
+ ancestry.addAll( m_ancestries.getAncestry( className ) );
+ return ancestry;
+ }
+}
--
cgit v1.2.3
From 1318888e5b37a2d76270c5c330e63d4b5dcf779e Mon Sep 17 00:00:00 2001
From: jeff
Date: Tue, 29 Jul 2014 00:37:51 -0400
Subject: added start of menu bar added about bow
---
conf/about.html | 6 +++
src/cuchaz/enigma/Constants.java | 3 ++
src/cuchaz/enigma/Util.java | 44 +++++++++++++++++
src/cuchaz/enigma/gui/AboutDialog.java | 86 ++++++++++++++++++++++++++++++++++
src/cuchaz/enigma/gui/Gui.java | 28 +++++++++--
5 files changed, 163 insertions(+), 4 deletions(-)
create mode 100644 conf/about.html
create mode 100644 src/cuchaz/enigma/gui/AboutDialog.java
diff --git a/conf/about.html b/conf/about.html
new file mode 100644
index 00000000..b75c1bf0
--- /dev/null
+++ b/conf/about.html
@@ -0,0 +1,6 @@
+
+ %s
+ A tool for debofuscation of Java code
+
+
Version: %s
+
\ No newline at end of file
diff --git a/src/cuchaz/enigma/Constants.java b/src/cuchaz/enigma/Constants.java
index 09787145..a8c4f44c 100644
--- a/src/cuchaz/enigma/Constants.java
+++ b/src/cuchaz/enigma/Constants.java
@@ -13,6 +13,9 @@ package cuchaz.enigma;
public class Constants
{
+ public static final String Name = "Enigma";
+ public static final String Version = "0.1";
+ public static final String Url = "http://www.cuchazinteractive.com/enigma";
public static final int MiB = 1024*1024; // 1 mebibyte
public static final int KiB = 1024; // 1 kebibyte
}
diff --git a/src/cuchaz/enigma/Util.java b/src/cuchaz/enigma/Util.java
index c51eb621..84927fd9 100644
--- a/src/cuchaz/enigma/Util.java
+++ b/src/cuchaz/enigma/Util.java
@@ -10,10 +10,17 @@
******************************************************************************/
package cuchaz.enigma;
+import java.awt.Desktop;
import java.io.Closeable;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.util.jar.JarFile;
+import com.google.common.io.CharStreams;
+
public class Util
{
@@ -62,4 +69,41 @@ public class Util
}
}
}
+
+ public static String readStreamToString( InputStream in )
+ throws IOException
+ {
+ return CharStreams.toString( new InputStreamReader( in, "UTF-8" ) );
+ }
+
+ public static String readResourceToString( String path )
+ throws IOException
+ {
+ InputStream in = Util.class.getResourceAsStream( path );
+ if( in == null )
+ {
+ throw new IllegalArgumentException( "Resource not found! " + path );
+ }
+ return readStreamToString( in );
+ }
+
+ public static void openUrl( String url )
+ {
+ if( Desktop.isDesktopSupported() )
+ {
+ Desktop desktop = Desktop.getDesktop();
+ try
+ {
+ desktop.browse( new URI( url ) );
+ }
+ catch( IOException ex )
+ {
+ throw new Error( ex );
+ }
+ catch( URISyntaxException ex )
+ {
+ throw new IllegalArgumentException( ex );
+ }
+ }
+ }
}
diff --git a/src/cuchaz/enigma/gui/AboutDialog.java b/src/cuchaz/enigma/gui/AboutDialog.java
new file mode 100644
index 00000000..2584182f
--- /dev/null
+++ b/src/cuchaz/enigma/gui/AboutDialog.java
@@ -0,0 +1,86 @@
+package cuchaz.enigma.gui;
+
+import java.awt.Color;
+import java.awt.Container;
+import java.awt.Cursor;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.IOException;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.WindowConstants;
+
+import cuchaz.enigma.Constants;
+import cuchaz.enigma.Util;
+
+public class AboutDialog
+{
+ public static void show( JFrame parent )
+ {
+ // init frame
+ final JFrame frame = new JFrame( Constants.Name + " - About" );
+ final Container pane = frame.getContentPane();
+ pane.setLayout( new FlowLayout() );
+
+ // load the content
+ try
+ {
+ String html = Util.readResourceToString( "/about.html" );
+ html = String.format( html, Constants.Name, Constants.Version );
+ JLabel label = new JLabel( html );
+ label.setHorizontalAlignment( JLabel.CENTER );
+ pane.add( label );
+ }
+ catch( IOException ex )
+ {
+ throw new Error( ex );
+ }
+
+ // show the link
+ String html = "%s";
+ html = String.format( html, Constants.Url, Constants.Url );
+ JButton link = new JButton( html );
+ link.addActionListener( new ActionListener( )
+ {
+ @Override
+ public void actionPerformed( ActionEvent event )
+ {
+ Util.openUrl( Constants.Url );
+ }
+ } );
+ link.setBorderPainted( false );
+ link.setOpaque( false );
+ link.setBackground( Color.WHITE );
+ link.setCursor( new Cursor( Cursor.HAND_CURSOR ) );
+ link.setFocusable( false );
+ JPanel linkPanel = new JPanel();
+ linkPanel.add( link );
+ pane.add( linkPanel );
+
+ // show ok button
+ JButton okButton = new JButton( "Ok" );
+ pane.add( okButton );
+ okButton.addActionListener( new ActionListener( )
+ {
+ @Override
+ public void actionPerformed( ActionEvent arg0 )
+ {
+ frame.dispose();
+ }
+ } );
+
+ // show the frame
+ pane.doLayout();
+ frame.setSize( 400, 220 );
+ frame.setResizable( false );
+ frame.setLocationRelativeTo( parent );
+ frame.setVisible( true );
+ frame.setDefaultCloseOperation( WindowConstants.DISPOSE_ON_CLOSE );
+ }
+}
diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java
index 2a539a3f..631089c4 100644
--- a/src/cuchaz/enigma/gui/Gui.java
+++ b/src/cuchaz/enigma/gui/Gui.java
@@ -30,6 +30,9 @@ import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
@@ -42,6 +45,7 @@ import javax.swing.text.BadLocationException;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.Token;
import cuchaz.enigma.ClassFile;
+import cuchaz.enigma.Constants;
import cuchaz.enigma.analysis.SourceIndex;
import cuchaz.enigma.mapping.ArgumentEntry;
import cuchaz.enigma.mapping.ClassEntry;
@@ -51,8 +55,6 @@ import cuchaz.enigma.mapping.MethodEntry;
public class Gui
{
- private static final String Name = "Enigma";
-
// controls
private JFrame m_frame;
private JList m_obfClasses;
@@ -74,7 +76,7 @@ public class Gui
public Gui( )
{
// init frame
- m_frame = new JFrame( Name );
+ m_frame = new JFrame( Constants.Name );
final Container pane = m_frame.getContentPane();
pane.setLayout( new BorderLayout() );
@@ -160,6 +162,24 @@ public class Gui
JSplitPane splitMain = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, splitLeft, rightPanel );
pane.add( splitMain, BorderLayout.CENTER );
+ // 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( )
+ {
+ @Override
+ public void actionPerformed( ActionEvent event )
+ {
+ AboutDialog.show( m_frame );
+ }
+ } );
+ menu.add( item );
+ menuBar.add( menu );
+ m_frame.setJMenuBar( menuBar );
+
// show the frame
pane.doLayout();
m_frame.setSize( 800, 600 );
@@ -176,7 +196,7 @@ public class Gui
public void setTitle( String title )
{
- m_frame.setTitle( Name + " - " + title );
+ m_frame.setTitle( Constants.Name + " - " + title );
}
public void setObfClasses( List classes )
--
cgit v1.2.3
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
diff --git a/src/cuchaz/enigma/Controller.java b/src/cuchaz/enigma/Controller.java
deleted file mode 100644
index 3af139e8..00000000
--- 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 b1abd9e0..bc7065fd 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 4842e208..6a300ed6 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 631089c4..a86ff9b0 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 00000000..5df2d434
--- /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
From bb4525e1fbeb2b94ff8e3f84d9e627d67f9c54b1 Mon Sep 17 00:00:00 2001
From: jeff
Date: Tue, 29 Jul 2014 23:24:01 -0400
Subject: forgot to apply copyright notices
---
src/cuchaz/enigma/gui/AboutDialog.java | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/src/cuchaz/enigma/gui/AboutDialog.java b/src/cuchaz/enigma/gui/AboutDialog.java
index 2584182f..79b75432 100644
--- a/src/cuchaz/enigma/gui/AboutDialog.java
+++ b/src/cuchaz/enigma/gui/AboutDialog.java
@@ -1,3 +1,13 @@
+/*******************************************************************************
+ * 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.Color;
--
cgit v1.2.3
From 4349d22cc8abf5ec74075dde1b45c5f2f8679bbf Mon Sep 17 00:00:00 2001
From: jeff
Date: Wed, 30 Jul 2014 23:43:09 -0400
Subject: switched to line-by-line mergable, human-readable file format for
mappings
---
src/cuchaz/enigma/Deobfuscator.java | 31 +--
src/cuchaz/enigma/gui/GuiController.java | 17 +-
src/cuchaz/enigma/mapping/ArgumentIndex.java | 41 ----
src/cuchaz/enigma/mapping/ArgumentMapping.java | 42 ++++
src/cuchaz/enigma/mapping/ClassIndex.java | 159 ---------------
src/cuchaz/enigma/mapping/ClassMapping.java | 217 +++++++++++++++++++++
.../enigma/mapping/DeobfuscatedAncestries.java | 8 +-
src/cuchaz/enigma/mapping/FieldEntry.java | 1 +
src/cuchaz/enigma/mapping/FieldMapping.java | 41 ++++
src/cuchaz/enigma/mapping/Mappings.java | 128 ++++++++++++
src/cuchaz/enigma/mapping/MappingsReader.java | 129 ++++++++++++
src/cuchaz/enigma/mapping/MappingsWriter.java | 75 +++++++
src/cuchaz/enigma/mapping/MethodIndex.java | 125 ------------
src/cuchaz/enigma/mapping/MethodMapping.java | 136 +++++++++++++
src/cuchaz/enigma/mapping/Renamer.java | 125 ++++++++++++
src/cuchaz/enigma/mapping/TranslationMappings.java | 187 ------------------
src/cuchaz/enigma/mapping/Translator.java | 16 +-
17 files changed, 933 insertions(+), 545 deletions(-)
delete mode 100644 src/cuchaz/enigma/mapping/ArgumentIndex.java
create mode 100644 src/cuchaz/enigma/mapping/ArgumentMapping.java
delete mode 100644 src/cuchaz/enigma/mapping/ClassIndex.java
create mode 100644 src/cuchaz/enigma/mapping/ClassMapping.java
create mode 100644 src/cuchaz/enigma/mapping/FieldMapping.java
create mode 100644 src/cuchaz/enigma/mapping/Mappings.java
create mode 100644 src/cuchaz/enigma/mapping/MappingsReader.java
create mode 100644 src/cuchaz/enigma/mapping/MappingsWriter.java
delete mode 100644 src/cuchaz/enigma/mapping/MethodIndex.java
create mode 100644 src/cuchaz/enigma/mapping/MethodMapping.java
create mode 100644 src/cuchaz/enigma/mapping/Renamer.java
delete mode 100644 src/cuchaz/enigma/mapping/TranslationMappings.java
diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java
index bc7065fd..7be57062 100644
--- a/src/cuchaz/enigma/Deobfuscator.java
+++ b/src/cuchaz/enigma/Deobfuscator.java
@@ -32,9 +32,10 @@ import cuchaz.enigma.mapping.ArgumentEntry;
import cuchaz.enigma.mapping.ClassEntry;
import cuchaz.enigma.mapping.Entry;
import cuchaz.enigma.mapping.FieldEntry;
+import cuchaz.enigma.mapping.Mappings;
import cuchaz.enigma.mapping.MethodEntry;
+import cuchaz.enigma.mapping.Renamer;
import cuchaz.enigma.mapping.TranslationDirection;
-import cuchaz.enigma.mapping.TranslationMappings;
import cuchaz.enigma.mapping.Translator;
public class Deobfuscator
@@ -43,7 +44,8 @@ public class Deobfuscator
private JarFile m_jar;
private DecompilerSettings m_settings;
private Ancestries m_ancestries;
- private TranslationMappings m_mappings;
+ private Mappings m_mappings;
+ private Renamer m_renamer;
private static Comparator m_obfuscatedClassSorter;
@@ -89,7 +91,7 @@ public class Deobfuscator
m_settings.setShowSyntheticMembers( true );
// init mappings
- setMappings( new TranslationMappings( m_ancestries ) );
+ setMappings( new Mappings() );
}
public String getJarName( )
@@ -97,23 +99,24 @@ public class Deobfuscator
return m_file.getName();
}
- public TranslationMappings getMappings( )
+ public Mappings getMappings( )
{
return m_mappings;
}
- public void setMappings( TranslationMappings val )
+ public void setMappings( Mappings val )
{
if( val == null )
{
- val = new TranslationMappings( m_ancestries );
+ val = new Mappings();
}
m_mappings = val;
+ m_renamer = new Renamer( m_ancestries, m_mappings );
// update decompiler options
m_settings.setTypeLoader( new TranslatingTypeLoader(
m_jar,
- m_mappings.getTranslator( TranslationDirection.Deobfuscating ),
- m_mappings.getTranslator( TranslationDirection.Obfuscating )
+ m_mappings.getTranslator( m_ancestries, TranslationDirection.Deobfuscating ),
+ m_mappings.getTranslator( m_ancestries, TranslationDirection.Obfuscating )
) );
}
@@ -168,19 +171,19 @@ public class Deobfuscator
{
if( entry instanceof ClassEntry )
{
- m_mappings.setClassName( (ClassEntry)entry, newName );
+ m_renamer.setClassName( (ClassEntry)entry, newName );
}
else if( entry instanceof FieldEntry )
{
- m_mappings.setFieldName( (FieldEntry)entry, newName );
+ m_renamer.setFieldName( (FieldEntry)entry, newName );
}
else if( entry instanceof MethodEntry )
{
- m_mappings.setMethodName( (MethodEntry)entry, newName );
+ m_renamer.setMethodName( (MethodEntry)entry, newName );
}
else if( entry instanceof ArgumentEntry )
{
- m_mappings.setArgumentName( (ArgumentEntry)entry, newName );
+ m_renamer.setArgumentName( (ArgumentEntry)entry, newName );
}
else
{
@@ -190,7 +193,7 @@ public class Deobfuscator
public Entry obfuscate( Entry in )
{
- Translator translator = m_mappings.getTranslator( TranslationDirection.Obfuscating );
+ Translator translator = m_mappings.getTranslator( m_ancestries, TranslationDirection.Obfuscating );
if( in instanceof ClassEntry )
{
return translator.translateEntry( (ClassEntry)in );
@@ -215,7 +218,7 @@ public class Deobfuscator
public Entry deobfuscate( Entry in )
{
- Translator translator = m_mappings.getTranslator( TranslationDirection.Deobfuscating );
+ Translator translator = m_mappings.getTranslator( m_ancestries, TranslationDirection.Deobfuscating );
if( in instanceof ClassEntry )
{
return translator.translateEntry( (ClassEntry)in );
diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java
index 5df2d434..fb22b961 100644
--- a/src/cuchaz/enigma/gui/GuiController.java
+++ b/src/cuchaz/enigma/gui/GuiController.java
@@ -11,8 +11,8 @@
package cuchaz.enigma.gui;
import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
import java.io.IOException;
import cuchaz.enigma.ClassFile;
@@ -22,7 +22,8 @@ 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;
+import cuchaz.enigma.mapping.MappingsReader;
+import cuchaz.enigma.mapping.MappingsWriter;
public class GuiController
{
@@ -56,17 +57,19 @@ public class GuiController
public void openMappings( File file )
throws IOException
{
- FileInputStream in = new FileInputStream( file );
- m_deobfuscator.setMappings( TranslationMappings.newFromStream( in ) );
+ FileReader in = new FileReader( file );
+ m_deobfuscator.setMappings( new MappingsReader().read( in ) );
in.close();
+ // TEMP
+ System.out.println( m_deobfuscator.getMappings() );
refreshOpenFiles();
}
public void saveMappings( File file )
throws IOException
{
- FileOutputStream out = new FileOutputStream( file );
- m_deobfuscator.getMappings().write( out );
+ FileWriter out = new FileWriter( file );
+ new MappingsWriter().write( out, m_deobfuscator.getMappings() );
out.close();
}
diff --git a/src/cuchaz/enigma/mapping/ArgumentIndex.java b/src/cuchaz/enigma/mapping/ArgumentIndex.java
deleted file mode 100644
index 57488d14..00000000
--- a/src/cuchaz/enigma/mapping/ArgumentIndex.java
+++ /dev/null
@@ -1,41 +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.mapping;
-
-import java.io.Serializable;
-
-public class ArgumentIndex implements Serializable
-{
- private static final long serialVersionUID = 8610742471440861315L;
-
- private String m_obfName;
- private String m_deobfName;
-
- public ArgumentIndex( String obfName, String deobfName )
- {
- m_obfName = obfName;
- m_deobfName = deobfName;
- }
-
- public String getObfName( )
- {
- return m_obfName;
- }
-
- public String getDeobfName( )
- {
- return m_deobfName;
- }
- public void setDeobfName( String val )
- {
- m_deobfName = val;
- }
-}
diff --git a/src/cuchaz/enigma/mapping/ArgumentMapping.java b/src/cuchaz/enigma/mapping/ArgumentMapping.java
new file mode 100644
index 00000000..d5e020a6
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/ArgumentMapping.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * 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.mapping;
+
+import java.io.Serializable;
+
+public class ArgumentMapping implements Serializable
+{
+ private static final long serialVersionUID = 8610742471440861315L;
+
+ private int m_index;
+ private String m_name;
+
+ // NOTE: this argument order is important for the MethodReader/MethodWriter
+ public ArgumentMapping( int index, String name )
+ {
+ m_index = index;
+ m_name = name;
+ }
+
+ public int getIndex( )
+ {
+ return m_index;
+ }
+
+ public String getName( )
+ {
+ return m_name;
+ }
+ public void setName( String val )
+ {
+ m_name = val;
+ }
+}
diff --git a/src/cuchaz/enigma/mapping/ClassIndex.java b/src/cuchaz/enigma/mapping/ClassIndex.java
deleted file mode 100644
index 699807b8..00000000
--- a/src/cuchaz/enigma/mapping/ClassIndex.java
+++ /dev/null
@@ -1,159 +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.mapping;
-
-import java.io.Serializable;
-import java.util.Map;
-
-import com.beust.jcommander.internal.Maps;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.HashBiMap;
-
-public class ClassIndex implements Serializable
-{
- private static final long serialVersionUID = -5148491146902340107L;
-
- private String m_obfName;
- private String m_deobfName;
- private BiMap m_fieldsObfToDeobf;
- private Map m_methodsByObf;
- private Map m_methodsByDeobf;
-
- public ClassIndex( String obfName, String deobfName )
- {
- m_obfName = obfName;
- m_deobfName = deobfName;
- m_fieldsObfToDeobf = HashBiMap.create();
- m_methodsByObf = Maps.newHashMap();
- m_methodsByDeobf = Maps.newHashMap();
- }
-
- public String getObfName( )
- {
- return m_obfName;
- }
-
- public String getDeobfName( )
- {
- return m_deobfName;
- }
- public void setDeobfName( String val )
- {
- m_deobfName = val;
- }
-
- public String getObfFieldName( String deobfName )
- {
- return m_fieldsObfToDeobf.inverse().get( deobfName );
- }
-
- public String getDeobfFieldName( String obfName )
- {
- return m_fieldsObfToDeobf.get( obfName );
- }
-
- public void setFieldName( String obfName, String deobfName )
- {
- m_fieldsObfToDeobf.put( obfName, deobfName );
- }
-
- public MethodIndex getMethodByObf( String obfName, String signature )
- {
- return m_methodsByObf.get( getMethodKey( obfName, signature ) );
- }
-
- public MethodIndex getMethodByDeobf( String deobfName, String signature )
- {
- return m_methodsByDeobf.get( getMethodKey( deobfName, signature ) );
- }
-
- private String getMethodKey( String name, String signature )
- {
- return name + signature;
- }
-
- public void setMethodNameAndSignature( String obfName, String obfSignature, String deobfName, String deobfSignature )
- {
- if( deobfName == null )
- {
- throw new IllegalArgumentException( "deobf name cannot be null!" );
- }
-
- MethodIndex methodIndex = m_methodsByObf.get( getMethodKey( obfName, obfSignature ) );
- if( methodIndex == null )
- {
- methodIndex = createMethodIndex( obfName, obfSignature );
- }
-
- m_methodsByDeobf.remove( getMethodKey( methodIndex.getDeobfName(), methodIndex.getDeobfSignature() ) );
- methodIndex.setDeobfName( deobfName );
- methodIndex.setDeobfSignature( deobfSignature );
- m_methodsByDeobf.put( getMethodKey( deobfName, deobfSignature ), methodIndex );
- }
-
- public void updateDeobfMethodSignatures( Translator translator )
- {
- for( MethodIndex methodIndex : m_methodsByObf.values() )
- {
- methodIndex.setDeobfSignature( translator.translateSignature( methodIndex.getObfSignature() ) );
- }
- }
-
- public void setArgumentName( String obfMethodName, String obfMethodSignature, int index, String obfName, String deobfName )
- {
- if( deobfName == null )
- {
- throw new IllegalArgumentException( "deobf name cannot be null!" );
- }
-
- MethodIndex methodIndex = m_methodsByObf.get( getMethodKey( obfMethodName, obfMethodSignature ) );
- if( methodIndex == null )
- {
- methodIndex = createMethodIndex( obfMethodName, obfMethodSignature );
- }
- methodIndex.setArgumentName( index, obfName, deobfName );
- }
-
- private MethodIndex createMethodIndex( String obfName, String obfSignature )
- {
- MethodIndex methodIndex = new MethodIndex( obfName, obfSignature, obfName, obfSignature );
- String key = getMethodKey( obfName, obfSignature );
- m_methodsByObf.put( key, methodIndex );
- m_methodsByDeobf.put( key, methodIndex );
- return methodIndex;
- }
-
- @Override
- public String toString( )
- {
- StringBuilder buf = new StringBuilder();
- buf.append( m_obfName );
- buf.append( " <-> " );
- buf.append( m_deobfName );
- buf.append( "\n" );
- buf.append( "Fields:\n" );
- for( Map.Entry entry : m_fieldsObfToDeobf.entrySet() )
- {
- buf.append( "\t" );
- buf.append( entry.getKey() );
- buf.append( " <-> " );
- buf.append( entry.getValue() );
- buf.append( "\n" );
- }
- buf.append( "Methods:\n" );
- for( MethodIndex methodIndex : m_methodsByObf.values() )
- {
- buf.append( methodIndex.toString() );
- buf.append( "\n" );
- }
- return buf.toString();
- }
-}
diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java
new file mode 100644
index 00000000..3ba3569f
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/ClassMapping.java
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ * 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.mapping;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import com.beust.jcommander.internal.Maps;
+
+public class ClassMapping implements Serializable
+{
+ private static final long serialVersionUID = -5148491146902340107L;
+
+ private String m_obfName;
+ private String m_deobfName;
+ private Map m_fieldsByObf;
+ private Map m_fieldsByDeobf;
+ private Map m_methodsByObf;
+ private Map m_methodsByDeobf;
+
+ // NOTE: this argument order is important for the MethodReader/MethodWriter
+ public ClassMapping( String obfName, String deobfName )
+ {
+ m_obfName = obfName;
+ m_deobfName = deobfName;
+ m_fieldsByObf = Maps.newHashMap();
+ m_fieldsByDeobf = Maps.newHashMap();
+ m_methodsByObf = Maps.newHashMap();
+ m_methodsByDeobf = Maps.newHashMap();
+ }
+
+ public String getObfName( )
+ {
+ return m_obfName;
+ }
+
+ public String getDeobfName( )
+ {
+ return m_deobfName;
+ }
+ public void setDeobfName( String val )
+ {
+ m_deobfName = val;
+ }
+
+ public Iterable fields( )
+ {
+ assert( m_fieldsByObf.size() == m_fieldsByDeobf.size() );
+ return m_fieldsByObf.values();
+ }
+
+ protected void addFieldMapping( FieldMapping fieldMapping )
+ {
+ m_fieldsByObf.put( fieldMapping.getObfName(), fieldMapping );
+ m_fieldsByDeobf.put( fieldMapping.getDeobfName(), fieldMapping );
+ }
+
+ public Iterable methods( )
+ {
+ assert( m_methodsByObf.size() == m_methodsByDeobf.size() );
+ return m_methodsByObf.values();
+ }
+
+ protected void addMethodMapping( MethodMapping methodMapping )
+ {
+ m_methodsByObf.put( getMethodKey( methodMapping.getObfName(), methodMapping.getObfSignature() ), methodMapping );
+ m_methodsByDeobf.put( getMethodKey( methodMapping.getDeobfName(), methodMapping.getDeobfSignature() ), methodMapping );
+ }
+
+ public String getObfFieldName( String deobfName )
+ {
+ FieldMapping fieldMapping = m_fieldsByDeobf.get( deobfName );
+ if( fieldMapping != null )
+ {
+ return fieldMapping.getObfName();
+ }
+ return null;
+ }
+
+ public String getDeobfFieldName( String obfName )
+ {
+ FieldMapping fieldMapping = m_fieldsByObf.get( obfName );
+ if( fieldMapping != null )
+ {
+ return fieldMapping.getDeobfName();
+ }
+ return null;
+ }
+
+ public void setFieldName( String obfName, String deobfName )
+ {
+ if( deobfName == null )
+ {
+ throw new IllegalArgumentException( "deobf name cannot be null!" );
+ }
+
+ FieldMapping fieldMapping = m_fieldsByObf.get( obfName );
+ if( fieldMapping == null )
+ {
+ fieldMapping = new FieldMapping( obfName, deobfName );
+ m_fieldsByObf.put( obfName, fieldMapping );
+ m_fieldsByDeobf.put( deobfName, fieldMapping );
+ }
+
+ m_fieldsByDeobf.remove( fieldMapping.getDeobfName() );
+ fieldMapping.setDeobfName( deobfName );
+ m_fieldsByDeobf.put( deobfName, fieldMapping );
+ }
+
+ public MethodMapping getMethodByObf( String obfName, String signature )
+ {
+ return m_methodsByObf.get( getMethodKey( obfName, signature ) );
+ }
+
+ public MethodMapping getMethodByDeobf( String deobfName, String signature )
+ {
+ return m_methodsByDeobf.get( getMethodKey( deobfName, signature ) );
+ }
+
+ private String getMethodKey( String name, String signature )
+ {
+ if( name == null )
+ {
+ throw new IllegalArgumentException( "name cannot be null!" );
+ }
+ if( signature == null )
+ {
+ throw new IllegalArgumentException( "signature cannot be null!" );
+ }
+ return name + signature;
+ }
+
+ public void setMethodNameAndSignature( String obfName, String obfSignature, String deobfName, String deobfSignature )
+ {
+ if( deobfName == null )
+ {
+ throw new IllegalArgumentException( "deobf name cannot be null!" );
+ }
+
+ MethodMapping methodIndex = m_methodsByObf.get( getMethodKey( obfName, obfSignature ) );
+ if( methodIndex == null )
+ {
+ methodIndex = createMethodIndex( obfName, obfSignature );
+ }
+
+ m_methodsByDeobf.remove( getMethodKey( methodIndex.getDeobfName(), methodIndex.getDeobfSignature() ) );
+ methodIndex.setDeobfName( deobfName );
+ methodIndex.setDeobfSignature( deobfSignature );
+ m_methodsByDeobf.put( getMethodKey( deobfName, deobfSignature ), methodIndex );
+ }
+
+ public void updateDeobfMethodSignatures( Translator translator )
+ {
+ for( MethodMapping methodIndex : m_methodsByObf.values() )
+ {
+ methodIndex.setDeobfSignature( translator.translateSignature( methodIndex.getObfSignature() ) );
+ }
+ }
+
+ public void setArgumentName( String obfMethodName, String obfMethodSignature, int argumentIndex, String argumentName )
+ {
+ if( argumentName == null )
+ {
+ throw new IllegalArgumentException( "argument name cannot be null!" );
+ }
+
+ MethodMapping methodIndex = m_methodsByObf.get( getMethodKey( obfMethodName, obfMethodSignature ) );
+ if( methodIndex == null )
+ {
+ methodIndex = createMethodIndex( obfMethodName, obfMethodSignature );
+ }
+ methodIndex.setArgumentName( argumentIndex, argumentName );
+ }
+
+ private MethodMapping createMethodIndex( String obfName, String obfSignature )
+ {
+ MethodMapping methodIndex = new MethodMapping( obfName, obfName, obfSignature, obfSignature );
+ String key = getMethodKey( obfName, obfSignature );
+ m_methodsByObf.put( key, methodIndex );
+ m_methodsByDeobf.put( key, methodIndex );
+ return methodIndex;
+ }
+
+ @Override
+ public String toString( )
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( m_obfName );
+ buf.append( " <-> " );
+ buf.append( m_deobfName );
+ buf.append( "\n" );
+ buf.append( "Fields:\n" );
+ for( FieldMapping fieldMapping : fields() )
+ {
+ buf.append( "\t" );
+ buf.append( fieldMapping.getObfName() );
+ buf.append( " <-> " );
+ buf.append( fieldMapping.getDeobfName() );
+ buf.append( "\n" );
+ }
+ buf.append( "Methods:\n" );
+ for( MethodMapping methodIndex : m_methodsByObf.values() )
+ {
+ buf.append( methodIndex.toString() );
+ buf.append( "\n" );
+ }
+ return buf.toString();
+ }
+}
diff --git a/src/cuchaz/enigma/mapping/DeobfuscatedAncestries.java b/src/cuchaz/enigma/mapping/DeobfuscatedAncestries.java
index 5320f110..dcb0741a 100644
--- a/src/cuchaz/enigma/mapping/DeobfuscatedAncestries.java
+++ b/src/cuchaz/enigma/mapping/DeobfuscatedAncestries.java
@@ -17,10 +17,10 @@ public class DeobfuscatedAncestries extends Ancestries
private static final long serialVersionUID = 8316248774892618324L;
private Ancestries m_ancestries;
- private Map m_classesByObf;
- private Map m_classesByDeobf;
+ private Map m_classesByObf;
+ private Map m_classesByDeobf;
- protected DeobfuscatedAncestries( Ancestries ancestries, Map classesByObf, Map classesByDeobf )
+ protected DeobfuscatedAncestries( Ancestries ancestries, Map classesByObf, Map classesByDeobf )
{
m_ancestries = ancestries;
m_classesByObf = classesByObf;
@@ -31,7 +31,7 @@ public class DeobfuscatedAncestries extends Ancestries
public String getSuperclassName( String deobfClassName )
{
// obfuscate the class name
- ClassIndex classIndex = m_classesByDeobf.get( deobfClassName );
+ ClassMapping classIndex = m_classesByDeobf.get( deobfClassName );
if( classIndex == null )
{
return null;
diff --git a/src/cuchaz/enigma/mapping/FieldEntry.java b/src/cuchaz/enigma/mapping/FieldEntry.java
index b9f42394..eefc4c4c 100644
--- a/src/cuchaz/enigma/mapping/FieldEntry.java
+++ b/src/cuchaz/enigma/mapping/FieldEntry.java
@@ -21,6 +21,7 @@ public class FieldEntry implements Entry, Serializable
private ClassEntry m_classEntry;
private String m_name;
+ // NOTE: this argument order is important for the MethodReader/MethodWriter
public FieldEntry( ClassEntry classEntry, String name )
{
if( classEntry == null )
diff --git a/src/cuchaz/enigma/mapping/FieldMapping.java b/src/cuchaz/enigma/mapping/FieldMapping.java
new file mode 100644
index 00000000..618f45c6
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/FieldMapping.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * 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.mapping;
+
+import java.io.Serializable;
+
+public class FieldMapping implements Serializable
+{
+ private static final long serialVersionUID = 8610742471440861315L;
+
+ private String m_obfName;
+ private String m_deobfName;
+
+ public FieldMapping( String obfName, String deobfName )
+ {
+ m_obfName = obfName;
+ m_deobfName = deobfName;
+ }
+
+ public String getObfName( )
+ {
+ return m_obfName;
+ }
+
+ public String getDeobfName( )
+ {
+ return m_deobfName;
+ }
+ public void setDeobfName( String val )
+ {
+ m_deobfName = val;
+ }
+}
diff --git a/src/cuchaz/enigma/mapping/Mappings.java b/src/cuchaz/enigma/mapping/Mappings.java
new file mode 100644
index 00000000..2a39057a
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/Mappings.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * 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.mapping;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.util.Map;
+import java.util.zip.GZIPInputStream;
+
+import com.beust.jcommander.internal.Maps;
+
+import cuchaz.enigma.Util;
+
+public class Mappings implements Serializable
+{
+ private static final long serialVersionUID = 4649790259460259026L;
+
+ protected Map m_classesByObf;
+ protected Map m_classesByDeobf;
+
+ public Mappings( )
+ {
+ m_classesByObf = Maps.newHashMap();
+ m_classesByDeobf = Maps.newHashMap();
+ }
+
+ public Mappings( Iterable classes )
+ {
+ this();
+
+ for( ClassMapping classMapping : classes )
+ {
+ m_classesByObf.put( classMapping.getObfName(), classMapping );
+ m_classesByDeobf.put( classMapping.getDeobfName(), classMapping );
+ }
+ }
+
+ public static Mappings newFromResource( String resource )
+ throws IOException
+ {
+ InputStream in = null;
+ try
+ {
+ in = Mappings.class.getResourceAsStream( resource );
+ return newFromStream( in );
+ }
+ finally
+ {
+ Util.closeQuietly( in );
+ }
+ }
+
+ public Iterable classes( )
+ {
+ assert( m_classesByObf.size() == m_classesByDeobf.size() );
+ return m_classesByObf.values();
+ }
+
+ protected void addClassMapping( ClassMapping classMapping )
+ {
+ m_classesByObf.put( classMapping.getObfName(), classMapping );
+ m_classesByDeobf.put( classMapping.getDeobfName(), classMapping );
+ }
+
+ public ClassMapping getClassByObf( ClassEntry entry )
+ {
+ return getClassByObf( entry.getName() );
+ }
+
+ public ClassMapping getClassByObf( String obfName )
+ {
+ return m_classesByObf.get( obfName );
+ }
+
+ public ClassMapping getClassByDeobf( ClassEntry entry )
+ {
+ return getClassByObf( entry.getName() );
+ }
+
+ public ClassMapping getClassByDeobf( String deobfName )
+ {
+ return m_classesByDeobf.get( deobfName );
+ }
+
+ public Translator getTranslator( Ancestries ancestries, TranslationDirection direction )
+ {
+ return new Translator(
+ direction,
+ direction.choose( m_classesByObf, m_classesByDeobf ),
+ direction.choose( ancestries, new DeobfuscatedAncestries( ancestries, m_classesByObf, m_classesByDeobf ) )
+ );
+ }
+
+ public static Mappings newFromStream( InputStream in )
+ throws IOException
+ {
+ try
+ {
+ return (Mappings)new ObjectInputStream( new GZIPInputStream( in ) ).readObject();
+ }
+ catch( ClassNotFoundException ex )
+ {
+ throw new Error( ex );
+ }
+ }
+
+ @Override
+ public String toString( )
+ {
+ StringBuilder buf = new StringBuilder();
+ for( ClassMapping classMapping : m_classesByObf.values() )
+ {
+ buf.append( classMapping.toString() );
+ buf.append( "\n" );
+ }
+ return buf.toString();
+ }
+}
diff --git a/src/cuchaz/enigma/mapping/MappingsReader.java b/src/cuchaz/enigma/mapping/MappingsReader.java
new file mode 100644
index 00000000..b0394090
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/MappingsReader.java
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * 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.mapping;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.NoSuchElementException;
+import java.util.Scanner;
+
+import cuchaz.enigma.Util;
+
+public class MappingsReader
+{
+ public Mappings read( Reader in )
+ throws IOException
+ {
+ return read( new BufferedReader( in ) );
+ }
+
+ public Mappings read( BufferedReader in )
+ throws IOException
+ {
+ Mappings mappings = new Mappings();
+ ClassMapping classMapping = null;
+ MethodMapping methodMapping = null;
+
+ int lineNumber = 0;
+ String line = null;
+ while( ( line = in.readLine() ) != null )
+ {
+ lineNumber++;
+
+ // strip comments
+ int commentPos = line.indexOf( '#' );
+ if( commentPos >= 0 )
+ {
+ line = line.substring( 0, commentPos );
+ }
+
+ // skip blank lines
+ line = line.trim();
+ if( line.length() <= 0 )
+ {
+ continue;
+ }
+
+ Scanner scanner = new Scanner( line );
+ try
+ {
+ while( scanner.hasNext() )
+ {
+ // read the first token
+ String token = scanner.next();
+
+ if( token.equalsIgnoreCase( "CLASS" ) )
+ {
+ classMapping = readClass( scanner );
+ mappings.addClassMapping( classMapping );
+ methodMapping = null;
+ }
+ else if( token.equalsIgnoreCase( "FIELD" ) )
+ {
+ if( classMapping == null )
+ {
+ throw new IllegalArgumentException( "Line " + lineNumber + ": Unexpected FIELD entry here!" );
+ }
+ classMapping.addFieldMapping( readField( scanner ) );
+ }
+ else if( token.equalsIgnoreCase( "METHOD" ) )
+ {
+ if( classMapping == null )
+ {
+ throw new IllegalArgumentException( "Line " + lineNumber + ": Unexpected METHOD entry here!" );
+ }
+ methodMapping = readMethod( scanner );
+ classMapping.addMethodMapping( methodMapping );
+ }
+ else if( token.equalsIgnoreCase( "ARG" ) )
+ {
+ if( classMapping == null || methodMapping == null )
+ {
+ throw new IllegalArgumentException( "Line " + lineNumber + ": Unexpected ARG entry here!" );
+ }
+ methodMapping.addArgumentMapping( readArgument( scanner ) );
+ }
+ }
+ }
+ catch( NoSuchElementException ex )
+ {
+ throw new IllegalArgumentException( "Line " + lineNumber + ": malformed line!" );
+ }
+ finally
+ {
+ Util.closeQuietly( scanner );
+ }
+ }
+
+ return mappings;
+ }
+
+ private ArgumentMapping readArgument( Scanner scanner )
+ {
+ return new ArgumentMapping( scanner.nextInt(), scanner.next() );
+ }
+
+ private ClassMapping readClass( Scanner scanner )
+ {
+ return new ClassMapping( scanner.next(), scanner.next() );
+ }
+
+ private FieldMapping readField( Scanner scanner )
+ {
+ return new FieldMapping( scanner.next(), scanner.next() );
+ }
+
+ private MethodMapping readMethod( Scanner scanner )
+ {
+ return new MethodMapping( scanner.next(), scanner.next(), scanner.next(), scanner.next() );
+ }
+}
diff --git a/src/cuchaz/enigma/mapping/MappingsWriter.java b/src/cuchaz/enigma/mapping/MappingsWriter.java
new file mode 100644
index 00000000..20863687
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/MappingsWriter.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * 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.mapping;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+
+public class MappingsWriter
+{
+ public void write( Writer out, Mappings mappings )
+ throws IOException
+ {
+ write( new PrintWriter( out ), mappings );
+ }
+
+ public void write( PrintWriter out, Mappings mappings )
+ throws IOException
+ {
+ for( ClassMapping classMapping : mappings.classes() )
+ {
+ write( out, classMapping );
+ }
+ }
+
+ public void write( PrintWriter out, ClassMapping classMapping )
+ throws IOException
+ {
+ out.format( "CLASS %s %s\n", classMapping.getObfName(), classMapping.getDeobfName() );
+
+ for( FieldMapping fieldMapping : classMapping.fields() )
+ {
+ write( out, fieldMapping );
+ }
+
+ for( MethodMapping methodMapping : classMapping.methods() )
+ {
+ write( out, methodMapping );
+ }
+ }
+
+ public void write( PrintWriter out, FieldMapping fieldMapping )
+ throws IOException
+ {
+ out.format( "\tFIELD %s %s\n", fieldMapping.getObfName(), fieldMapping.getDeobfName() );
+ }
+
+ public void write( PrintWriter out, MethodMapping methodMapping )
+ throws IOException
+ {
+ out.format( "\tMETHOD %s %s %s %s\n",
+ methodMapping.getObfName(), methodMapping.getDeobfName(),
+ methodMapping.getObfSignature(), methodMapping.getDeobfSignature()
+ );
+
+ for( ArgumentMapping argumentMapping : methodMapping.arguments() )
+ {
+ write( out, argumentMapping );
+ }
+ }
+
+ public void write( PrintWriter out, ArgumentMapping argumentMapping )
+ throws IOException
+ {
+ out.format( "\t\tARG %d %s\n", argumentMapping.getIndex(), argumentMapping.getName() );
+ }
+}
diff --git a/src/cuchaz/enigma/mapping/MethodIndex.java b/src/cuchaz/enigma/mapping/MethodIndex.java
deleted file mode 100644
index f965355d..00000000
--- a/src/cuchaz/enigma/mapping/MethodIndex.java
+++ /dev/null
@@ -1,125 +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.mapping;
-
-import java.io.Serializable;
-import java.util.Map;
-import java.util.TreeMap;
-
-public class MethodIndex implements Serializable
-{
- private static final long serialVersionUID = -4409570216084263978L;
-
- private String m_obfName;
- private String m_deobfName;
- private String m_obfSignature;
- private String m_deobfSignature;
- private Map m_arguments;
-
- public MethodIndex( String obfName, String obfSignature, String deobfName, String deobfSignature )
- {
- m_obfName = obfName;
- m_deobfName = deobfName;
- m_obfSignature = obfSignature;
- m_deobfSignature = deobfSignature;
- m_arguments = new TreeMap();
- }
-
- public String getObfName( )
- {
- return m_obfName;
- }
-
- public String getDeobfName( )
- {
- return m_deobfName;
- }
- public void setDeobfName( String val )
- {
- m_deobfName = val;
- }
-
- public String getObfSignature( )
- {
- return m_obfSignature;
- }
-
- public String getDeobfSignature( )
- {
- return m_deobfSignature;
- }
- public void setDeobfSignature( String val )
- {
- m_deobfSignature = val;
- }
-
- public String getObfArgumentName( int index )
- {
- ArgumentIndex argumentIndex = m_arguments.get( index );
- if( argumentIndex != null )
- {
- return argumentIndex.getObfName();
- }
-
- return null;
- }
-
- public String getDeobfArgumentName( int index )
- {
- ArgumentIndex argumentIndex = m_arguments.get( index );
- if( argumentIndex != null )
- {
- return argumentIndex.getDeobfName();
- }
-
- return null;
- }
-
- public void setArgumentName( int index, String obfName, String deobfName )
- {
- ArgumentIndex argumentIndex = m_arguments.get( index );
- if( argumentIndex == null )
- {
- argumentIndex = new ArgumentIndex( obfName, deobfName );
- m_arguments.put( index, argumentIndex );
- }
- else
- {
- argumentIndex.setDeobfName( deobfName );
- }
- }
-
- @Override
- public String toString( )
- {
- StringBuilder buf = new StringBuilder();
- buf.append( "\t" );
- buf.append( m_obfName );
- buf.append( " <-> " );
- buf.append( m_deobfName );
- buf.append( "\n" );
- buf.append( "\t" );
- buf.append( m_obfSignature );
- buf.append( " <-> " );
- buf.append( m_deobfSignature );
- buf.append( "\n" );
- buf.append( "\tArguments:\n" );
- for( ArgumentIndex argumentIndex : m_arguments.values() )
- {
- buf.append( "\t\t" );
- buf.append( argumentIndex.getObfName() );
- buf.append( " <-> " );
- buf.append( argumentIndex.getDeobfName() );
- buf.append( "\n" );
- }
- return buf.toString();
- }
-}
diff --git a/src/cuchaz/enigma/mapping/MethodMapping.java b/src/cuchaz/enigma/mapping/MethodMapping.java
new file mode 100644
index 00000000..f2bc54d1
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/MethodMapping.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * 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.mapping;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.TreeMap;
+
+public class MethodMapping implements Serializable
+{
+ private static final long serialVersionUID = -4409570216084263978L;
+
+ private String m_obfName;
+ private String m_deobfName;
+ private String m_obfSignature;
+ private String m_deobfSignature;
+ private Map m_arguments;
+
+ // NOTE: this argument order is important for the MethodReader/MethodWriter
+ public MethodMapping( String obfName, String deobfName, String obfSignature, String deobfSignature )
+ {
+ m_obfName = obfName;
+ m_deobfName = deobfName;
+ m_obfSignature = obfSignature;
+ m_deobfSignature = deobfSignature;
+ m_arguments = new TreeMap();
+ }
+
+ public String getObfName( )
+ {
+ return m_obfName;
+ }
+
+ public String getDeobfName( )
+ {
+ return m_deobfName;
+ }
+ public void setDeobfName( String val )
+ {
+ m_deobfName = val;
+ }
+
+ public String getObfSignature( )
+ {
+ return m_obfSignature;
+ }
+
+ public String getDeobfSignature( )
+ {
+ return m_deobfSignature;
+ }
+ public void setDeobfSignature( String val )
+ {
+ m_deobfSignature = val;
+ }
+
+ public Iterable arguments( )
+ {
+ return m_arguments.values();
+ }
+
+ protected void addArgumentMapping( ArgumentMapping argumentMapping )
+ {
+ m_arguments.put( argumentMapping.getIndex(), argumentMapping );
+ }
+
+ public String getObfArgumentName( int index )
+ {
+ ArgumentMapping argumentMapping = m_arguments.get( index );
+ if( argumentMapping != null )
+ {
+ return argumentMapping.getName();
+ }
+
+ return null;
+ }
+
+ public String getDeobfArgumentName( int index )
+ {
+ ArgumentMapping argumentMapping = m_arguments.get( index );
+ if( argumentMapping != null )
+ {
+ return argumentMapping.getName();
+ }
+
+ return null;
+ }
+
+ public void setArgumentName( int index, String name )
+ {
+ ArgumentMapping argumentMapping = m_arguments.get( index );
+ if( argumentMapping == null )
+ {
+ argumentMapping = new ArgumentMapping( index, name );
+ m_arguments.put( index, argumentMapping );
+ }
+ else
+ {
+ argumentMapping.setName( name );
+ }
+ }
+
+ @Override
+ public String toString( )
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.append( "\t" );
+ buf.append( m_obfName );
+ buf.append( " <-> " );
+ buf.append( m_deobfName );
+ buf.append( "\n" );
+ buf.append( "\t" );
+ buf.append( m_obfSignature );
+ buf.append( " <-> " );
+ buf.append( m_deobfSignature );
+ buf.append( "\n" );
+ buf.append( "\tArguments:\n" );
+ for( ArgumentMapping argumentMapping : m_arguments.values() )
+ {
+ buf.append( "\t\t" );
+ buf.append( argumentMapping.getIndex() );
+ buf.append( " <-> " );
+ buf.append( argumentMapping.getName() );
+ buf.append( "\n" );
+ }
+ return buf.toString();
+ }
+}
diff --git a/src/cuchaz/enigma/mapping/Renamer.java b/src/cuchaz/enigma/mapping/Renamer.java
new file mode 100644
index 00000000..4a648ad3
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/Renamer.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * 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.mapping;
+
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.util.zip.GZIPOutputStream;
+
+public class Renamer
+{
+ private Ancestries m_ancestries;
+ private Mappings m_mappings;
+
+ public Renamer( Ancestries ancestries, Mappings mappings )
+ {
+ m_ancestries = ancestries;
+ m_mappings = mappings;
+ }
+
+ public void setClassName( ClassEntry obf, String deobfName )
+ {
+ ClassMapping classMapping = m_mappings.m_classesByObf.get( obf.getName() );
+ if( classMapping == null )
+ {
+ classMapping = createClassMapping( obf );
+ }
+
+ m_mappings.m_classesByDeobf.remove( classMapping.getDeobfName() );
+ classMapping.setDeobfName( deobfName );
+ m_mappings.m_classesByDeobf.put( deobfName, classMapping );
+
+ updateDeobfMethodSignatures();
+
+ // TEMP
+ String translatedName = m_mappings.getTranslator( m_ancestries, TranslationDirection.Deobfuscating ).translate( obf );
+ assert( translatedName != null && translatedName.equals( deobfName ) );
+ }
+
+ public void setFieldName( FieldEntry obf, String deobfName )
+ {
+ ClassMapping classMapping = m_mappings.m_classesByObf.get( obf.getClassName() );
+ if( classMapping == null )
+ {
+ classMapping = createClassMapping( obf.getClassEntry() );
+ }
+
+ classMapping.setFieldName( obf.getName(), deobfName );
+
+ // TEMP
+ System.out.println( classMapping );
+ String translatedName = m_mappings.getTranslator( m_ancestries, TranslationDirection.Deobfuscating ).translate( obf );
+ assert( translatedName != null && translatedName.equals( deobfName ) );
+ }
+
+ public void setMethodName( MethodEntry obf, String deobfName )
+ {
+ ClassMapping classMapping = m_mappings.m_classesByObf.get( obf.getClassName() );
+ if( classMapping == null )
+ {
+ classMapping = createClassMapping( obf.getClassEntry() );
+ }
+
+ String deobfSignature = m_mappings.getTranslator( m_ancestries, TranslationDirection.Deobfuscating ).translateSignature( obf.getSignature() );
+ classMapping.setMethodNameAndSignature( obf.getName(), obf.getSignature(), deobfName, deobfSignature );
+
+ // TODO: update ancestor/descendant methods in other classes in the inheritance hierarchy too
+
+ // TEMP
+ System.out.println( classMapping );
+ String translatedName = m_mappings.getTranslator( m_ancestries, TranslationDirection.Deobfuscating ).translate( obf );
+ assert( translatedName != null && translatedName.equals( deobfName ) );
+ }
+
+ public void setArgumentName( ArgumentEntry obf, String deobfName )
+ {
+ ClassMapping classMapping = m_mappings.m_classesByObf.get( obf.getClassName() );
+ if( classMapping == null )
+ {
+ classMapping = createClassMapping( obf.getClassEntry() );
+ }
+
+ classMapping.setArgumentName( obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), deobfName );
+
+ // TEMP
+ System.out.println( classMapping );
+ String translatedName = m_mappings.getTranslator( m_ancestries, TranslationDirection.Deobfuscating ).translate( obf );
+ assert( translatedName != null && translatedName.equals( deobfName ) );
+ }
+
+ public void write( OutputStream out )
+ throws IOException
+ {
+ // TEMP: just use the object output for now. We can find a more efficient storage format later
+ GZIPOutputStream gzipout = new GZIPOutputStream( out );
+ ObjectOutputStream oout = new ObjectOutputStream( gzipout );
+ oout.writeObject( this );
+ gzipout.finish();
+ }
+
+ private ClassMapping createClassMapping( ClassEntry obf )
+ {
+ ClassMapping classMapping = new ClassMapping( obf.getName(), obf.getName() );
+ m_mappings.m_classesByObf.put( classMapping.getObfName(), classMapping );
+ m_mappings.m_classesByDeobf.put( classMapping.getDeobfName(), classMapping );
+ return classMapping;
+ }
+
+ private void updateDeobfMethodSignatures( )
+ {
+ Translator translator = m_mappings.getTranslator( m_ancestries, TranslationDirection.Deobfuscating );
+ for( ClassMapping classMapping : m_mappings.m_classesByObf.values() )
+ {
+ classMapping.updateDeobfMethodSignatures( translator );
+ }
+ }
+}
diff --git a/src/cuchaz/enigma/mapping/TranslationMappings.java b/src/cuchaz/enigma/mapping/TranslationMappings.java
deleted file mode 100644
index d6cd4491..00000000
--- a/src/cuchaz/enigma/mapping/TranslationMappings.java
+++ /dev/null
@@ -1,187 +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.mapping;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.OutputStream;
-import java.io.Serializable;
-import java.util.Map;
-import java.util.zip.GZIPInputStream;
-import java.util.zip.GZIPOutputStream;
-
-import com.beust.jcommander.internal.Maps;
-
-import cuchaz.enigma.Util;
-
-public class TranslationMappings implements Serializable
-{
- private static final long serialVersionUID = 4649790259460259026L;
-
- private Map m_classesByObf;
- private Map m_classesByDeobf;
- private Ancestries m_ancestries;
-
- public TranslationMappings( Ancestries ancestries )
- {
- m_classesByObf = Maps.newHashMap();
- m_classesByDeobf = Maps.newHashMap();
- m_ancestries = ancestries;
- }
-
- public static TranslationMappings newFromResource( String resource )
- throws IOException
- {
- InputStream in = null;
- try
- {
- in = TranslationMappings.class.getResourceAsStream( resource );
- return newFromStream( in );
- }
- finally
- {
- Util.closeQuietly( in );
- }
- }
-
- public Translator getTranslator( TranslationDirection direction )
- {
- return new Translator(
- direction,
- direction.choose( m_classesByObf, m_classesByDeobf ),
- direction.choose( m_ancestries, new DeobfuscatedAncestries( m_ancestries, m_classesByObf, m_classesByDeobf ) )
- );
- }
-
- public void setClassName( ClassEntry obf, String deobfName )
- {
- ClassIndex classIndex = m_classesByObf.get( obf.getName() );
- if( classIndex == null )
- {
- classIndex = createClassIndex( obf );
- }
-
- m_classesByDeobf.remove( classIndex.getDeobfName() );
- classIndex.setDeobfName( deobfName );
- m_classesByDeobf.put( deobfName, classIndex );
-
- updateDeobfMethodSignatures();
-
- // TEMP
- String translatedName = getTranslator( TranslationDirection.Deobfuscating ).translate( obf );
- assert( translatedName != null && translatedName.equals( deobfName ) );
- }
-
- public void setFieldName( FieldEntry obf, String deobfName )
- {
- ClassIndex classIndex = m_classesByObf.get( obf.getClassName() );
- if( classIndex == null )
- {
- classIndex = createClassIndex( obf.getClassEntry() );
- }
-
- classIndex.setFieldName( obf.getName(), deobfName );
-
- // TEMP
- System.out.println( classIndex );
- String translatedName = getTranslator( TranslationDirection.Deobfuscating ).translate( obf );
- assert( translatedName != null && translatedName.equals( deobfName ) );
- }
-
- public void setMethodName( MethodEntry obf, String deobfName )
- {
- ClassIndex classIndex = m_classesByObf.get( obf.getClassName() );
- if( classIndex == null )
- {
- classIndex = createClassIndex( obf.getClassEntry() );
- }
-
- String deobfSignature = getTranslator( TranslationDirection.Deobfuscating ).translateSignature( obf.getSignature() );
- classIndex.setMethodNameAndSignature( obf.getName(), obf.getSignature(), deobfName, deobfSignature );
-
- // TODO: update ancestor/descendant methods in other classes in the inheritance hierarchy too
-
- // TEMP
- System.out.println( classIndex );
- String translatedName = getTranslator( TranslationDirection.Deobfuscating ).translate( obf );
- assert( translatedName != null && translatedName.equals( deobfName ) );
- }
-
- public void setArgumentName( ArgumentEntry obf, String deobfName )
- {
- ClassIndex classIndex = m_classesByObf.get( obf.getClassName() );
- if( classIndex == null )
- {
- classIndex = createClassIndex( obf.getClassEntry() );
- }
-
- classIndex.setArgumentName( obf.getMethodName(), obf.getMethodSignature(), obf.getIndex(), obf.getName(), deobfName );
-
- // TEMP
- System.out.println( classIndex );
- String translatedName = getTranslator( TranslationDirection.Deobfuscating ).translate( obf );
- assert( translatedName != null && translatedName.equals( deobfName ) );
- }
-
- public void write( OutputStream out )
- throws IOException
- {
- // TEMP: just use the object output for now. We can find a more efficient storage format later
- GZIPOutputStream gzipout = new GZIPOutputStream( out );
- ObjectOutputStream oout = new ObjectOutputStream( gzipout );
- oout.writeObject( this );
- gzipout.finish();
- }
-
- public static TranslationMappings newFromStream( InputStream in )
- throws IOException
- {
- try
- {
- return (TranslationMappings)new ObjectInputStream( new GZIPInputStream( in ) ).readObject();
- }
- catch( ClassNotFoundException ex )
- {
- throw new Error( ex );
- }
- }
-
- private ClassIndex createClassIndex( ClassEntry obf )
- {
- ClassIndex classIndex = new ClassIndex( obf.getName(), obf.getName() );
- m_classesByObf.put( classIndex.getObfName(), classIndex );
- m_classesByDeobf.put( classIndex.getDeobfName(), classIndex );
- return classIndex;
- }
-
- private void updateDeobfMethodSignatures( )
- {
- Translator translator = getTranslator( TranslationDirection.Deobfuscating );
- for( ClassIndex classIndex : m_classesByObf.values() )
- {
- classIndex.updateDeobfMethodSignatures( translator );
- }
- }
-
- @Override
- public String toString( )
- {
- StringBuilder buf = new StringBuilder();
- for( ClassIndex classIndex : m_classesByObf.values() )
- {
- buf.append( classIndex.toString() );
- buf.append( "\n" );
- }
- return buf.toString();
- }
-}
diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java
index bae0dce7..3dbc103b 100644
--- a/src/cuchaz/enigma/mapping/Translator.java
+++ b/src/cuchaz/enigma/mapping/Translator.java
@@ -19,10 +19,10 @@ import cuchaz.enigma.mapping.SignatureUpdater.ClassNameUpdater;
public class Translator
{
private TranslationDirection m_direction;
- private Map m_classes;
+ private Map m_classes;
private Ancestries m_ancestries;
- protected Translator( TranslationDirection direction, Map classes, Ancestries ancestries )
+ protected Translator( TranslationDirection direction, Map classes, Ancestries ancestries )
{
m_direction = direction;
m_classes = classes;
@@ -36,7 +36,7 @@ public class Translator
public String translateClass( String in )
{
- ClassIndex classIndex = m_classes.get( in );
+ ClassMapping classIndex = m_classes.get( in );
if( classIndex != null )
{
return m_direction.choose(
@@ -63,7 +63,7 @@ public class Translator
for( String className : getSelfAndAncestors( in.getClassName() ) )
{
// look for the class
- ClassIndex classIndex = m_classes.get( className );
+ ClassMapping classIndex = m_classes.get( className );
if( classIndex != null )
{
// look for the field
@@ -99,11 +99,11 @@ public class Translator
for( String className : getSelfAndAncestors( in.getClassName() ) )
{
// look for the class
- ClassIndex classIndex = m_classes.get( className );
+ ClassMapping classIndex = m_classes.get( className );
if( classIndex != null )
{
// look for the method
- MethodIndex methodIndex = m_direction.choose(
+ MethodMapping methodIndex = m_direction.choose(
classIndex.getMethodByObf( in.getName(), in.getSignature() ),
classIndex.getMethodByDeobf( in.getName(), in.getSignature() )
);
@@ -139,11 +139,11 @@ public class Translator
for( String className : getSelfAndAncestors( in.getClassName() ) )
{
// look for the class
- ClassIndex classIndex = m_classes.get( className );
+ ClassMapping classIndex = m_classes.get( className );
if( classIndex != null )
{
// look for the method
- MethodIndex methodIndex = m_direction.choose(
+ MethodMapping methodIndex = m_direction.choose(
classIndex.getMethodByObf( in.getMethodName(), in.getMethodSignature() ),
classIndex.getMethodByDeobf( in.getMethodName(), in.getMethodSignature() )
);
--
cgit v1.2.3
From faae0a6514c2565a10f9a62dd18c5d79fbbe4156 Mon Sep 17 00:00:00 2001
From: jeff
Date: Thu, 31 Jul 2014 22:27:26 -0400
Subject: fixed bug with save mappings menu gui shows deobfuscated classes list
now working on name validation/sanitization
---
src/cuchaz/enigma/ClassFile.java | 34 ++++++-----
src/cuchaz/enigma/Deobfuscator.java | 60 +++++--------------
src/cuchaz/enigma/gui/ClassListCellRenderer.java | 40 +++++++++++++
src/cuchaz/enigma/gui/Gui.java | 64 +++++++++++++++++++--
src/cuchaz/enigma/gui/GuiController.java | 18 +++++-
.../gui/ObfuscatedClassListCellRenderer.java | 40 -------------
src/cuchaz/enigma/mapping/NameValidator.java | 67 ++++++++++++++++++++++
7 files changed, 216 insertions(+), 107 deletions(-)
create mode 100644 src/cuchaz/enigma/gui/ClassListCellRenderer.java
delete mode 100644 src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java
create mode 100644 src/cuchaz/enigma/mapping/NameValidator.java
diff --git a/src/cuchaz/enigma/ClassFile.java b/src/cuchaz/enigma/ClassFile.java
index 221a119e..c3c72a47 100644
--- a/src/cuchaz/enigma/ClassFile.java
+++ b/src/cuchaz/enigma/ClassFile.java
@@ -10,36 +10,42 @@
******************************************************************************/
package cuchaz.enigma;
-import java.util.regex.Pattern;
public class ClassFile
{
- private static Pattern m_obfuscatedClassPattern;
+ private String m_obfName;
+ private String m_deobfName;
- static
+ public ClassFile( String obfName )
{
- m_obfuscatedClassPattern = Pattern.compile( "^[a-z]+$" );
+ m_obfName = obfName;
}
- private String m_name;
-
- public ClassFile( String name )
+ public String getName( )
{
- m_name = name;
+ if( m_deobfName != null )
+ {
+ return m_deobfName;
+ }
+ return m_obfName;
}
- public String getName( )
+ public String getObfName( )
{
- return m_name;
+ return m_obfName;
}
- public boolean isObfuscated( )
+ public String getDeobfName( )
{
- return m_obfuscatedClassPattern.matcher( m_name ).matches();
+ return m_deobfName;
}
-
+ public void setDeobfName( String val )
+ {
+ m_deobfName = val;
+ }
+
public String getPath( )
{
- return m_name.replace( ".", "/" ) + ".class";
+ return m_deobfName.replace( ".", "/" ) + ".class";
}
}
diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java
index 7be57062..619eebfc 100644
--- a/src/cuchaz/enigma/Deobfuscator.java
+++ b/src/cuchaz/enigma/Deobfuscator.java
@@ -15,9 +15,6 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
@@ -30,10 +27,12 @@ import com.strobel.decompiler.PlainTextOutput;
import cuchaz.enigma.mapping.Ancestries;
import cuchaz.enigma.mapping.ArgumentEntry;
import cuchaz.enigma.mapping.ClassEntry;
+import cuchaz.enigma.mapping.ClassMapping;
import cuchaz.enigma.mapping.Entry;
import cuchaz.enigma.mapping.FieldEntry;
import cuchaz.enigma.mapping.Mappings;
import cuchaz.enigma.mapping.MethodEntry;
+import cuchaz.enigma.mapping.NameValidator;
import cuchaz.enigma.mapping.Renamer;
import cuchaz.enigma.mapping.TranslationDirection;
import cuchaz.enigma.mapping.Translator;
@@ -47,25 +46,6 @@ public class Deobfuscator
private Mappings m_mappings;
private Renamer m_renamer;
- private static Comparator m_obfuscatedClassSorter;
-
- static
- {
- m_obfuscatedClassSorter = new Comparator( )
- {
- @Override
- public int compare( ClassFile a, ClassFile b )
- {
- if( a.getName().length() != b.getName().length() )
- {
- return a.getName().length() - b.getName().length();
- }
-
- return a.getName().compareTo( b.getName() );
- }
- };
- }
-
public Deobfuscator( File file )
throws IOException
{
@@ -120,48 +100,38 @@ public class Deobfuscator
) );
}
- public List getObfuscatedClasses( )
+ public void getSortedClasses( List obfClasses, List deobfClasses )
{
- List classes = new ArrayList();
Enumeration entries = m_jar.entries();
while( entries.hasMoreElements() )
{
JarEntry entry = entries.nextElement();
// get the class name
- String className = toClassName( entry.getName() );
- if( className == null )
+ String obfName = NameValidator.fileNameToClassName( entry.getName() );
+ if( obfName == null )
{
continue;
}
- ClassFile classFile = new ClassFile( className );
- if( classFile.isObfuscated() )
+ ClassFile classFile = new ClassFile( obfName );
+ ClassMapping classMapping = m_mappings.getClassByObf( classFile.getName() );
+ if( classMapping != null )
{
- classes.add( classFile );
+ classFile.setDeobfName( classMapping.getDeobfName() );
+ deobfClasses.add( classFile );
+ }
+ else
+ {
+ obfClasses.add( classFile );
}
}
- Collections.sort( classes, m_obfuscatedClassSorter );
- return classes;
- }
-
- // TODO: could go somewhere more generic
- private static String toClassName( String fileName )
- {
- final String suffix = ".class";
-
- if( !fileName.endsWith( suffix ) )
- {
- return null;
- }
-
- return fileName.substring( 0, fileName.length() - suffix.length() ).replace( "/", "." );
}
public String getSource( final ClassFile classFile )
{
StringWriter buf = new StringWriter();
- Decompiler.decompile( classFile.getName(), new PlainTextOutput( buf ), m_settings );
+ Decompiler.decompile( classFile.getObfName(), new PlainTextOutput( buf ), m_settings );
return buf.toString();
}
diff --git a/src/cuchaz/enigma/gui/ClassListCellRenderer.java b/src/cuchaz/enigma/gui/ClassListCellRenderer.java
new file mode 100644
index 00000000..302f140b
--- /dev/null
+++ b/src/cuchaz/enigma/gui/ClassListCellRenderer.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.ClassFile;
+
+public class ClassListCellRenderer implements ListCellRenderer
+{
+ private DefaultListCellRenderer m_defaultRenderer;
+
+ public ClassListCellRenderer( )
+ {
+ m_defaultRenderer = new DefaultListCellRenderer();
+ }
+
+ @Override
+ public Component getListCellRendererComponent( JList extends ClassFile> list, ClassFile classFile, int index, boolean isSelected, boolean hasFocus )
+ {
+ JLabel label = (JLabel)m_defaultRenderer.getListCellRendererComponent( list, classFile, index, isSelected, hasFocus );
+
+ label.setText( classFile.getName() );
+
+ return label;
+ }
+}
diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java
index a86ff9b0..d448dc28 100644
--- a/src/cuchaz/enigma/gui/Gui.java
+++ b/src/cuchaz/enigma/gui/Gui.java
@@ -21,6 +21,8 @@ import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
import java.util.Vector;
@@ -58,6 +60,25 @@ import cuchaz.enigma.mapping.MethodEntry;
public class Gui
{
+ private static Comparator m_obfuscatedClassSorter;
+
+ static
+ {
+ m_obfuscatedClassSorter = new Comparator( )
+ {
+ @Override
+ public int compare( ClassFile a, ClassFile b )
+ {
+ if( a.getName().length() != b.getName().length() )
+ {
+ return a.getName().length() - b.getName().length();
+ }
+
+ return a.getName().compareTo( b.getName() );
+ }
+ };
+ }
+
private GuiController m_controller;
// controls
@@ -101,7 +122,7 @@ public class Gui
m_obfClasses = new JList();
m_obfClasses.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
m_obfClasses.setLayoutOrientation( JList.VERTICAL );
- m_obfClasses.setCellRenderer( new ObfuscatedClassListCellRenderer() );
+ m_obfClasses.setCellRenderer( new ClassListCellRenderer() );
m_obfClasses.addMouseListener( new MouseAdapter()
{
public void mouseClicked( MouseEvent event )
@@ -124,8 +145,23 @@ public class Gui
// init deobfuscated classes list
m_deobfClasses = new JList();
- m_obfClasses.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
- m_obfClasses.setLayoutOrientation( JList.VERTICAL );
+ m_deobfClasses.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
+ m_deobfClasses.setLayoutOrientation( JList.VERTICAL );
+ m_deobfClasses.setCellRenderer( new ClassListCellRenderer() );
+ m_deobfClasses.addMouseListener( new MouseAdapter()
+ {
+ public void mouseClicked( MouseEvent event )
+ {
+ if( event.getClickCount() == 2 )
+ {
+ ClassFile selected = m_deobfClasses.getSelectedValue();
+ if( selected != null )
+ {
+ m_controller.deobfuscateClass( selected );
+ }
+ }
+ }
+ } );
JScrollPane deobfScroller = new JScrollPane( m_deobfClasses );
JPanel deobfPanel = new JPanel();
deobfPanel.setLayout( new BorderLayout() );
@@ -248,7 +284,6 @@ public class Gui
try
{
m_controller.openMappings( m_mappingFileChooser.getSelectedFile() );
- m_saveMappingsMenu.setEnabled( true );
}
catch( IOException ex )
{
@@ -383,7 +418,9 @@ public class Gui
{
if( classes != null )
{
- m_obfClasses.setListData( new Vector( classes ) );
+ Vector sortedClasses = new Vector( classes );
+ Collections.sort( sortedClasses, m_obfuscatedClassSorter );
+ m_obfClasses.setListData( sortedClasses );
}
else
{
@@ -391,6 +428,23 @@ public class Gui
}
}
+ public void setDeobfClasses( List classes )
+ {
+ if( classes != null )
+ {
+ m_deobfClasses.setListData( new Vector( classes ) );
+ }
+ else
+ {
+ m_deobfClasses.setListData( new Vector() );
+ }
+ }
+
+ public void setMappingsLoaded( boolean isLoaded )
+ {
+ m_saveMappingsMenu.setEnabled( isLoaded );
+ }
+
public void setSource( String source )
{
setSource( source, null );
diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java
index fb22b961..ce1c31bd 100644
--- a/src/cuchaz/enigma/gui/GuiController.java
+++ b/src/cuchaz/enigma/gui/GuiController.java
@@ -14,6 +14,8 @@ import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
import cuchaz.enigma.ClassFile;
import cuchaz.enigma.Deobfuscator;
@@ -45,7 +47,7 @@ public class GuiController
{
m_deobfuscator = new Deobfuscator( file );
m_gui.onOpenJar( m_deobfuscator.getJarName() );
- m_gui.setObfClasses( m_deobfuscator.getObfuscatedClasses() );
+ refreshClasses();
}
public void closeJar( )
@@ -60,8 +62,8 @@ public class GuiController
FileReader in = new FileReader( file );
m_deobfuscator.setMappings( new MappingsReader().read( in ) );
in.close();
- // TEMP
- System.out.println( m_deobfuscator.getMappings() );
+ m_gui.setMappingsLoaded( true );
+ refreshClasses();
refreshOpenFiles();
}
@@ -76,6 +78,7 @@ public class GuiController
public void closeMappings( )
{
m_deobfuscator.setMappings( null );
+ m_gui.setMappingsLoaded( false );
refreshOpenFiles();
}
@@ -119,6 +122,15 @@ public class GuiController
refreshOpenFiles();
}
+ private void refreshClasses( )
+ {
+ List obfClasses = new ArrayList();
+ List deobfClasses = new ArrayList();
+ m_deobfuscator.getSortedClasses( obfClasses, deobfClasses );
+ m_gui.setObfClasses( obfClasses );
+ m_gui.setDeobfClasses( deobfClasses );
+ }
+
private void refreshOpenFiles( )
{
if( m_currentFile != null )
diff --git a/src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java b/src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java
deleted file mode 100644
index 0badb3b9..00000000
--- a/src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java
+++ /dev/null
@@ -1,40 +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.gui;
-
-import java.awt.Component;
-
-import javax.swing.DefaultListCellRenderer;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.ListCellRenderer;
-
-import cuchaz.enigma.ClassFile;
-
-public class ObfuscatedClassListCellRenderer implements ListCellRenderer
-{
- private DefaultListCellRenderer m_defaultRenderer;
-
- public ObfuscatedClassListCellRenderer( )
- {
- m_defaultRenderer = new DefaultListCellRenderer();
- }
-
- @Override
- public Component getListCellRendererComponent( JList extends ClassFile> list, ClassFile classFile, int index, boolean isSelected, boolean hasFocus )
- {
- JLabel label = (JLabel)m_defaultRenderer.getListCellRendererComponent( list, classFile, index, isSelected, hasFocus );
-
- label.setText( classFile.getName() );
-
- return label;
- }
-}
diff --git a/src/cuchaz/enigma/mapping/NameValidator.java b/src/cuchaz/enigma/mapping/NameValidator.java
new file mode 100644
index 00000000..30982dc6
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/NameValidator.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * 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.mapping;
+
+import java.util.regex.Pattern;
+
+public class NameValidator
+{
+ private static final String IdentifierPattern;
+ private static final Pattern ClassPattern;
+
+ static
+ {
+ // java allows all kinds of weird characters...
+ StringBuilder startChars = new StringBuilder();
+ StringBuilder partChars = new StringBuilder();
+ for( int i = Character.MIN_CODE_POINT; i <= Character.MAX_CODE_POINT; i++ )
+ {
+ if( Character.isJavaIdentifierStart( i ) )
+ {
+ startChars.appendCodePoint( i );
+ }
+ if( Character.isJavaIdentifierPart( i ) )
+ {
+ partChars.appendCodePoint( i );
+ }
+ }
+
+ IdentifierPattern = String.format( "[\\Q%s\\E][\\Q%s\\E]*", startChars.toString(), partChars.toString() );
+ ClassPattern = Pattern.compile( String.format( "^(%s(\\.|/))*(%s)$", IdentifierPattern, IdentifierPattern ) );
+ }
+
+ public String validateClassName( String name )
+ {
+ if( !ClassPattern.matcher( name ).matches() )
+ {
+ throw new IllegalArgumentException( "Illegal name: " + name );
+ }
+
+ return classNameToJavaName( name );
+ }
+
+ public static String fileNameToClassName( String fileName )
+ {
+ final String suffix = ".class";
+
+ if( !fileName.endsWith( suffix ) )
+ {
+ return null;
+ }
+
+ return fileName.substring( 0, fileName.length() - suffix.length() ).replace( "/", "." );
+ }
+
+ public static String classNameToJavaName( String className )
+ {
+ return className.replace( ".", "/" );
+ }
+}
--
cgit v1.2.3
From ada041979ecf3dfd4543f3c250fcc78ad594866c Mon Sep 17 00:00:00 2001
From: jeff
Date: Sat, 2 Aug 2014 16:45:32 -0400
Subject: started working on method parameter renaming
---
src/cuchaz/enigma/Deobfuscator.java | 4 +-
src/cuchaz/enigma/TranslatingTypeLoader.java | 10 +--
.../enigma/bytecode/MethodParameterWriter.java | 35 ++++++++++
.../enigma/bytecode/MethodParametersAttribute.java | 80 ++++++++++++++++++++++
4 files changed, 123 insertions(+), 6 deletions(-)
create mode 100644 src/cuchaz/enigma/bytecode/MethodParameterWriter.java
create mode 100644 src/cuchaz/enigma/bytecode/MethodParametersAttribute.java
diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java
index 619eebfc..edc29e17 100644
--- a/src/cuchaz/enigma/Deobfuscator.java
+++ b/src/cuchaz/enigma/Deobfuscator.java
@@ -95,8 +95,8 @@ public class Deobfuscator
// update decompiler options
m_settings.setTypeLoader( new TranslatingTypeLoader(
m_jar,
- m_mappings.getTranslator( m_ancestries, TranslationDirection.Deobfuscating ),
- m_mappings.getTranslator( m_ancestries, TranslationDirection.Obfuscating )
+ m_mappings.getTranslator( m_ancestries, TranslationDirection.Obfuscating ),
+ m_mappings.getTranslator( m_ancestries, TranslationDirection.Deobfuscating )
) );
}
diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java
index 872f4861..cd36e8da 100644
--- a/src/cuchaz/enigma/TranslatingTypeLoader.java
+++ b/src/cuchaz/enigma/TranslatingTypeLoader.java
@@ -23,19 +23,20 @@ import com.strobel.assembler.metadata.Buffer;
import com.strobel.assembler.metadata.ITypeLoader;
import cuchaz.enigma.bytecode.ClassTranslator;
+import cuchaz.enigma.bytecode.MethodParameterWriter;
import cuchaz.enigma.mapping.Translator;
public class TranslatingTypeLoader implements ITypeLoader
{
private JarFile m_jar;
- private ClassTranslator m_classTranslator;
private Translator m_obfuscatingTranslator;
+ private Translator m_deobfuscatingTranslator;
- public TranslatingTypeLoader( JarFile jar, Translator deobfuscatingTranslator, Translator obfuscatingTranslator )
+ public TranslatingTypeLoader( JarFile jar, Translator obfuscatingTranslator, Translator deobfuscatingTranslator )
{
m_jar = jar;
- m_classTranslator = new ClassTranslator( deobfuscatingTranslator );
m_obfuscatingTranslator = obfuscatingTranslator;
+ m_deobfuscatingTranslator = deobfuscatingTranslator;
}
@Override
@@ -69,7 +70,8 @@ public class TranslatingTypeLoader implements ITypeLoader
try
{
CtClass c = classPool.get( name );
- m_classTranslator.translate( c );
+ new ClassTranslator( m_deobfuscatingTranslator ).translate( c );
+ new MethodParameterWriter( m_deobfuscatingTranslator ).writeMethodArguments( c );
buf = c.toBytecode();
}
catch( Exception ex )
diff --git a/src/cuchaz/enigma/bytecode/MethodParameterWriter.java b/src/cuchaz/enigma/bytecode/MethodParameterWriter.java
new file mode 100644
index 00000000..1e5d1f0a
--- /dev/null
+++ b/src/cuchaz/enigma/bytecode/MethodParameterWriter.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * 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.bytecode;
+
+import javassist.CtBehavior;
+import javassist.CtClass;
+import javassist.bytecode.AttributeInfo;
+import cuchaz.enigma.mapping.Translator;
+
+public class MethodParameterWriter
+{
+ private Translator m_translator;
+
+ public MethodParameterWriter( Translator translator )
+ {
+ m_translator = translator;
+ }
+
+ public void writeMethodArguments( CtClass c )
+ {
+ // Procyon will read method arguments from the "MethodParameters" attribute, so write those
+ for( CtBehavior behavior : c.getDeclaredBehaviors() )
+ {
+ AttributeInfo attribute = behavior.getMethodInfo().getAttribute( "MethodParameter" );
+ }
+ }
+}
diff --git a/src/cuchaz/enigma/bytecode/MethodParametersAttribute.java b/src/cuchaz/enigma/bytecode/MethodParametersAttribute.java
new file mode 100644
index 00000000..0b29403d
--- /dev/null
+++ b/src/cuchaz/enigma/bytecode/MethodParametersAttribute.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * 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.bytecode;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+import javassist.bytecode.AttributeInfo;
+import javassist.bytecode.ConstPool;
+
+public class MethodParametersAttribute extends AttributeInfo
+{
+ public MethodParametersAttribute( ConstPool pool, int attributeNameIndex, List parameterNameIndices )
+ {
+ super( pool, "MethodParameters", writeStruct( attributeNameIndex, parameterNameIndices ) );
+ }
+
+ private static byte[] writeStruct( int attributeNameIndex, List parameterNameIndices )
+ {
+ // JVM Spec says the struct looks like this:
+ // http://cr.openjdk.java.net/~mr/se/8/java-se-8-fr-spec-01/java-se-8-jvms-fr-diffs.pdf
+ // uint16 name_index -> points to UTF8 entry in constant pool that says "MethodParameters"
+ // uint32 length -> length of this struct, minus 6 bytes (ie, length of num_params and parameter array)
+ // uint8 num_params
+ // for each param:
+ // uint16 name_index -> points to UTF8 entry in constant pool, or 0 for no entry
+ // uint16 access_flags -> don't care, just set to 0
+
+ ByteArrayOutputStream buf = new ByteArrayOutputStream();
+ DataOutputStream out = new DataOutputStream( buf );
+
+ // NOTE: java hates unsigned integers, so we have to be careful here
+ // the writeShort(), writeByte() methods will read 16,8 low-order bits from the int argument
+ // as long as the int argument is in range of the unsigned short/byte type, it will be written as an unsigned short/byte
+ // if the int is out of range, the byte stream won't look the way we want and weird things will happen
+ final int SIZEOF_UINT16 = 2;
+ final int MAX_UINT8 = ( 1 << 8 ) - 1;
+ final int MAX_UINT16 = ( 1 << 16 ) - 1;
+ final long MAX_UINT32 = ( 1 << 32 ) - 1;
+
+ try
+ {
+ assert( attributeNameIndex >= 0 && attributeNameIndex <= MAX_UINT16 );
+ out.writeShort( attributeNameIndex );
+
+ long length = SIZEOF_UINT16 + parameterNameIndices.size()*( SIZEOF_UINT16 + SIZEOF_UINT16 );
+ assert( length >= 0 && length <= MAX_UINT32 );
+ out.writeInt( (int)length );
+
+ assert( parameterNameIndices.size() >= 0 && parameterNameIndices.size() <= MAX_UINT8 );
+ out.writeByte( parameterNameIndices.size() );
+
+ for( Integer index : parameterNameIndices )
+ {
+ assert( index >= 0 && index <= MAX_UINT16 );
+ out.writeShort( index );
+
+ // just write 0 for the access flags
+ out.writeShort( 0 );
+ }
+
+ out.close();
+ return buf.toByteArray();
+ }
+ catch( IOException ex )
+ {
+ throw new Error( ex );
+ }
+ }
+}
--
cgit v1.2.3
From 76be350b3c54ea88cc1a95b5cf0d1db153f2edb3 Mon Sep 17 00:00:00 2001
From: jeff
Date: Sun, 3 Aug 2014 11:16:33 -0400
Subject: fixed bugs with saving mappings got argument renaming to work
---
src/cuchaz/enigma/TranslatingTypeLoader.java | 2 +-
src/cuchaz/enigma/analysis/SourcedAst.java | 21 +++++++--
.../enigma/bytecode/MethodParameterWriter.java | 26 ++++++++++-
.../enigma/bytecode/MethodParametersAttribute.java | 46 ++++++++++++------
src/cuchaz/enigma/gui/Gui.java | 54 ++++++++++++----------
src/cuchaz/enigma/gui/GuiController.java | 8 ++--
src/cuchaz/enigma/mapping/EntryPair.java | 30 ++----------
src/cuchaz/enigma/mapping/MethodMapping.java | 2 +-
8 files changed, 112 insertions(+), 77 deletions(-)
diff --git a/src/cuchaz/enigma/TranslatingTypeLoader.java b/src/cuchaz/enigma/TranslatingTypeLoader.java
index cd36e8da..e57a09de 100644
--- a/src/cuchaz/enigma/TranslatingTypeLoader.java
+++ b/src/cuchaz/enigma/TranslatingTypeLoader.java
@@ -70,8 +70,8 @@ public class TranslatingTypeLoader implements ITypeLoader
try
{
CtClass c = classPool.get( name );
- new ClassTranslator( m_deobfuscatingTranslator ).translate( c );
new MethodParameterWriter( m_deobfuscatingTranslator ).writeMethodArguments( c );
+ new ClassTranslator( m_deobfuscatingTranslator ).translate( c );
buf = c.toBytecode();
}
catch( Exception ex )
diff --git a/src/cuchaz/enigma/analysis/SourcedAst.java b/src/cuchaz/enigma/analysis/SourcedAst.java
index 04c6f03b..52a34534 100644
--- a/src/cuchaz/enigma/analysis/SourcedAst.java
+++ b/src/cuchaz/enigma/analysis/SourcedAst.java
@@ -13,7 +13,10 @@ package cuchaz.enigma.analysis;
import java.io.IOException;
import java.util.HashMap;
+import javassist.bytecode.Descriptor;
+
import com.google.common.collect.Maps;
+import com.sun.source.tree.ClassTree;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.ImportTree;
import com.sun.source.tree.Tree;
@@ -34,7 +37,7 @@ public class SourcedAst
m_positions = m_trees.getSourcePositions();
m_classNameIndex = Maps.newHashMap();
- // index all the class names
+ // index all the class names from package imports
for( ImportTree importTree : m_tree.getImports() )
{
// ignore static imports for now
@@ -44,9 +47,9 @@ public class SourcedAst
}
// get the full and simple class names
- String fullName = importTree.getQualifiedIdentifier().toString();
+ String fullName = Descriptor.toJvmName( importTree.getQualifiedIdentifier().toString() );
String simpleName = fullName;
- String[] parts = fullName.split( "\\." );
+ String[] parts = fullName.split( "/" );
if( parts.length > 0 )
{
simpleName = parts[parts.length - 1];
@@ -54,6 +57,18 @@ public class SourcedAst
m_classNameIndex.put( simpleName, fullName );
}
+
+ // index the self class using the package name
+ String packageName = Descriptor.toJvmName( m_tree.getPackageName().toString() );
+ for( Tree typeTree : m_tree.getTypeDecls() )
+ {
+ if( typeTree instanceof ClassTree )
+ {
+ ClassTree classTree = (ClassTree)typeTree;
+ String className = classTree.getSimpleName().toString();
+ m_classNameIndex.put( className, packageName + "/" + className );
+ }
+ }
}
public int getStart( Tree node )
diff --git a/src/cuchaz/enigma/bytecode/MethodParameterWriter.java b/src/cuchaz/enigma/bytecode/MethodParameterWriter.java
index 1e5d1f0a..a8d3983f 100644
--- a/src/cuchaz/enigma/bytecode/MethodParameterWriter.java
+++ b/src/cuchaz/enigma/bytecode/MethodParameterWriter.java
@@ -10,9 +10,15 @@
******************************************************************************/
package cuchaz.enigma.bytecode;
+import java.util.ArrayList;
+import java.util.List;
+
import javassist.CtBehavior;
import javassist.CtClass;
-import javassist.bytecode.AttributeInfo;
+import javassist.bytecode.Descriptor;
+import cuchaz.enigma.mapping.ArgumentEntry;
+import cuchaz.enigma.mapping.ClassEntry;
+import cuchaz.enigma.mapping.MethodEntry;
import cuchaz.enigma.mapping.Translator;
public class MethodParameterWriter
@@ -27,9 +33,25 @@ public class MethodParameterWriter
public void writeMethodArguments( CtClass c )
{
// Procyon will read method arguments from the "MethodParameters" attribute, so write those
+ ClassEntry classEntry = new ClassEntry( Descriptor.toJvmName( c.getName() ) );
for( CtBehavior behavior : c.getDeclaredBehaviors() )
{
- AttributeInfo attribute = behavior.getMethodInfo().getAttribute( "MethodParameter" );
+ int numParams = Descriptor.numOfParameters( behavior.getMethodInfo().getDescriptor() );
+ if( numParams <= 0 )
+ {
+ continue;
+ }
+
+ // get the list of parameter names
+ MethodEntry methodEntry = new MethodEntry( classEntry, behavior.getMethodInfo().getName(), behavior.getSignature() );
+ List names = new ArrayList( numParams );
+ for( int i=0; i parameterNameIndices )
+ private MethodParametersAttribute( ConstPool pool, List parameterNameIndices )
{
- super( pool, "MethodParameters", writeStruct( attributeNameIndex, parameterNameIndices ) );
+ super( pool, "MethodParameters", writeStruct( parameterNameIndices ) );
}
- private static byte[] writeStruct( int attributeNameIndex, List parameterNameIndices )
+ public static void updateClass( MethodInfo info, List names )
{
- // JVM Spec says the struct looks like this:
+ // add the names to the class const pool
+ ConstPool constPool = info.getConstPool();
+ List parameterNameIndices = new ArrayList();
+ for( String name : names )
+ {
+ if( name != null )
+ {
+ parameterNameIndices.add( constPool.addUtf8Info( name ) );
+ }
+ else
+ {
+ parameterNameIndices.add( 0 );
+ }
+ }
+
+ // add the attribute to the method
+ info.addAttribute( new MethodParametersAttribute( constPool, parameterNameIndices ) );
+ }
+
+ private static byte[] writeStruct( List parameterNameIndices )
+ {
+ // JVM 8 Spec says the struct looks like this:
// http://cr.openjdk.java.net/~mr/se/8/java-se-8-fr-spec-01/java-se-8-jvms-fr-diffs.pdf
- // uint16 name_index -> points to UTF8 entry in constant pool that says "MethodParameters"
- // uint32 length -> length of this struct, minus 6 bytes (ie, length of num_params and parameter array)
// uint8 num_params
// for each param:
// uint16 name_index -> points to UTF8 entry in constant pool, or 0 for no entry
@@ -43,20 +64,13 @@ public class MethodParametersAttribute extends AttributeInfo
// the writeShort(), writeByte() methods will read 16,8 low-order bits from the int argument
// as long as the int argument is in range of the unsigned short/byte type, it will be written as an unsigned short/byte
// if the int is out of range, the byte stream won't look the way we want and weird things will happen
+ final int SIZEOF_UINT8 = 1;
final int SIZEOF_UINT16 = 2;
final int MAX_UINT8 = ( 1 << 8 ) - 1;
final int MAX_UINT16 = ( 1 << 16 ) - 1;
- final long MAX_UINT32 = ( 1 << 32 ) - 1;
try
{
- assert( attributeNameIndex >= 0 && attributeNameIndex <= MAX_UINT16 );
- out.writeShort( attributeNameIndex );
-
- long length = SIZEOF_UINT16 + parameterNameIndices.size()*( SIZEOF_UINT16 + SIZEOF_UINT16 );
- assert( length >= 0 && length <= MAX_UINT32 );
- out.writeInt( (int)length );
-
assert( parameterNameIndices.size() >= 0 && parameterNameIndices.size() <= MAX_UINT8 );
out.writeByte( parameterNameIndices.size() );
@@ -70,7 +84,9 @@ public class MethodParametersAttribute extends AttributeInfo
}
out.close();
- return buf.toByteArray();
+ byte[] data = buf.toByteArray();
+ assert( data.length == SIZEOF_UINT8 + parameterNameIndices.size()*( SIZEOF_UINT16 + SIZEOF_UINT16 ) );
+ return data;
}
catch( IOException ex )
{
diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java
index d448dc28..3f46b6ec 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.File;
import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
@@ -54,6 +55,7 @@ import cuchaz.enigma.Constants;
import cuchaz.enigma.analysis.SourceIndex;
import cuchaz.enigma.mapping.ArgumentEntry;
import cuchaz.enigma.mapping.ClassEntry;
+import cuchaz.enigma.mapping.Entry;
import cuchaz.enigma.mapping.EntryPair;
import cuchaz.enigma.mapping.FieldEntry;
import cuchaz.enigma.mapping.MethodEntry;
@@ -101,9 +103,9 @@ public class Gui
private JMenuItem m_closeMappingsMenu;
// state
- private EntryPair m_selectedEntryPair;
+ private EntryPair m_selectedEntryPair;
private JFileChooser m_jarFileChooser;
- private JFileChooser m_mappingFileChooser;
+ private JFileChooser m_mappingsFileChooser;
public Gui( )
{
@@ -111,7 +113,7 @@ public class Gui
// init file choosers
m_jarFileChooser = new JFileChooser();
- m_mappingFileChooser = new JFileChooser();
+ m_mappingsFileChooser = new JFileChooser();
// init frame
m_frame = new JFrame( Constants.Name );
@@ -279,11 +281,11 @@ public class Gui
@Override
public void actionPerformed( ActionEvent event )
{
- if( m_mappingFileChooser.showOpenDialog( m_frame ) == JFileChooser.APPROVE_OPTION )
+ if( m_mappingsFileChooser.showOpenDialog( m_frame ) == JFileChooser.APPROVE_OPTION )
{
try
{
- m_controller.openMappings( m_mappingFileChooser.getSelectedFile() );
+ m_controller.openMappings( m_mappingsFileChooser.getSelectedFile() );
}
catch( IOException ex )
{
@@ -304,7 +306,7 @@ public class Gui
{
try
{
- m_controller.saveMappings( m_mappingFileChooser.getSelectedFile() );
+ m_controller.saveMappings( m_mappingsFileChooser.getSelectedFile() );
}
catch( IOException ex )
{
@@ -322,11 +324,11 @@ public class Gui
@Override
public void actionPerformed( ActionEvent event )
{
- if( m_mappingFileChooser.showSaveDialog( m_frame ) == JFileChooser.APPROVE_OPTION )
+ if( m_mappingsFileChooser.showSaveDialog( m_frame ) == JFileChooser.APPROVE_OPTION )
{
try
{
- m_controller.saveMappings( m_mappingFileChooser.getSelectedFile() );
+ m_controller.saveMappings( m_mappingsFileChooser.getSelectedFile() );
m_saveMappingsMenu.setEnabled( true );
}
catch( IOException ex )
@@ -440,9 +442,10 @@ public class Gui
}
}
- public void setMappingsLoaded( boolean isLoaded )
+ public void setMappingsFile( File file )
{
- m_saveMappingsMenu.setEnabled( isLoaded );
+ m_mappingsFileChooser.setSelectedFile( file );
+ m_saveMappingsMenu.setEnabled( file != null );
}
public void setSource( String source )
@@ -493,7 +496,8 @@ public class Gui
redraw();
}
- private void showEntryPair( EntryPair pair )
+ @SuppressWarnings( "unchecked" )
+ private void showEntryPair( EntryPair pair )
{
if( pair == null )
{
@@ -514,19 +518,19 @@ public class Gui
m_actionPanel.add( dynamicPanel );
if( pair.deobf instanceof ClassEntry )
{
- showEntry( (ClassEntry)pair.deobf, dynamicPanel );
+ showClassEntryPair( (EntryPair extends ClassEntry>)pair, dynamicPanel );
}
else if( pair.deobf instanceof FieldEntry )
{
- showEntry( (FieldEntry)pair.deobf, dynamicPanel );
+ showFieldEntryPair( (EntryPair extends FieldEntry>)pair, dynamicPanel );
}
else if( pair.deobf instanceof MethodEntry )
{
- showEntry( (MethodEntry)pair.deobf, dynamicPanel );
+ showMethodEntryPair( (EntryPair extends MethodEntry>)pair, dynamicPanel );
}
else if( pair.deobf instanceof ArgumentEntry )
{
- showEntry( (ArgumentEntry)pair.deobf, dynamicPanel );
+ showArgumentEntryPair( (EntryPair extends ArgumentEntry>)pair, dynamicPanel );
}
else
{
@@ -536,30 +540,30 @@ public class Gui
redraw();
}
- private void showEntry( ClassEntry entry, JPanel panel )
+ private void showClassEntryPair( EntryPair extends ClassEntry> pair, JPanel panel )
{
m_typeLabel.setText( "Class: " );
}
- private void showEntry( FieldEntry entry, JPanel panel )
+ private void showFieldEntryPair( EntryPair extends FieldEntry> pair, JPanel panel )
{
m_typeLabel.setText( "Field: " );
- addNameValue( panel, "Class", entry.getClassEntry().getName() );
+ addNameValue( panel, "Class", pair.obf.getClassEntry().getName() + " <-> " + pair.deobf.getClassEntry().getName() );
}
- private void showEntry( MethodEntry entry, JPanel panel )
+ private void showMethodEntryPair( EntryPair extends MethodEntry> pair, JPanel panel )
{
m_typeLabel.setText( "Method: " );
- addNameValue( panel, "Class", entry.getClassEntry().getName() );
- addNameValue( panel, "Signature", entry.getSignature() );
+ addNameValue( panel, "Class", pair.obf.getClassEntry().getName() + " <-> " + pair.deobf.getClassEntry().getName() );
+ addNameValue( panel, "Signature", pair.obf.getSignature() + " <-> " + pair.deobf.getSignature() );
}
- private void showEntry( ArgumentEntry entry, JPanel panel )
+ private void showArgumentEntryPair( EntryPair extends ArgumentEntry> pair, JPanel panel )
{
m_typeLabel.setText( "Argument: " );
- addNameValue( panel, "Class", entry.getMethodEntry().getClassEntry().getName() );
- addNameValue( panel, "Method", entry.getMethodEntry().getName() );
- addNameValue( panel, "Index", Integer.toString( entry.getIndex() ) );
+ addNameValue( panel, "Class", pair.obf.getClassEntry().getName() + " <-> " + pair.deobf.getClassEntry().getName() );
+ addNameValue( panel, "Method", pair.obf.getMethodEntry().getName() + " <-> " + pair.deobf.getMethodEntry().getName() );
+ addNameValue( panel, "Index", Integer.toString( pair.obf.getIndex() ) );
}
private void addNameValue( JPanel container, String name, String value )
diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java
index ce1c31bd..6704ef8a 100644
--- a/src/cuchaz/enigma/gui/GuiController.java
+++ b/src/cuchaz/enigma/gui/GuiController.java
@@ -62,7 +62,7 @@ public class GuiController
FileReader in = new FileReader( file );
m_deobfuscator.setMappings( new MappingsReader().read( in ) );
in.close();
- m_gui.setMappingsLoaded( true );
+ m_gui.setMappingsFile( file );
refreshClasses();
refreshOpenFiles();
}
@@ -78,7 +78,7 @@ public class GuiController
public void closeMappings( )
{
m_deobfuscator.setMappings( null );
- m_gui.setMappingsLoaded( false );
+ m_gui.setMappingsFile( null );
refreshOpenFiles();
}
@@ -88,7 +88,7 @@ public class GuiController
deobfuscate( m_currentFile );
}
- public EntryPair getEntryPair( int pos )
+ public EntryPair getEntryPair( int pos )
{
if( m_index == null )
{
@@ -100,7 +100,7 @@ public class GuiController
{
return null;
}
- return new EntryPair( m_deobfuscator.obfuscate( deobfEntry ), deobfEntry );
+ return new EntryPair( m_deobfuscator.obfuscate( deobfEntry ), deobfEntry );
}
public void rename( Entry obfsEntry, String newName )
diff --git a/src/cuchaz/enigma/mapping/EntryPair.java b/src/cuchaz/enigma/mapping/EntryPair.java
index e40e9992..e3325b37 100644
--- a/src/cuchaz/enigma/mapping/EntryPair.java
+++ b/src/cuchaz/enigma/mapping/EntryPair.java
@@ -10,37 +10,15 @@
******************************************************************************/
package cuchaz.enigma.mapping;
-import cuchaz.enigma.Util;
-public class EntryPair
+public class EntryPair
{
- public Entry obf;
- public Entry deobf;
+ public T obf;
+ public T deobf;
- public EntryPair( Entry obf, Entry deobf )
+ public EntryPair( T obf, T deobf )
{
this.obf = obf;
this.deobf = deobf;
}
-
- @Override
- public int hashCode( )
- {
- return Util.combineHashesOrdered( obf, deobf );
- }
-
- @Override
- public boolean equals( Object other )
- {
- if( other instanceof EntryPair )
- {
- return equals( (EntryPair)other );
- }
- return false;
- }
-
- public boolean equals( EntryPair other )
- {
- return obf.equals( other.obf ) && deobf.equals( other.deobf );
- }
}
diff --git a/src/cuchaz/enigma/mapping/MethodMapping.java b/src/cuchaz/enigma/mapping/MethodMapping.java
index f2bc54d1..1cdc38a1 100644
--- a/src/cuchaz/enigma/mapping/MethodMapping.java
+++ b/src/cuchaz/enigma/mapping/MethodMapping.java
@@ -127,7 +127,7 @@ public class MethodMapping implements Serializable
{
buf.append( "\t\t" );
buf.append( argumentMapping.getIndex() );
- buf.append( " <-> " );
+ buf.append( " -> " );
buf.append( argumentMapping.getName() );
buf.append( "\n" );
}
--
cgit v1.2.3
From 57f45b0409d5363782052183bb090175c469f89a Mon Sep 17 00:00:00 2001
From: jeff
Date: Mon, 4 Aug 2014 00:26:48 -0400
Subject: added stable save order for mappings to hopefully help with merging
added color-coding for source identifiers redesigned rename GUI customized
editor pane, added popup menu finished name validation added last-chance save
on window close
---
src/cuchaz/enigma/ClassFile.java | 31 +-
src/cuchaz/enigma/Deobfuscator.java | 119 ++++---
src/cuchaz/enigma/analysis/SourceIndex.java | 4 +-
src/cuchaz/enigma/analysis/SourcedAst.java | 15 +-
src/cuchaz/enigma/gui/AboutDialog.java | 2 -
src/cuchaz/enigma/gui/BoxHighlightPainter.java | 16 +-
src/cuchaz/enigma/gui/BrowserCaret.java | 50 +++
src/cuchaz/enigma/gui/ClassListCellRenderer.java | 40 ---
.../gui/DeobfuscatedClassListCellRenderer.java | 43 +++
.../enigma/gui/DeobfuscatedHighlightPainter.java | 22 ++
src/cuchaz/enigma/gui/Gui.java | 354 ++++++++++++++++-----
src/cuchaz/enigma/gui/GuiController.java | 94 ++++--
.../gui/ObfuscatedClassListCellRenderer.java | 42 +++
.../enigma/gui/ObfuscatedHighlightPainter.java | 22 ++
src/cuchaz/enigma/mapping/ArgumentMapping.java | 12 +-
src/cuchaz/enigma/mapping/ClassMapping.java | 27 +-
src/cuchaz/enigma/mapping/EntryPair.java | 6 +-
src/cuchaz/enigma/mapping/FieldMapping.java | 12 +-
.../enigma/mapping/IllegalNameException.java | 29 ++
src/cuchaz/enigma/mapping/MappingsWriter.java | 22 +-
src/cuchaz/enigma/mapping/MethodMapping.java | 12 +-
src/cuchaz/enigma/mapping/NameValidator.java | 52 ++-
src/cuchaz/enigma/mapping/Renamer.java | 19 --
23 files changed, 746 insertions(+), 299 deletions(-)
create mode 100644 src/cuchaz/enigma/gui/BrowserCaret.java
delete mode 100644 src/cuchaz/enigma/gui/ClassListCellRenderer.java
create mode 100644 src/cuchaz/enigma/gui/DeobfuscatedClassListCellRenderer.java
create mode 100644 src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java
create mode 100644 src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java
create mode 100644 src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java
create mode 100644 src/cuchaz/enigma/mapping/IllegalNameException.java
diff --git a/src/cuchaz/enigma/ClassFile.java b/src/cuchaz/enigma/ClassFile.java
index c3c72a47..613b379d 100644
--- a/src/cuchaz/enigma/ClassFile.java
+++ b/src/cuchaz/enigma/ClassFile.java
@@ -13,39 +13,24 @@ package cuchaz.enigma;
public class ClassFile
{
- private String m_obfName;
- private String m_deobfName;
+ private String m_name;
- public ClassFile( String obfName )
+ public ClassFile( String name )
{
- m_obfName = obfName;
- }
-
- public String getName( )
- {
- if( m_deobfName != null )
+ if( name.indexOf( '.' ) >= 0 )
{
- return m_deobfName;
+ throw new IllegalArgumentException( "Class name should be in JVM format!" );
}
- return m_obfName;
- }
-
- public String getObfName( )
- {
- return m_obfName;
+ m_name = name;
}
- public String getDeobfName( )
- {
- return m_deobfName;
- }
- public void setDeobfName( String val )
+ public String getName( )
{
- m_deobfName = val;
+ return m_name;
}
public String getPath( )
{
- return m_deobfName.replace( ".", "/" ) + ".class";
+ return m_name.replace( ".", "/" ) + ".class";
}
}
diff --git a/src/cuchaz/enigma/Deobfuscator.java b/src/cuchaz/enigma/Deobfuscator.java
index edc29e17..a3937b4c 100644
--- a/src/cuchaz/enigma/Deobfuscator.java
+++ b/src/cuchaz/enigma/Deobfuscator.java
@@ -17,6 +17,7 @@ import java.io.InputStream;
import java.io.StringWriter;
import java.util.Enumeration;
import java.util.List;
+import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@@ -32,7 +33,6 @@ import cuchaz.enigma.mapping.Entry;
import cuchaz.enigma.mapping.FieldEntry;
import cuchaz.enigma.mapping.Mappings;
import cuchaz.enigma.mapping.MethodEntry;
-import cuchaz.enigma.mapping.NameValidator;
import cuchaz.enigma.mapping.Renamer;
import cuchaz.enigma.mapping.TranslationDirection;
import cuchaz.enigma.mapping.Translator;
@@ -100,26 +100,28 @@ public class Deobfuscator
) );
}
- public void getSortedClasses( List obfClasses, List deobfClasses )
+ public void getSeparatedClasses( List obfClasses, Map deobfClasses )
{
Enumeration entries = m_jar.entries();
while( entries.hasMoreElements() )
{
JarEntry entry = entries.nextElement();
- // get the class name
- String obfName = NameValidator.fileNameToClassName( entry.getName() );
- if( obfName == null )
+ // skip everything but class files
+ if( !entry.getName().endsWith( ".class" ) )
{
continue;
}
- ClassFile classFile = new ClassFile( obfName );
+ // get the class name from the file
+ String className = entry.getName().substring( 0, entry.getName().length() - 6 );
+ ClassFile classFile = new ClassFile( className );
+
+ // separate the classes
ClassMapping classMapping = m_mappings.getClassByObf( classFile.getName() );
if( classMapping != null )
{
- classFile.setDeobfName( classMapping.getDeobfName() );
- deobfClasses.add( classFile );
+ deobfClasses.put( classFile, classMapping.getDeobfName() );
}
else
{
@@ -130,84 +132,123 @@ public class Deobfuscator
public String getSource( final ClassFile classFile )
{
+ // is this class deobfuscated?
+ // we need to tell the decompiler the deobfuscated name so it doesn't get freaked out
+ // the decompiler only sees the deobfuscated class, so we need to load it by the deobfuscated name
+ String deobfName = classFile.getName();
+ ClassMapping classMapping = m_mappings.getClassByObf( classFile.getName() );
+ if( classMapping != null )
+ {
+ deobfName = classMapping.getDeobfName();
+ }
+
+ // decompile it!
StringWriter buf = new StringWriter();
- Decompiler.decompile( classFile.getObfName(), new PlainTextOutput( buf ), m_settings );
+ Decompiler.decompile( deobfName, new PlainTextOutput( buf ), m_settings );
return buf.toString();
}
// NOTE: these methods are a bit messy... oh well
- public void rename( Entry entry, String newName )
+ public void rename( Entry obfEntry, String newName )
{
- if( entry instanceof ClassEntry )
+ if( obfEntry instanceof ClassEntry )
{
- m_renamer.setClassName( (ClassEntry)entry, newName );
+ m_renamer.setClassName( (ClassEntry)obfEntry, newName );
}
- else if( entry instanceof FieldEntry )
+ else if( obfEntry instanceof FieldEntry )
{
- m_renamer.setFieldName( (FieldEntry)entry, newName );
+ m_renamer.setFieldName( (FieldEntry)obfEntry, newName );
}
- else if( entry instanceof MethodEntry )
+ else if( obfEntry instanceof MethodEntry )
{
- m_renamer.setMethodName( (MethodEntry)entry, newName );
+ m_renamer.setMethodName( (MethodEntry)obfEntry, newName );
}
- else if( entry instanceof ArgumentEntry )
+ else if( obfEntry instanceof ArgumentEntry )
{
- m_renamer.setArgumentName( (ArgumentEntry)entry, newName );
+ m_renamer.setArgumentName( (ArgumentEntry)obfEntry, newName );
}
else
{
- throw new Error( "Unknown entry type: " + entry.getClass().getName() );
+ throw new Error( "Unknown entry type: " + obfEntry.getClass().getName() );
}
}
- public Entry obfuscate( Entry in )
+ public Entry obfuscateEntry( Entry deobfEntry )
{
Translator translator = m_mappings.getTranslator( m_ancestries, TranslationDirection.Obfuscating );
- if( in instanceof ClassEntry )
+ if( deobfEntry instanceof ClassEntry )
+ {
+ return translator.translateEntry( (ClassEntry)deobfEntry );
+ }
+ else if( deobfEntry instanceof FieldEntry )
+ {
+ return translator.translateEntry( (FieldEntry)deobfEntry );
+ }
+ else if( deobfEntry instanceof MethodEntry )
+ {
+ return translator.translateEntry( (MethodEntry)deobfEntry );
+ }
+ else if( deobfEntry instanceof ArgumentEntry )
+ {
+ return translator.translateEntry( (ArgumentEntry)deobfEntry );
+ }
+ else
+ {
+ throw new Error( "Unknown entry type: " + deobfEntry.getClass().getName() );
+ }
+ }
+
+ public Entry deobfuscateEntry( Entry obfEntry )
+ {
+ Translator translator = m_mappings.getTranslator( m_ancestries, TranslationDirection.Deobfuscating );
+ if( obfEntry instanceof ClassEntry )
{
- return translator.translateEntry( (ClassEntry)in );
+ return translator.translateEntry( (ClassEntry)obfEntry );
}
- else if( in instanceof FieldEntry )
+ else if( obfEntry instanceof FieldEntry )
{
- return translator.translateEntry( (FieldEntry)in );
+ return translator.translateEntry( (FieldEntry)obfEntry );
}
- else if( in instanceof MethodEntry )
+ else if( obfEntry instanceof MethodEntry )
{
- return translator.translateEntry( (MethodEntry)in );
+ return translator.translateEntry( (MethodEntry)obfEntry );
}
- else if( in instanceof ArgumentEntry )
+ else if( obfEntry instanceof ArgumentEntry )
{
- return translator.translateEntry( (ArgumentEntry)in );
+ return translator.translateEntry( (ArgumentEntry)obfEntry );
}
else
{
- throw new Error( "Unknown entry type: " + in.getClass().getName() );
+ throw new Error( "Unknown entry type: " + obfEntry.getClass().getName() );
}
}
- public Entry deobfuscate( Entry in )
+ public boolean hasMapping( Entry obfEntry )
{
Translator translator = m_mappings.getTranslator( m_ancestries, TranslationDirection.Deobfuscating );
- if( in instanceof ClassEntry )
+ if( obfEntry instanceof ClassEntry )
{
- return translator.translateEntry( (ClassEntry)in );
+ String deobfName = translator.translate( (ClassEntry)obfEntry );
+ return deobfName != null && !deobfName.equals( obfEntry.getName() );
}
- else if( in instanceof FieldEntry )
+ else if( obfEntry instanceof FieldEntry )
{
- return translator.translateEntry( (FieldEntry)in );
+ String deobfName = translator.translate( (FieldEntry)obfEntry );
+ return deobfName != null && !deobfName.equals( obfEntry.getName() );
}
- else if( in instanceof MethodEntry )
+ else if( obfEntry instanceof MethodEntry )
{
- return translator.translateEntry( (MethodEntry)in );
+ String deobfName = translator.translate( (MethodEntry)obfEntry );
+ return deobfName != null && !deobfName.equals( obfEntry.getName() );
}
- else if( in instanceof ArgumentEntry )
+ else if( obfEntry instanceof ArgumentEntry )
{
- return translator.translateEntry( (ArgumentEntry)in );
+ return translator.translate( (ArgumentEntry)obfEntry ) != null;
}
else
{
- throw new Error( "Unknown entry type: " + in.getClass().getName() );
+ throw new Error( "Unknown entry type: " + obfEntry.getClass().getName() );
}
}
}
diff --git a/src/cuchaz/enigma/analysis/SourceIndex.java b/src/cuchaz/enigma/analysis/SourceIndex.java
index ee92d1ed..61c833ce 100644
--- a/src/cuchaz/enigma/analysis/SourceIndex.java
+++ b/src/cuchaz/enigma/analysis/SourceIndex.java
@@ -52,7 +52,7 @@ public class SourceIndex implements Iterable>
return m_tokenToEntry.get( token );
}
- public Entry getEntry( int pos )
+ public Map.Entry getEntry( int pos )
{
// linear search is fast enough for now
for( Map.Entry entry : this )
@@ -60,7 +60,7 @@ public class SourceIndex implements Iterable>
Token token = entry.getValue();
if( pos >= token.start && pos <= token.end() )
{
- return entry.getKey();
+ return entry;
}
}
return null;
diff --git a/src/cuchaz/enigma/analysis/SourcedAst.java b/src/cuchaz/enigma/analysis/SourcedAst.java
index 52a34534..968c8804 100644
--- a/src/cuchaz/enigma/analysis/SourcedAst.java
+++ b/src/cuchaz/enigma/analysis/SourcedAst.java
@@ -59,14 +59,17 @@ public class SourcedAst
}
// index the self class using the package name
- String packageName = Descriptor.toJvmName( m_tree.getPackageName().toString() );
- for( Tree typeTree : m_tree.getTypeDecls() )
+ if( m_tree.getPackageName() != null )
{
- if( typeTree instanceof ClassTree )
+ String packageName = Descriptor.toJvmName( m_tree.getPackageName().toString() );
+ for( Tree typeTree : m_tree.getTypeDecls() )
{
- ClassTree classTree = (ClassTree)typeTree;
- String className = classTree.getSimpleName().toString();
- m_classNameIndex.put( className, packageName + "/" + className );
+ if( typeTree instanceof ClassTree )
+ {
+ ClassTree classTree = (ClassTree)typeTree;
+ String className = classTree.getSimpleName().toString();
+ m_classNameIndex.put( className, packageName + "/" + className );
+ }
}
}
}
diff --git a/src/cuchaz/enigma/gui/AboutDialog.java b/src/cuchaz/enigma/gui/AboutDialog.java
index 79b75432..a245956e 100644
--- a/src/cuchaz/enigma/gui/AboutDialog.java
+++ b/src/cuchaz/enigma/gui/AboutDialog.java
@@ -18,8 +18,6 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
-import javax.swing.Box;
-import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
diff --git a/src/cuchaz/enigma/gui/BoxHighlightPainter.java b/src/cuchaz/enigma/gui/BoxHighlightPainter.java
index 22db28b7..b9474ff8 100644
--- a/src/cuchaz/enigma/gui/BoxHighlightPainter.java
+++ b/src/cuchaz/enigma/gui/BoxHighlightPainter.java
@@ -19,10 +19,16 @@ import javax.swing.text.BadLocationException;
import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;
-public class BoxHighlightPainter implements Highlighter.HighlightPainter
+public abstract class BoxHighlightPainter implements Highlighter.HighlightPainter
{
- private static final Color FillColor = new Color( 230, 230, 230 );
- private static final Color BorderColor = new Color( 100, 100, 100 );
+ private Color m_fillColor;
+ private Color m_borderColor;
+
+ protected BoxHighlightPainter( Color fillColor, Color borderColor )
+ {
+ m_fillColor = fillColor;
+ m_borderColor = borderColor;
+ }
@Override
public void paint( Graphics g, int start, int end, Shape shape, JTextComponent text )
@@ -39,11 +45,11 @@ public class BoxHighlightPainter implements Highlighter.HighlightPainter
bounds.height -= 2;
// fill the area
- g.setColor( FillColor );
+ g.setColor( m_fillColor );
g.fillRoundRect( bounds.x, bounds.y, bounds.width, bounds.height, 4, 4 );
// draw a box around the area
- g.setColor( BorderColor );
+ g.setColor( m_borderColor );
g.drawRoundRect( bounds.x, bounds.y, bounds.width, bounds.height, 4, 4 );
}
catch( BadLocationException ex )
diff --git a/src/cuchaz/enigma/gui/BrowserCaret.java b/src/cuchaz/enigma/gui/BrowserCaret.java
new file mode 100644
index 00000000..f7e608bb
--- /dev/null
+++ b/src/cuchaz/enigma/gui/BrowserCaret.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * 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.Graphics;
+import java.awt.Shape;
+
+import javax.swing.text.DefaultCaret;
+import javax.swing.text.Highlighter;
+import javax.swing.text.JTextComponent;
+
+public class BrowserCaret extends DefaultCaret
+{
+ private static final long serialVersionUID = 1158977422507969940L;
+
+ private static final Highlighter.HighlightPainter m_selectionPainter = new Highlighter.HighlightPainter( )
+ {
+ @Override
+ public void paint( Graphics g, int p0, int p1, Shape bounds, JTextComponent c )
+ {
+ // don't paint anything
+ }
+ };
+
+ @Override
+ public boolean isSelectionVisible( )
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isVisible( )
+ {
+ return true;
+ }
+
+ @Override
+ public Highlighter.HighlightPainter getSelectionPainter( )
+ {
+ return m_selectionPainter;
+ }
+}
diff --git a/src/cuchaz/enigma/gui/ClassListCellRenderer.java b/src/cuchaz/enigma/gui/ClassListCellRenderer.java
deleted file mode 100644
index 302f140b..00000000
--- a/src/cuchaz/enigma/gui/ClassListCellRenderer.java
+++ /dev/null
@@ -1,40 +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.gui;
-
-import java.awt.Component;
-
-import javax.swing.DefaultListCellRenderer;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.ListCellRenderer;
-
-import cuchaz.enigma.ClassFile;
-
-public class ClassListCellRenderer implements ListCellRenderer
-{
- private DefaultListCellRenderer m_defaultRenderer;
-
- public ClassListCellRenderer( )
- {
- m_defaultRenderer = new DefaultListCellRenderer();
- }
-
- @Override
- public Component getListCellRendererComponent( JList extends ClassFile> list, ClassFile classFile, int index, boolean isSelected, boolean hasFocus )
- {
- JLabel label = (JLabel)m_defaultRenderer.getListCellRendererComponent( list, classFile, index, isSelected, hasFocus );
-
- label.setText( classFile.getName() );
-
- return label;
- }
-}
diff --git a/src/cuchaz/enigma/gui/DeobfuscatedClassListCellRenderer.java b/src/cuchaz/enigma/gui/DeobfuscatedClassListCellRenderer.java
new file mode 100644
index 00000000..3a8729d2
--- /dev/null
+++ b/src/cuchaz/enigma/gui/DeobfuscatedClassListCellRenderer.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * 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 java.util.Map;
+
+import javassist.bytecode.Descriptor;
+
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.ListCellRenderer;
+
+import cuchaz.enigma.ClassFile;
+
+public class DeobfuscatedClassListCellRenderer implements ListCellRenderer>
+{
+ private DefaultListCellRenderer m_defaultRenderer;
+
+ public DeobfuscatedClassListCellRenderer( )
+ {
+ m_defaultRenderer = new DefaultListCellRenderer();
+ }
+
+ @Override
+ public Component getListCellRendererComponent( JList extends Map.Entry> list, Map.Entry entry, int index, boolean isSelected, boolean hasFocus )
+ {
+ JLabel label = (JLabel)m_defaultRenderer.getListCellRendererComponent( list, entry, index, isSelected, hasFocus );
+
+ label.setText( Descriptor.toJavaName( entry.getValue() ) );
+
+ return label;
+ }
+}
diff --git a/src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java b/src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java
new file mode 100644
index 00000000..6a428842
--- /dev/null
+++ b/src/cuchaz/enigma/gui/DeobfuscatedHighlightPainter.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * 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.Color;
+
+public class DeobfuscatedHighlightPainter extends BoxHighlightPainter
+{
+ public DeobfuscatedHighlightPainter( )
+ {
+ // green ish
+ super( new Color( 220, 255, 220 ), new Color( 80, 160, 80 ) );
+ }
+}
diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java
index 3f46b6ec..87b93085 100644
--- a/src/cuchaz/enigma/gui/Gui.java
+++ b/src/cuchaz/enigma/gui/Gui.java
@@ -11,6 +11,7 @@
package cuchaz.enigma.gui;
import java.awt.BorderLayout;
+import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
@@ -18,18 +19,21 @@ import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import java.util.Map;
import java.util.Vector;
import javax.swing.BorderFactory;
-import javax.swing.BoxLayout;
-import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
@@ -38,7 +42,9 @@ import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextField;
@@ -47,17 +53,19 @@ import javax.swing.WindowConstants;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.BadLocationException;
+import javax.swing.text.Highlighter;
import jsyntaxpane.DefaultSyntaxKit;
+import jsyntaxpane.SyntaxDocument;
import jsyntaxpane.Token;
import cuchaz.enigma.ClassFile;
import cuchaz.enigma.Constants;
-import cuchaz.enigma.analysis.SourceIndex;
import cuchaz.enigma.mapping.ArgumentEntry;
import cuchaz.enigma.mapping.ClassEntry;
import cuchaz.enigma.mapping.Entry;
import cuchaz.enigma.mapping.EntryPair;
import cuchaz.enigma.mapping.FieldEntry;
+import cuchaz.enigma.mapping.IllegalNameException;
import cuchaz.enigma.mapping.MethodEntry;
public class Gui
@@ -86,14 +94,11 @@ public class Gui
// controls
private JFrame m_frame;
private JList m_obfClasses;
- private JList m_deobfClasses;
+ private JList> m_deobfClasses;
private JEditorPane m_editor;
- private JPanel m_actionPanel;
- private JPanel m_renamePanel;
- private JLabel m_typeLabel;
- private JTextField m_nameField;
- private JButton m_renameButton;
- private BoxHighlightPainter m_highlightPainter;
+ private JPanel m_infoPanel;
+ private BoxHighlightPainter m_obfuscatedHighlightPainter;
+ private BoxHighlightPainter m_deobfuscatedHighlightPainter;
// dynamic menu items
private JMenuItem m_closeJarMenu;
@@ -101,6 +106,7 @@ public class Gui
private JMenuItem m_saveMappingsMenu;
private JMenuItem m_saveMappingsAsMenu;
private JMenuItem m_closeMappingsMenu;
+ private JMenuItem m_renameMenu;
// state
private EntryPair m_selectedEntryPair;
@@ -124,7 +130,7 @@ public class Gui
m_obfClasses = new JList();
m_obfClasses.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
m_obfClasses.setLayoutOrientation( JList.VERTICAL );
- m_obfClasses.setCellRenderer( new ClassListCellRenderer() );
+ m_obfClasses.setCellRenderer( new ObfuscatedClassListCellRenderer() );
m_obfClasses.addMouseListener( new MouseAdapter()
{
public void mouseClicked( MouseEvent event )
@@ -146,20 +152,20 @@ public class Gui
obfPanel.add( obfScroller, BorderLayout.CENTER );
// init deobfuscated classes list
- m_deobfClasses = new JList();
+ m_deobfClasses = new JList>();
m_deobfClasses.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
m_deobfClasses.setLayoutOrientation( JList.VERTICAL );
- m_deobfClasses.setCellRenderer( new ClassListCellRenderer() );
+ m_deobfClasses.setCellRenderer( new DeobfuscatedClassListCellRenderer() );
m_deobfClasses.addMouseListener( new MouseAdapter()
{
public void mouseClicked( MouseEvent event )
{
if( event.getClickCount() == 2 )
{
- ClassFile selected = m_deobfClasses.getSelectedValue();
+ Map.Entry selected = m_deobfClasses.getSelectedValue();
if( selected != null )
{
- m_controller.deobfuscateClass( selected );
+ m_controller.deobfuscateClass( selected.getKey() );
}
}
}
@@ -170,39 +176,20 @@ public class Gui
deobfPanel.add( new JLabel( "De-obfuscated Classes" ), BorderLayout.NORTH );
deobfPanel.add( deobfScroller, BorderLayout.CENTER );
- // init action panel
- m_actionPanel = new JPanel();
- m_actionPanel.setLayout( new BoxLayout( m_actionPanel, BoxLayout.Y_AXIS ) );
- m_actionPanel.setPreferredSize( new Dimension( 0, 120 ) );
- m_actionPanel.setBorder( BorderFactory.createTitledBorder( "Identifier Info" ) );
- m_nameField = new JTextField( 26 );
- m_renameButton = new JButton( "Rename" );
- m_renameButton.addActionListener( new ActionListener( )
- {
- @Override
- public void actionPerformed( ActionEvent event )
- {
- if( m_selectedEntryPair != null )
- {
- m_controller.rename( m_selectedEntryPair.obf, m_nameField.getText() );
- }
- }
- } );
- m_renamePanel = new JPanel();
- m_renamePanel.setLayout( new FlowLayout( FlowLayout.LEFT, 6, 0 ) );
- m_typeLabel = new JLabel( "LongName:", JLabel.RIGHT );
- // NOTE: this looks ridiculous, but it fixes the label size to the size of current text
- m_typeLabel.setPreferredSize( m_typeLabel.getPreferredSize() );
- m_renamePanel.add( m_typeLabel );
- m_renamePanel.add( m_nameField );
- m_renamePanel.add( m_renameButton );
+ // init info panel
+ m_infoPanel = new JPanel();
+ m_infoPanel.setLayout( new GridLayout( 4, 1, 0, 0 ) );
+ m_infoPanel.setPreferredSize( new Dimension( 0, 100 ) );
+ m_infoPanel.setBorder( BorderFactory.createTitledBorder( "Identifier Info" ) );
clearEntryPair();
// init editor
DefaultSyntaxKit.initKit();
- m_highlightPainter = new BoxHighlightPainter();
+ m_obfuscatedHighlightPainter = new ObfuscatedHighlightPainter();
+ m_deobfuscatedHighlightPainter = new DeobfuscatedHighlightPainter();
m_editor = new JEditorPane();
m_editor.setEditable( false );
+ m_editor.setCaret( new BrowserCaret() );
JScrollPane sourceScroller = new JScrollPane( m_editor );
m_editor.setContentType( "text/java" );
m_editor.addCaretListener( new CaretListener( )
@@ -214,19 +201,55 @@ public class Gui
if( m_selectedEntryPair != null )
{
showEntryPair( m_selectedEntryPair );
+ m_renameMenu.setEnabled( true );
}
else
{
clearEntryPair();
+ m_renameMenu.setEnabled( false );
}
}
} );
+ m_editor.addKeyListener( new KeyAdapter( )
+ {
+ @Override
+ public void keyPressed( KeyEvent event )
+ {
+ switch( event.getKeyCode() )
+ {
+ case KeyEvent.VK_R:
+ startRename();
+ break;
+ }
+ }
+ } );
+
+ // turn off token highlighting (it's wrong most of the time anyway...)
+ DefaultSyntaxKit kit = (DefaultSyntaxKit)m_editor.getEditorKit();
+ kit.toggleComponent( m_editor, "jsyntaxpane.components.TokenMarker" );
+
+ // init editor popup menu
+ JPopupMenu popupMenu = new JPopupMenu();
+ m_editor.setComponentPopupMenu( popupMenu );
+ {
+ JMenuItem menu = new JMenuItem( "Rename" );
+ menu.addActionListener( new ActionListener( )
+ {
+ @Override
+ public void actionPerformed( ActionEvent event )
+ {
+ startRename();
+ }
+ } );
+ popupMenu.add( menu );
+ m_renameMenu = menu;
+ }
// layout controls
JSplitPane splitLeft = new JSplitPane( JSplitPane.VERTICAL_SPLIT, true, obfPanel, deobfPanel );
JPanel rightPanel = new JPanel();
rightPanel.setLayout( new BorderLayout() );
- rightPanel.add( m_actionPanel, BorderLayout.NORTH );
+ rightPanel.add( m_infoPanel, BorderLayout.NORTH );
rightPanel.add( sourceScroller, BorderLayout.CENTER );
JSplitPane splitMain = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, true, splitLeft, rightPanel );
pane.add( splitMain, BorderLayout.CENTER );
@@ -353,6 +376,19 @@ public class Gui
} );
m_closeMappingsMenu = item;
}
+ menu.addSeparator();
+ {
+ JMenuItem item = new JMenuItem( "Exit" );
+ menu.add( item );
+ item.addActionListener( new ActionListener( )
+ {
+ @Override
+ public void actionPerformed( ActionEvent event )
+ {
+ close();
+ }
+ } );
+ }
}
{
JMenu menu = new JMenu( "Help" );
@@ -374,12 +410,21 @@ public class Gui
// init state
onCloseJar();
+ m_frame.addWindowListener( new WindowAdapter( )
+ {
+ @Override
+ public void windowClosing( WindowEvent event )
+ {
+ close();
+ }
+ } );
+
// show the frame
pane.doLayout();
m_frame.setSize( 800, 600 );
m_frame.setMinimumSize( new Dimension( 640, 480 ) );
m_frame.setVisible( true );
- m_frame.setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE );
+ m_frame.setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE );
}
public GuiController getController( )
@@ -430,15 +475,15 @@ public class Gui
}
}
- public void setDeobfClasses( List classes )
+ public void setDeobfClasses( Map deobfClasses )
{
- if( classes != null )
+ if( deobfClasses != null )
{
- m_deobfClasses.setListData( new Vector( classes ) );
+ m_deobfClasses.setListData( new Vector>( deobfClasses.entrySet() ) );
}
else
{
- m_deobfClasses.setListData( new Vector() );
+ m_deobfClasses.setListData( new Vector>() );
}
}
@@ -450,48 +495,77 @@ public class Gui
public void setSource( String source )
{
- setSource( source, null );
+ setSource( source, 0 );
}
- public void setSource( String source, SourceIndex index )
+ public void setSource( String source, int lineNum )
{
+ // remove any old highlighters
+ m_editor.getHighlighter().removeAllHighlights();
+
m_editor.setText( source );
- setHighlightedTokens( null );
+
+ // count the offset of the target line
+ String text = m_editor.getText();
+ int pos = 0;
+ int numLines = 0;
+ for( ; pos < text.length(); pos++ )
+ {
+ if( numLines == lineNum )
+ {
+ break;
+ }
+ if( text.charAt( pos ) == '\n' )
+ {
+ numLines++;
+ }
+ }
+
+ // put the caret at the line number
+ m_editor.setCaretPosition( pos );
+ m_editor.grabFocus();
}
- public void setHighlightedTokens( Iterable tokens )
+ public void setHighlightedTokens( Iterable obfuscatedTokens, Iterable deobfuscatedTokens )
{
// remove any old highlighters
m_editor.getHighlighter().removeAllHighlights();
- if( tokens == null )
+ // color things based on the index
+ if( obfuscatedTokens != null )
{
- return;
+ setHighlightedTokens( obfuscatedTokens, m_obfuscatedHighlightPainter );
+ }
+ if( deobfuscatedTokens != null )
+ {
+ setHighlightedTokens( deobfuscatedTokens, m_deobfuscatedHighlightPainter );
}
- // color things based on the index
+ redraw();
+ }
+
+ private void setHighlightedTokens( Iterable tokens, Highlighter.HighlightPainter painter )
+ {
for( Token token : tokens )
{
try
{
- m_editor.getHighlighter().addHighlight( token.start, token.end(), m_highlightPainter );
+ m_editor.getHighlighter().addHighlight( token.start, token.end(), painter );
}
catch( BadLocationException ex )
{
throw new IllegalArgumentException( ex );
}
}
-
- redraw();
}
private void clearEntryPair( )
{
- m_actionPanel.removeAll();
+ m_infoPanel.removeAll();
JLabel label = new JLabel( "No identifier selected" );
unboldLabel( label );
label.setHorizontalAlignment( JLabel.CENTER );
- m_actionPanel.add( label );
+ m_infoPanel.add( label );
redraw();
}
@@ -507,30 +581,22 @@ public class Gui
m_selectedEntryPair = pair;
- // layout the action panel
- m_actionPanel.removeAll();
- m_actionPanel.add( m_renamePanel );
- m_nameField.setText( pair.deobf.getName() );
-
- // layout the dynamic section
- JPanel dynamicPanel = new JPanel();
- dynamicPanel.setLayout( new GridLayout( 3, 1, 0, 0 ) );
- m_actionPanel.add( dynamicPanel );
+ m_infoPanel.removeAll();
if( pair.deobf instanceof ClassEntry )
{
- showClassEntryPair( (EntryPair extends ClassEntry>)pair, dynamicPanel );
+ showClassEntryPair( (EntryPair extends ClassEntry>)pair );
}
else if( pair.deobf instanceof FieldEntry )
{
- showFieldEntryPair( (EntryPair extends FieldEntry>)pair, dynamicPanel );
+ showFieldEntryPair( (EntryPair extends FieldEntry>)pair );
}
else if( pair.deobf instanceof MethodEntry )
{
- showMethodEntryPair( (EntryPair extends MethodEntry>)pair, dynamicPanel );
+ showMethodEntryPair( (EntryPair extends MethodEntry>)pair );
}
else if( pair.deobf instanceof ArgumentEntry )
{
- showArgumentEntryPair( (EntryPair extends ArgumentEntry>)pair, dynamicPanel );
+ showArgumentEntryPair( (EntryPair extends ArgumentEntry>)pair );
}
else
{
@@ -540,30 +606,30 @@ public class Gui
redraw();
}
- private void showClassEntryPair( EntryPair extends ClassEntry> pair, JPanel panel )
+ private void showClassEntryPair( EntryPair extends ClassEntry> pair )
{
- m_typeLabel.setText( "Class: " );
+ addNameValue( m_infoPanel, "Class", pair.deobf.getName() );
}
- private void showFieldEntryPair( EntryPair extends FieldEntry> pair, JPanel panel )
+ private void showFieldEntryPair( EntryPair extends FieldEntry> pair )
{
- m_typeLabel.setText( "Field: " );
- addNameValue( panel, "Class", pair.obf.getClassEntry().getName() + " <-> " + pair.deobf.getClassEntry().getName() );
+ addNameValue( m_infoPanel, "Field", pair.deobf.getName() );
+ addNameValue( m_infoPanel, "Class", pair.deobf.getClassEntry().getName() );
}
- private void showMethodEntryPair( EntryPair extends MethodEntry> pair, JPanel panel )
+ private void showMethodEntryPair( EntryPair extends MethodEntry> pair )
{
- m_typeLabel.setText( "Method: " );
- addNameValue( panel, "Class", pair.obf.getClassEntry().getName() + " <-> " + pair.deobf.getClassEntry().getName() );
- addNameValue( panel, "Signature", pair.obf.getSignature() + " <-> " + pair.deobf.getSignature() );
+ addNameValue( m_infoPanel, "Method", pair.deobf.getName() );
+ addNameValue( m_infoPanel, "Class", pair.deobf.getClassEntry().getName() );
+ addNameValue( m_infoPanel, "Signature", pair.deobf.getSignature() );
}
- private void showArgumentEntryPair( EntryPair extends ArgumentEntry> pair, JPanel panel )
+ private void showArgumentEntryPair( EntryPair extends ArgumentEntry> pair )
{
- m_typeLabel.setText( "Argument: " );
- addNameValue( panel, "Class", pair.obf.getClassEntry().getName() + " <-> " + pair.deobf.getClassEntry().getName() );
- addNameValue( panel, "Method", pair.obf.getMethodEntry().getName() + " <-> " + pair.deobf.getMethodEntry().getName() );
- addNameValue( panel, "Index", Integer.toString( pair.obf.getIndex() ) );
+ 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() ) );
}
private void addNameValue( JPanel container, String name, String value )
@@ -578,6 +644,120 @@ public class Gui
panel.add( unboldLabel( new JLabel( value, JLabel.LEFT ) ) );
}
+
+ private void startRename( )
+ {
+ // init the text box
+ final JTextField text = new JTextField();
+ text.setText( m_selectedEntryPair.deobf.getName() );
+ text.setPreferredSize( new Dimension( 360, text.getPreferredSize().height ) );
+ text.addKeyListener( new KeyAdapter( )
+ {
+ @Override
+ public void keyPressed( KeyEvent event )
+ {
+ switch( event.getKeyCode() )
+ {
+ case KeyEvent.VK_ENTER:
+ finishRename( text, true );
+ break;
+
+ case KeyEvent.VK_ESCAPE:
+ finishRename( text, false );
+ break;
+ }
+ }
+ } );
+
+ // find the label with the name and replace it with the text box
+ JPanel panel = (JPanel)m_infoPanel.getComponent( 0 );
+ panel.remove( panel.getComponentCount() - 1 );
+ panel.add( text );
+ text.grabFocus();
+ text.selectAll();
+
+ redraw();
+ }
+
+ private void finishRename( JTextField text, boolean saveName )
+ {
+ String newName = text.getText();
+ if( saveName && newName != null && newName.length() > 0 )
+ {
+ SyntaxDocument doc = (SyntaxDocument)m_editor.getDocument();
+ int lineNum = doc.getLineNumberAt( m_editor.getCaretPosition() );
+ try
+ {
+ m_controller.rename( m_selectedEntryPair.obf, newName, lineNum );
+ }
+ catch( IllegalNameException ex )
+ {
+ text.setBorder( BorderFactory.createLineBorder( Color.red, 1 ) );
+ }
+ return;
+ }
+
+ // 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 ) ) );
+
+ m_editor.grabFocus();
+
+ redraw();
+ }
+
+ private void close( )
+ {
+ if( !m_controller.isDirty() )
+ {
+ // everything is saved, we can exit safely
+ m_frame.dispose();
+ }
+ else
+ {
+ // ask to save before closing
+ String[] options = {
+ "Save and exit",
+ "Discard changes",
+ "Cancel"
+ };
+ int response = JOptionPane.showOptionDialog(
+ m_frame,
+ "Your mappings have not been saved yet. Do you want to save?",
+ "Save your changes?",
+ JOptionPane.YES_NO_CANCEL_OPTION,
+ JOptionPane.QUESTION_MESSAGE,
+ null,
+ options,
+ options[2]
+ );
+ switch( response )
+ {
+ case JOptionPane.YES_OPTION: // save and exit
+ if( m_mappingsFileChooser.getSelectedFile() != null || m_mappingsFileChooser.showSaveDialog( m_frame ) == JFileChooser.APPROVE_OPTION )
+ {
+ try
+ {
+ m_controller.saveMappings( m_mappingsFileChooser.getSelectedFile() );
+ m_frame.dispose();
+ }
+ catch( IOException ex )
+ {
+ throw new Error( ex );
+ }
+ }
+ break;
+
+ case JOptionPane.NO_OPTION:
+ // don't save, exit
+ m_frame.dispose();
+ break;
+
+ // cancel means do nothing
+ }
+ }
+ }
private JLabel unboldLabel( JLabel label )
{
diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java
index 6704ef8a..e1ba49a6 100644
--- a/src/cuchaz/enigma/gui/GuiController.java
+++ b/src/cuchaz/enigma/gui/GuiController.java
@@ -14,14 +14,18 @@ import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
+
+import jsyntaxpane.Token;
+
+import com.beust.jcommander.internal.Lists;
+import com.beust.jcommander.internal.Maps;
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.MappingsReader;
@@ -33,6 +37,7 @@ public class GuiController
private Gui m_gui;
private SourceIndex m_index;
private ClassFile m_currentFile;
+ private boolean m_isDirty;
public GuiController( Gui gui )
{
@@ -40,6 +45,12 @@ public class GuiController
m_deobfuscator = null;
m_index = null;
m_currentFile = null;
+ m_isDirty = false;
+ }
+
+ public boolean isDirty( )
+ {
+ return m_isDirty;
}
public void openJar( File file )
@@ -62,6 +73,7 @@ public class GuiController
FileReader in = new FileReader( file );
m_deobfuscator.setMappings( new MappingsReader().read( in ) );
in.close();
+ m_isDirty = false;
m_gui.setMappingsFile( file );
refreshClasses();
refreshOpenFiles();
@@ -73,12 +85,14 @@ public class GuiController
FileWriter out = new FileWriter( file );
new MappingsWriter().write( out, m_deobfuscator.getMappings() );
out.close();
+ m_isDirty = false;
}
public void closeMappings( )
{
m_deobfuscator.setMappings( null );
m_gui.setMappingsFile( null );
+ refreshClasses();
refreshOpenFiles();
}
@@ -95,51 +109,62 @@ public class GuiController
return null;
}
- Entry deobfEntry = m_index.getEntry( pos );
- if( deobfEntry == null )
+ Map.Entry deobfEntryAndToken = m_index.getEntry( pos );
+ if( deobfEntryAndToken == null )
{
return null;
}
- return new EntryPair( m_deobfuscator.obfuscate( deobfEntry ), deobfEntry );
+ Entry deobfEntry = deobfEntryAndToken.getKey();
+ Token token = deobfEntryAndToken.getValue();
+ return new EntryPair( m_deobfuscator.obfuscateEntry( deobfEntry ), deobfEntry, token );
}
- public void rename( Entry obfsEntry, String newName )
+ public boolean entryHasMapping( int pos )
{
- m_deobfuscator.rename( obfsEntry, newName );
-
- // did we rename the current file?
- if( obfsEntry instanceof ClassEntry )
+ EntryPair pair = getEntryPair( pos );
+ if( pair == null || pair.obf == null )
{
- ClassEntry classEntry = (ClassEntry)obfsEntry;
-
- // update the current file
- if( classEntry.getName().equals( m_currentFile.getName() ) )
- {
- m_currentFile = new ClassFile( newName );
- }
+ return false;
}
-
- refreshOpenFiles();
+ return m_deobfuscator.hasMapping( pair.obf );
+ }
+
+ public void rename( Entry obfsEntry, String newName, int lineNum )
+ {
+ m_deobfuscator.rename( obfsEntry, newName );
+ m_isDirty = true;
+ refreshClasses();
+ refreshOpenFiles( lineNum );
}
private void refreshClasses( )
{
- List obfClasses = new ArrayList();
- List deobfClasses = new ArrayList();
- m_deobfuscator.getSortedClasses( obfClasses, deobfClasses );
+ List obfClasses = Lists.newArrayList();
+ Map deobfClasses = Maps.newHashMap();
+ m_deobfuscator.getSeparatedClasses( obfClasses, deobfClasses );
m_gui.setObfClasses( obfClasses );
m_gui.setDeobfClasses( deobfClasses );
}
-
+
private void refreshOpenFiles( )
+ {
+ refreshOpenFiles( 0 );
+ }
+
+ private void refreshOpenFiles( int lineNum )
{
if( m_currentFile != null )
{
- deobfuscate( m_currentFile );
+ deobfuscate( m_currentFile, lineNum );
}
}
private void deobfuscate( final ClassFile classFile )
+ {
+ deobfuscate( classFile, 0 );
+ }
+
+ private void deobfuscate( final ClassFile classFile, final int lineNum )
{
m_gui.setSource( "(deobfuscating...)" );
@@ -149,13 +174,28 @@ public class GuiController
@Override
public void run( )
{
- // deobfuscate the bytecode
+ // deobfuscate,decompile the bytecode
String source = m_deobfuscator.getSource( classFile );
- m_gui.setSource( source );
+ m_gui.setSource( source, lineNum );
// index the source file
m_index = Analyzer.analyze( classFile.getName(), source );
- m_gui.setHighlightedTokens( m_index.tokens() );
+
+ // set the highlighted tokens
+ List obfuscatedTokens = Lists.newArrayList();
+ List deobfuscatedTokens = Lists.newArrayList();
+ for( Token token : m_index.tokens() )
+ {
+ if( entryHasMapping( token.start ) )
+ {
+ deobfuscatedTokens.add( token );
+ }
+ else
+ {
+ obfuscatedTokens.add( token );
+ }
+ }
+ m_gui.setHighlightedTokens( obfuscatedTokens, deobfuscatedTokens );
}
}.start();
}
diff --git a/src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java b/src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java
new file mode 100644
index 00000000..d46e1ae6
--- /dev/null
+++ b/src/cuchaz/enigma/gui/ObfuscatedClassListCellRenderer.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * 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 javassist.bytecode.Descriptor;
+
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.ListCellRenderer;
+
+import cuchaz.enigma.ClassFile;
+
+public class ObfuscatedClassListCellRenderer implements ListCellRenderer
+{
+ private DefaultListCellRenderer m_defaultRenderer;
+
+ public ObfuscatedClassListCellRenderer( )
+ {
+ m_defaultRenderer = new DefaultListCellRenderer();
+ }
+
+ @Override
+ public Component getListCellRendererComponent( JList extends ClassFile> list, ClassFile classFile, int index, boolean isSelected, boolean hasFocus )
+ {
+ JLabel label = (JLabel)m_defaultRenderer.getListCellRendererComponent( list, classFile, index, isSelected, hasFocus );
+
+ label.setText( Descriptor.toJavaName( classFile.getName() ) );
+
+ return label;
+ }
+}
diff --git a/src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java b/src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java
new file mode 100644
index 00000000..724be34e
--- /dev/null
+++ b/src/cuchaz/enigma/gui/ObfuscatedHighlightPainter.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * 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.Color;
+
+public class ObfuscatedHighlightPainter extends BoxHighlightPainter
+{
+ public ObfuscatedHighlightPainter( )
+ {
+ // red ish
+ super( new Color( 255, 220, 220 ), new Color( 160, 80, 80 ) );
+ }
+}
diff --git a/src/cuchaz/enigma/mapping/ArgumentMapping.java b/src/cuchaz/enigma/mapping/ArgumentMapping.java
index d5e020a6..168306a2 100644
--- a/src/cuchaz/enigma/mapping/ArgumentMapping.java
+++ b/src/cuchaz/enigma/mapping/ArgumentMapping.java
@@ -12,7 +12,7 @@ package cuchaz.enigma.mapping;
import java.io.Serializable;
-public class ArgumentMapping implements Serializable
+public class ArgumentMapping implements Serializable, Comparable
{
private static final long serialVersionUID = 8610742471440861315L;
@@ -23,7 +23,7 @@ public class ArgumentMapping implements Serializable
public ArgumentMapping( int index, String name )
{
m_index = index;
- m_name = name;
+ m_name = NameValidator.validateArgumentName( name );
}
public int getIndex( )
@@ -37,6 +37,12 @@ public class ArgumentMapping implements Serializable
}
public void setName( String val )
{
- m_name = val;
+ m_name = NameValidator.validateArgumentName( val );
+ }
+
+ @Override
+ public int compareTo( ArgumentMapping other )
+ {
+ return Integer.compare( m_index, other.m_index );
}
}
diff --git a/src/cuchaz/enigma/mapping/ClassMapping.java b/src/cuchaz/enigma/mapping/ClassMapping.java
index 3ba3569f..a1cc775f 100644
--- a/src/cuchaz/enigma/mapping/ClassMapping.java
+++ b/src/cuchaz/enigma/mapping/ClassMapping.java
@@ -15,7 +15,7 @@ import java.util.Map;
import com.beust.jcommander.internal.Maps;
-public class ClassMapping implements Serializable
+public class ClassMapping implements Serializable, Comparable
{
private static final long serialVersionUID = -5148491146902340107L;
@@ -30,7 +30,7 @@ public class ClassMapping implements Serializable
public ClassMapping( String obfName, String deobfName )
{
m_obfName = obfName;
- m_deobfName = deobfName;
+ m_deobfName = NameValidator.validateClassName( deobfName );
m_fieldsByObf = Maps.newHashMap();
m_fieldsByDeobf = Maps.newHashMap();
m_methodsByObf = Maps.newHashMap();
@@ -48,7 +48,7 @@ public class ClassMapping implements Serializable
}
public void setDeobfName( String val )
{
- m_deobfName = val;
+ m_deobfName = NameValidator.validateClassName( val );
}
public Iterable fields( )
@@ -97,11 +97,6 @@ public class ClassMapping implements Serializable
public void setFieldName( String obfName, String deobfName )
{
- if( deobfName == null )
- {
- throw new IllegalArgumentException( "deobf name cannot be null!" );
- }
-
FieldMapping fieldMapping = m_fieldsByObf.get( obfName );
if( fieldMapping == null )
{
@@ -140,11 +135,6 @@ public class ClassMapping implements Serializable
public void setMethodNameAndSignature( String obfName, String obfSignature, String deobfName, String deobfSignature )
{
- if( deobfName == null )
- {
- throw new IllegalArgumentException( "deobf name cannot be null!" );
- }
-
MethodMapping methodIndex = m_methodsByObf.get( getMethodKey( obfName, obfSignature ) );
if( methodIndex == null )
{
@@ -167,11 +157,6 @@ public class ClassMapping implements Serializable
public void setArgumentName( String obfMethodName, String obfMethodSignature, int argumentIndex, String argumentName )
{
- if( argumentName == null )
- {
- throw new IllegalArgumentException( "argument name cannot be null!" );
- }
-
MethodMapping methodIndex = m_methodsByObf.get( getMethodKey( obfMethodName, obfMethodSignature ) );
if( methodIndex == null )
{
@@ -214,4 +199,10 @@ public class ClassMapping implements Serializable
}
return buf.toString();
}
+
+ @Override
+ public int compareTo( ClassMapping other )
+ {
+ return m_obfName.compareTo( other.m_obfName );
+ }
}
diff --git a/src/cuchaz/enigma/mapping/EntryPair.java b/src/cuchaz/enigma/mapping/EntryPair.java
index e3325b37..1bf9be09 100644
--- a/src/cuchaz/enigma/mapping/EntryPair.java
+++ b/src/cuchaz/enigma/mapping/EntryPair.java
@@ -10,15 +10,19 @@
******************************************************************************/
package cuchaz.enigma.mapping;
+import jsyntaxpane.Token;
+
public class EntryPair
{
public T obf;
public T deobf;
+ public Token token;
- public EntryPair( T obf, T deobf )
+ public EntryPair( T obf, T deobf, Token token )
{
this.obf = obf;
this.deobf = deobf;
+ this.token = token;
}
}
diff --git a/src/cuchaz/enigma/mapping/FieldMapping.java b/src/cuchaz/enigma/mapping/FieldMapping.java
index 618f45c6..ae0855a8 100644
--- a/src/cuchaz/enigma/mapping/FieldMapping.java
+++ b/src/cuchaz/enigma/mapping/FieldMapping.java
@@ -12,7 +12,7 @@ package cuchaz.enigma.mapping;
import java.io.Serializable;
-public class FieldMapping implements Serializable
+public class FieldMapping implements Serializable, Comparable
{
private static final long serialVersionUID = 8610742471440861315L;
@@ -22,7 +22,7 @@ public class FieldMapping implements Serializable
public FieldMapping( String obfName, String deobfName )
{
m_obfName = obfName;
- m_deobfName = deobfName;
+ m_deobfName = NameValidator.validateFieldName( deobfName );
}
public String getObfName( )
@@ -36,6 +36,12 @@ public class FieldMapping implements Serializable
}
public void setDeobfName( String val )
{
- m_deobfName = val;
+ m_deobfName = NameValidator.validateFieldName( val );
+ }
+
+ @Override
+ public int compareTo( FieldMapping other )
+ {
+ return m_obfName.compareTo( other.m_obfName );
}
}
diff --git a/src/cuchaz/enigma/mapping/IllegalNameException.java b/src/cuchaz/enigma/mapping/IllegalNameException.java
new file mode 100644
index 00000000..560e5d93
--- /dev/null
+++ b/src/cuchaz/enigma/mapping/IllegalNameException.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * 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.mapping;
+
+public class IllegalNameException extends RuntimeException
+{
+ private static final long serialVersionUID = -2279910052561114323L;
+
+ private String m_name;
+
+ public IllegalNameException( String name )
+ {
+ m_name = name;
+ }
+
+ @Override
+ public String getMessage( )
+ {
+ return "Illegal name: " + m_name;
+ }
+}
diff --git a/src/cuchaz/enigma/mapping/MappingsWriter.java b/src/cuchaz/enigma/mapping/MappingsWriter.java
index 20863687..a97052fa 100644
--- a/src/cuchaz/enigma/mapping/MappingsWriter.java
+++ b/src/cuchaz/enigma/mapping/MappingsWriter.java
@@ -13,6 +13,9 @@ package cuchaz.enigma.mapping;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
public class MappingsWriter
{
@@ -25,7 +28,7 @@ public class MappingsWriter
public void write( PrintWriter out, Mappings mappings )
throws IOException
{
- for( ClassMapping classMapping : mappings.classes() )
+ for( ClassMapping classMapping : sorted( mappings.classes() ) )
{
write( out, classMapping );
}
@@ -36,12 +39,12 @@ public class MappingsWriter
{
out.format( "CLASS %s %s\n", classMapping.getObfName(), classMapping.getDeobfName() );
- for( FieldMapping fieldMapping : classMapping.fields() )
+ for( FieldMapping fieldMapping : sorted( classMapping.fields() ) )
{
write( out, fieldMapping );
}
- for( MethodMapping methodMapping : classMapping.methods() )
+ for( MethodMapping methodMapping : sorted( classMapping.methods() ) )
{
write( out, methodMapping );
}
@@ -61,7 +64,7 @@ public class MappingsWriter
methodMapping.getObfSignature(), methodMapping.getDeobfSignature()
);
- for( ArgumentMapping argumentMapping : methodMapping.arguments() )
+ for( ArgumentMapping argumentMapping : sorted( methodMapping.arguments() ) )
{
write( out, argumentMapping );
}
@@ -72,4 +75,15 @@ public class MappingsWriter
{
out.format( "\t\tARG %d %s\n", argumentMapping.getIndex(), argumentMapping.getName() );
}
+
+ private > List sorted( Iterable classes )
+ {
+ List out = new ArrayList();
+ for( T t : classes )
+ {
+ out.add( t );
+ }
+ Collections.sort( out );
+ return out;
+ }
}
diff --git a/src/cuchaz/enigma/mapping/MethodMapping.java b/src/cuchaz/enigma/mapping/MethodMapping.java
index 1cdc38a1..7857ea7e 100644
--- a/src/cuchaz/enigma/mapping/MethodMapping.java
+++ b/src/cuchaz/enigma/mapping/MethodMapping.java
@@ -14,7 +14,7 @@ import java.io.Serializable;
import java.util.Map;
import java.util.TreeMap;
-public class MethodMapping implements Serializable
+public class MethodMapping implements Serializable, Comparable